RGB colours in ThreeJS - javascript

I have a set of points stored in a giant string, with newline characters \n separating one point from the next. Each point is stored as x y z r g b, where r g b are values ranging from 0-255.
According to the ThreeJS docs, it is possible to do this:
var color = new THREE.Color("rgb(255,0,0)");
However, my points still show up as all white in my ThreeJS viewer. What am I doing wrong?
Code is as follows:
var cloud = data.split('\n');
for (var i=0; i<cloud.length; i++) {
var colour = 'rgb(' + pt[3] + ',' + pt[4] + ',' + pt[5] + ')';
model.vertices.push( new THREE.Vector3(x, y, z) );
colours.push( new THREE.Color(colour) );
}

I realised what my mistake was: I forgot to parse points 3 to 5 as floats.
This fixed it:
var colour = 'rgb(' + parseFloat(pt[3]) + ',' + parseFloat(pt[4]) + ',' + parseFloat(pt[5]) + ')';

Related

SVG rotation issue with JavaScript variables

Is there a way to use a variable inside the rotation function in JavaScript? The script below does not work (x and y will not assigned).
var x = 20;
var y = 20;
object.children[0].setAttribute('transform','rotate(-20, x, y)');
As setAttribute takes as string you can either use string concatenation or template literals (as shown below).
var x = 20;
var y = 20;
object.children[0].setAttribute('transform',`rotate(-20, ${x}, ${y})`);
As commented this is ES6 syntax. Below is using string concatenation.
var x = 20;
var y = 20;
object.children[0].setAttribute('transform','rotate(-20, ' + x + ', ' + y + ')');
While building the string in place with literals or concat is fine, if you are planning on doing this more than once, I would suggest creating a string builder function for rotate. For example:
function rotateStr(a, x, y) {
return `rotate(${a}, ${x}, ${y})`
// return 'rotate(' + x + ',' + y + ',' + z + ')' if you can't use templates
}
var x = 20;
var y = 20;
object.children[0].setAttribute('transform', rotateStr(-20, x, y))

Using javascript to change rgb value of background onclick

I'm trying to implement a very simple JavaScript program: every time you click the button, the RGB values of the background color are randomized.
Here's the Javascript:
function change() {
var x = Math.floor(Math.random() * 256); // range is 0-255
var y = Math.floor(Math.random() * 256);
var z = Math.floor(Math.random() * 256);
var thergb = "'rgb(" + x + "," + y + "," + z + ")'";
console.log(thergb);
document.body.style.background=thergb;
}
I'm pretty sure the problem is in how I hack together the thergb variable, but there are no errors in the console so I'm not quite sure. I log the console just to make sure it's giving me an actual random rgb, which it is.
Here's the full JSFiddle: http://jsfiddle.net/L92bY/
You have wrapped it in ' .. why ?
If you remove that it works..
var thergb = "rgb(" + x + "," + y + "," + z + ")";
Demo at http://jsfiddle.net/gaby/L92bY/9/
(you also needed to define the change function in the head tag and not in the onLoad event..)
The CSS syntax for an rgb() value does not include single quotes.
Change 'rgb(x,y,z)' to rgb(x,y,z).
Two things:
You need to choose one of the "nowrap" options for where the fiddle server puts your code.
You need to get rid of the single-quote characters around your "rgb()" expression.
var thergb = "rgb(" + x + "," + y + "," + z + ")";
Personally I'd set "backgroundColor" instead of just "background", but it works (in Firefox at least) to set "background".
Fixed fiddle.
Working fiddle (just corrected your code): http://jsfiddle.net/L92bY/18/
The syntax for the CSS color as rgb is rgb(r,g,b) (no extra apostrophe "'") = not 'rgb(r,g,b)'
function change() {
var x = Math.floor(Math.random() * 256); // range is 0-255
var y = Math.floor(Math.random() * 256);
var z = Math.floor(Math.random() * 256);
var thergb = "rgb(" + x + "," + y + "," + z + ")";
console.log(thergb);
document.body.style.background=thergb;
}
PS: If this is not working for you you are calling this javascript function BEFORE it was declared.
You could probably also just simplify where your code went wrong by using string template literals.
var thergb = `rgb(${x}, ${y}, ${z})`

JavaScript Changing BG Color

I made a div with background-color set to rgb(0,0,0); and I want to change it's color on click with javascript. I made a function to do that.
function change(){
var x = 1;
var y = x + 100;
document.getElementById("box").style.backgroundColor = "rgb(" + y + "," + y + "," + y + ")"; }
It works fine but I can change the div's color just once. What I want to do is get div's color value and set it to x and run the function again. So the bg will go like black->grey->white on each click. Depending on the y variable.
I can get the div's value but it'll get it in "rgb(0,0,0);" format. I don't know what to do after getting this. How do I manipulate just integers in rgb(0,0,0); ?
You can store current x value in data attributes:
function change(box) {
var x = +box.getAttribute('data-x'), // +box.dataset.x for modern browsers
y = x + 100;
box.style.backgroundColor = "rgb(" + y + "," + y + "," + y + ")";
box.setAttribute('data-x', y);
}
HTML
<div id="box" onclick="change(this)"></div>
Demo: http://jsfiddle.net/Wuz75/
Instead of trying to analyse the color, since your colors will be static, just make an array of colors, and keep track of the index.
var colors = [
"rgb(0,0,0)",
"rgb(100,100,100)",
"rgb(255,255,255)"
],
c = 0;
Then in your function, use c to get the next color, and then increment, or reset to 0.
function change() {
document.getElementById("box").style.backgroundColor = colors[c];
c = ++c % colors.length;
}
So whenever you run the function, it'll switch between colors in the Array.
Or you can use :
function change(x) {
var el = document.getElementById('color');
var rgb = el.style.backgroundColor.replace(/rgb|\(|\)|\s/g, '').split(',');
if ( rgb == "" ) { rgb = [0,0,0] };
for (var a = 0; a < rgb.length; a++ ) {
rgb[a] = parseInt(rgb[a]) + x;
}
el.style.backgroundColor = 'rgb('+rgb.join(',')+')';
}
Here is a demo : http://jsbin.com/ozepaz/1/edit

Classifying a Raphael paper into 20x20 divisions

I have a paper with 400 x 500 in size. I am trying to divide this into 20 x 20 pixels with below code
var dpH = 500, dpW = 400, drawPad = new Raphael(document.getElementById('p'),
dpW, dpH);
for ( var i = 0; i <= dpH / 20; i++) {
drawPad.path("M" + 1 + " " + ((i * 20) + 1) + "L" + dpW + " "
+ ((i * 20) + 1));
}
for ( var j = 0; j <= (dpW / 20); j++) {
drawPad.path("M" + ((j * 20) + 1) + " " + 1 + "L" + ((j * 20) + 1) + " "
+ dpH);
}
And HTML markup is like below
<div id="p" style="background-image:url(image.png)"> </div>
with same height and width of Background Image.
My original requirement was making the image.png as Rapheal paper. But I was failed to do that. So I made it as background-image to the DIV#P. Then converted the DIv to Paper.
Here are my questions related to above
Does all the pixels of Background-Image and DIV match with each other?
The way I did above is to classify the total paper into 20x20 pixel divisions. Is that correct way of doing?
What is the width of the drawn line?
Please help me on this.
Ok, so if I understand you correctly; What you really want is to get the raw image data for 20x20 squares of the image.
Here's how you can extract image data with Canvas (also on jsFiddle):
var dpH = 500,
dpW = 400,
ctx = document.getElementById('p').getContext('2d'),
exportData = function() {
var data;
for (var y=0, yl=dpH/20; y<yl; y++) {
for (var x=0, xl=dpW/20; x<xl; x++) {
imgData = ctx.getImageData(x*20, y*20, 20, 20).data;
console.log("Image data for " + x*20 + ", " + y*20, imgData);
// data is an array with 4 values pr pixel
// Top left pixel in the 20x20 square
r = imgData[0]; // red
g = imgData[1]; // green
b = imgData[2]; // blue
a = imgData[3]; // alpha
console.log("RGBa of " + x*20 + ", " + y*20 + ": ", r, g, b, a);
}
}
},
drawImage = function() {
ctx.drawImage(this, 0, 0);
exportData(this);
};
var img = new Image();
img.onload = drawImage;
img.src = "image.png"; // has to be on the same domain
** Original answer **
The result is a DIV with an SVG-element inside, and a background image behind it. The browser (if it supports SVG) will render them on top of each other. Do you want to extract pixel values? If so, you have to do this through HTML5 Canvas instead of SVG.
Sorry, I don't understand. What are you trying to accomplish? Do you want the pixel data for 20x20 squares? With Raphael you are just drawing lines on top of the picture.
The defaut with of a path is 1 pixels. You can change this by setting an attribute on the path. Example (also on jsfiddle.net):
var dpH = 500,
dpW = 400,
drawPad = Raphael(document.getElementById('p'), dpW, dpH),
style = {
"stroke" : "#fff", // white
"stroke-width" : 2 // default 1
};
for ( var i = 0; i <= dpH / 20; i++) {
drawPad.path("M" + 1 + " " + ((i * 20) + 1) + "L" + dpW + " "
+ ((i * 20) + 1)).attr(style);
}
for ( var j = 0; j <= (dpW / 20); j++) {
drawPad.path("M" + ((j * 20) + 1) + " " + 1 + "L" + ((j * 20) + 1) + " "
+ dpH).attr(style);
}​

javascript variable scope/closure in loop after timeout

It's late and the part of my brain where Douglas Crockford lives is closed. Ive tried a few things but nothing's doing as expected.
I've got a canvas where I draw a 2 lines, then fade them out on a timer but only the last line in the loop is being faded out. Here's my fiddle, look down to line 50ish in the JS, to see it in action drag your mouse around in the bottom right pane:
http://jsfiddle.net/mRsvc/4/
this is the function, basically the timeout only gets the last value in the loop, I've seen this before and I'm sure if I wasn't so delirious it might be simpler. Here's the function in particular:
function update()
{
var i;
this.context.lineWidth = BRUSH_SIZE;
this.context.strokeStyle = "rgba(" + COLOR[0] + ", " + COLOR[1] + ", " + COLOR[2] + ", " + BRUSH_PRESSURE + ")";
for (i = 0; i < scope.painters.length; i++)
{
scope.context.beginPath();
var dx = scope.painters[i].dx;
var dy = scope.painters[i].dy;
scope.context.moveTo(dx, dy);
var dx1 = scope.painters[i].ax = (scope.painters[i].ax + (scope.painters[i].dx - scope.mouseX) * scope.painters[i].div) * scope.painters[i].ease;
scope.painters[i].dx -= dx1;
var dx2 = scope.painters[i].dx;
var dy1 = scope.painters[i].ay = (scope.painters[i].ay + (scope.painters[i].dy - scope.mouseY) * scope.painters[i].div) * scope.painters[i].ease;
scope.painters[i].dy -= dy1;
var dy2 = scope.painters[i].dy;
scope.context.lineTo(dx2, dy2);
scope.context.stroke();
for(j=FADESTEPS;j>0;j--)
{
setTimeout(function()
{
var x=dx,y=dy,x2=dx2,y2=dy2;
scope.context.beginPath();
scope.context.lineWidth=BRUSH_SIZE+1;
scope.context.moveTo(x, y);
scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")";
scope.context.lineTo(x2, y2);
scope.context.stroke();
scope.context.lineWidth=BRUSH_SIZE;
},
DURATION/j);
}
}
}
The problem is that the variables dx, dy, etc that you refer to in the function you pass to setTimeout() are defined in the surrounding scope and by the time any of the timeouts actually runs these variables all hold the values from the last iteration of the loop(s).
You need to create an extra containing function to close over the values from each iteration. Try something like the following:
for(j=FADESTEPS;j>0;j--) {
(function(x,y,x2,y2) {
setTimeout(function() {
scope.context.beginPath();
scope.context.lineWidth=BRUSH_SIZE+1;
scope.context.moveTo(x, y);
scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")";
scope.context.lineTo(x2, y2);
scope.context.stroke();
scope.context.lineWidth=BRUSH_SIZE;
},
DURATION/j);
})(dx, dy, dx2, dy2);
}
This creates a new anonymous function for each iteration of the j=FADESTEPS loop, executing it immediately and passing the dx, etc. values as they were at the time each iteration of the loop ran, and moving the x, y, etc. variables out of your existing function and making them parameters of the new one so then by the time the timeout runs it will use the correct values.
You can try something like this:
`<script>
for(j=10;j>0;j--)
{
var fn = function(ind){return function()
{
console.log(ind);
};
}(j);
setTimeout(fn,
1000);
}
</script>`
Or another way (as soon as you do not use IE, but let it learn canvas at first :))
for(j=FADESTEPS;j>0;j--)
{
setTimeout(function(x,y,x2,y2)
{
scope.context.beginPath();
scope.context.lineWidth=BRUSH_SIZE+1;
scope.context.moveTo(x, y);
scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")";
scope.context.lineTo(x2, y2);
scope.context.stroke();
scope.context.lineWidth=BRUSH_SIZE;
},
DURATION/j,dx,dy,dx2,dy2);
}
ps: there is no need in set of extra functions (the reasons are clear)
First of all j is a global.
Second of all, you never close the paths that you begin, which can cause memory leaks. It seems really slow and this may be why. You need to call closePath() whenever you're done with the paths you start with beginPath()
Next, I think there's some general funniness with how this works. You're fading out by drawing over the last thing with white. I've done something similar to this before, but instead I cleared the whole screen and kept drawing things over and over again. It worked okay for me.
Explanation
The other answers about dx and dy being passed from the higher scope are the right answers though. Async functions defined in synchronous for loops will take the last version of the state.
for (var i = 0; i < 10; i++) setTimeout(function() { console.log(i)}, 10 )
10
10
// ...
I would suggest you to use an array and store the points avoiding setTimeOut call in a loop. Somewhat like this.
this.interval = setInterval(update, REFRESH_RATE);
var _points = [];
function update() {
var i;
this.context.lineWidth = BRUSH_SIZE;
this.context.strokeStyle = "rgba(" + COLOR[0] + ", " + COLOR[1] + ", " + COLOR[2] + ", " + BRUSH_PRESSURE + ")";
for (i = 0; i < scope.painters.length; i++) {
scope.context.beginPath();
var dx = scope.painters[i].dx;
var dy = scope.painters[i].dy;
scope.context.moveTo(dx, dy);
var dx1 = scope.painters[i].ax = (scope.painters[i].ax + (scope.painters[i].dx - scope.mouseX) * scope.painters[i].div) * scope.painters[i].ease;
scope.painters[i].dx -= dx1;
var dx2 = scope.painters[i].dx;
var dy1 = scope.painters[i].ay = (scope.painters[i].ay + (scope.painters[i].dy - scope.mouseY) * scope.painters[i].div) * scope.painters[i].ease;
scope.painters[i].dy -= dy1;
var dy2 = scope.painters[i].dy;
scope.context.lineTo(dx2, dy2);
scope.context.stroke();
_points.push([dx, dy, dx2, dy2]);
clear();
}
}
function clear(){
if(_points.length < FADESTEPS){
return;
}
var p = _points.shift();
if(!p){
return;
}
var x = p[0],
y = p[1],
x2 = p[2],
y2 = p[3];
scope.context.beginPath();
scope.context.lineWidth = BRUSH_SIZE + 1;
scope.context.moveTo(x, y);
scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")";
scope.context.lineTo(x2, y2);
scope.context.stroke();
scope.context.lineWidth = BRUSH_SIZE;
}
I know this is not exactly what you need, but I think this can be modified to get it.

Categories