Hi there my problem with the code below is the the arc is creating 1 shape not the ten specified in the for loop...
If I was to change from arc to $cd.fillRect(10,20,$x,$y); then that would create 10 different rectangles but not the arc... what am I misunderstanding here?
var $canvas = $('#canvas-one')[0],
$cd;
if ($canvas.getContext) {
$cd = $canvas.getContext('2d');
for (i = 0; i <= 10; i++) {
$cd.fillStyle = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")";
$cd.strokeStyle = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")";
var $x = 300 + Math.floor(Math.random() * 101);
var $y = 300 + Math.floor(Math.random() * 101);
var $radius = 0.1 + Math.floor(Math.random() * 6);
$cd.beginPath();
$cd.arc($x, $y, $radius, 0, Math.PI * 2, true);
}
$cd.stroke();
$cd.fill();
//$canvas.width = $canvas.height;
}
stroke and fill should be in the loop
I think you forgot to multiply x with i.
for (let i = 0; i < 10; i++) {
context.fillStyle = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")";
context.beginPath();
context.arc(i * x, y,15, 0, 2 * Math.PI,true);
context.fill();
Related
I have an electron app where I receive some data from a camera via the serial port and then I display it using a canvas.
I want to use bilinear interpolation as the data received is only 64 pixels. The problem that I have is that the interpolation function is too slow and it cannot keep it with the data that is received via serial therefore it laggs and is not real time anymore.
Any idea what I can do to make it faster?
Here is the function:
let imgData = ctx.getImageData(0, 0, width, height);
let data = imgData.data;
for i {
for j {
//The size of a block is 64 pixels
let indexX = Math.floor(j / (64 * 4));
let indexY = Math.floor(i / 64);
let Q11 = {
x: index_X * 64,
y: index_Y * 64,
value: parseFloat(PixelData[indexX + indexY * 16])
};
let Q12 = {
x: index_X * 64,
y: (index_Y + 1) * 64,
value: parseFloat(PixelData[indexX + (indexY + 1) * 16])
};
let Q21 = {
x: (index_X + 1) * 64,
y: index_Y * 64,
value: parseFloat(PixelData[(indexX + 1) + indexY * 16])
};
let Q22 = {
x: (index_X + 1) * 64,
y: (index_Y + 1) * 64,
value: parseFloat(PixelData[(indexX + 1) + (indexY + 1) * 16])
};
let R1 = Q11.value * ((Q21.x - (j / 4)) / 64) + Q21.value * (((j / 4) - Q11.x) / 64);
let R2 = Q12.value * ((Q22.x - (j / 4)) / 64) + Q22.value * (((j / 4) - Q12.x) / 64);
let MLXTempInterpolated = R1 * ((Q12.y - i) / 64) + R2 * ((i - Q21.y) / 64);
let tempIndex = TempMap(MLXTempInterpolated, minTemp, maxTemp, 120) //This is pretty fast
try {
data[j + i * ((64 * 15 + 1) * 4) + 0] = colorPalette[tempIndex].r //r
data[j + i * ((64 * 15 + 1) * 4) + 1] = colorPalette[tempIndex].g //g
data[j + i * ((64 * 15 + 1) * 4) + 2] = colorPalette[tempIndex].b //b
data[j + i * ((64 * 15 + 1) * 4) + 3] = 255 //alfa
} catch (err) {
//console.log(err)
}
} //for j
} // for i
// put the modified pixels back on the canvas
ctx.putImageData(imgData, 0, 0);
Wouldn't drawing it onto another canvas do the bilinear interpolation for you?
var canvas2 = document.createElement('canvas');
var ctx2 = canvas2.getContext('2d');
canvas2.width = canvas2.height = 1024;
ctx2.drawImage( canvas, 0, 0, 1024, 1024 );
I created my colors code 0-70 from green to red. Now, I want to change colors 0 - 70 from red to green.
function percentToRGB(percent) {
if (percent === 100) {
percent = 99
}
var r, g, b;
if (percent < 50) {
// green to yellow
r = Math.floor(255 * (percent / 50));
g = 255;
} else {
// yellow to red
r = 255;
g = Math.floor(255 * ((50 - percent % 50) / 50));
}
b = 0;
return "rgb(" + r + "," + g + "," + b + ")";
}
function render(i) {
var item = "<li style='background-color:" + percentToRGB(i) + "'>" + i + "</li>";
$("ul").append(item);
}
function repeat(fn, times) {
for (var i = 0; i < times; i++) fn(i);
}
repeat(render, 100);
li {
font-size:8px;
height:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>
You should just be able to switch the g and r variables around within the percentToRGB function. Here's a JSFiddle Link.
So the function would become:
function percentToRGB(percent) {
if (percent === 100) {
percent = 99
}
var r, g, b;
if (percent < 50) {
// green to yellow
g = Math.floor(255 * (percent / 50));
r = 255;
} else {
// yellow to red
g = 255;
r = Math.floor(255 * ((50 - percent % 50) / 50));
}
b = 0;
return "rgb(" + r + "," + g + "," + b + ")";
}
I am trying to randomly generate a pair of colors with RGB format using JS, which are similar to each other but slightly different in shade.
See in the reference image below, how all 3 "cases" (which would be randomly generated) contain two colors, both of which are very similar, but of slightly different shades.
I tried the following code, but both the colors generated are totally different.
How can I have the second color be just slightly different from the first, whilst the pair are generated with random values?
ran1 = Math.floor(Math.random() * 255) + 1;
ran2 = Math.floor(Math.random() * 255) + 1;
ran3 = Math.floor(Math.random() * 255) + 1;
ran4 = Math.floor(Math.random() * 255) + 1;
ran5 = Math.floor(Math.random() * 255) + 1;
ran6 = Math.floor(Math.random() * 255) + 1;
color1 = "rgb(" + ran1 + "," + ran2 + "," + ran3 + ")"; // random color
color2 = "rgb(" + ran4 + "," + ran5 + "," + ran6 + ")"; // probably dissimilar to color1
This will provide two colors with slightly different shades, but only demonstrates a principle to be expanded; it is not a packaged, perfect, production ready solution.
Basically, it adds to the second color's RGB values, a little bit more than those of the first, if the first's values aren't already too high.
const slightness = 20; // positive for slightly lighter color
const colors = document.querySelectorAll( "div" ),
color1 = colors[ 0 ],
color2 = colors[ 1 ];
function shallWe( c ) {
return c < 236 ? slightness : 0;
}
let ran1 = Math.floor(Math.random() * 255) + 1,
ran2 = Math.floor(Math.random() * 255) + 1,
ran3 = Math.floor(Math.random() * 255) + 1;
color1.style.background = "rgb(" + ran1 + "," + ran2 + "," + ran3 + ")";
ran1 += shallWe( ran1 );
ran2 += shallWe( ran2 );
ran3 += shallWe( ran3 );
color2.style.background = "rgb(" + ran1 + "," + ran2 + "," + ran3 + ")";
div { padding: 2em; }
<div></div><div></div>
I'm trying to use javascript to make an image face the mouse of the user, I'm close but my calculations are a bit off (the rotation on the x-axis seems to be inverted). I based my code of this link: rotate3d shorthand
javascript:
$(document).mousemove(function(e){
pageheight = $(document).height();
pagewidth = $(document).width();
widthpercentage = e.pageX / pagewidth;
heightpercentage = e.pageY / pageheight;
specialW = (widthpercentage * 180 - 90);
specialH = (heightpercentage * 180 - 90);
function toRadians(degrees) {
radians = degrees * (Math.PI /180);
return radians;
}
function matrix(x, y, z, rads) {
var sc = Math.sin(rads / 2) * Math.cos(rads / 2);
var sq = Math.pow(Math.sin(rads / 2), 2);
var array = [];
var a1 = 1 - 2 * (Math.pow(y, 2) + Math.pow(z, 2)) * sq,
a2 = 2 * (x * y * sq - z * sc),
a3 = 2 * (x * z * sq + y * sc),
a4 = 0,
b1 = 2 * (x * y * sq + z * sc),
b2 = 1 - 2 * (Math.pow(x, 2) + Math.pow(z, 2)) * sq,
b3 = 2 * (y * z * sq - x * sc),
b4 = 0,
c1 = 2 * (x * z * sq - y * sc),
c2 = 2 * (y * z * sq + x * sc),
c3 = 1 - 2 * (Math.pow(x, 2) + Math.pow(y, 2)) * sq,
c4 = 0,
d1 = 0,
d2 = 0,
d3 = 0,
d4 = 1;
array.push(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4);
return array;
}
xmatrix = matrix(1, 0, 0, toRadians(specialH));
ymatrix = matrix(0, 1, 0, toRadians(specialW));
function multiply(xarray, yarray) {
var newarray = [];
var a1 = (xarray[0] * yarray[0]) + (xarray[4] * yarray[1]) + (xarray[8] * yarray[2]) + (xarray[12] * yarray[3]),
a2 = (xarray[0] * yarray[4]) + (xarray[4] * yarray[5]) + (xarray[8] * yarray[6]) + (xarray[12] * yarray[7]),
a3 = (xarray[0] * yarray[8]) + (xarray[4] * yarray[9]) + (xarray[8] * yarray[10]) + (xarray[12] * yarray[11]),
a4 = (xarray[0] * yarray[12]) + (xarray[4] * yarray[13]) + (xarray[8] * yarray[14]) + (xarray[12] * yarray[15]),
b1 = (xarray[1] * yarray[0]) + (xarray[5] * yarray[1]) + (xarray[9] * yarray[2]) + (xarray[13] * yarray[3]),
b2 = (xarray[1] * yarray[4]) + (xarray[5] * yarray[5]) + (xarray[9] * yarray[6]) + (xarray[13] * yarray[7]),
b3 = (xarray[1] * yarray[8]) + (xarray[5] * yarray[9]) + (xarray[9] * yarray[10]) + (xarray[13] * yarray[11]),
b4 = (xarray[1] * yarray[12]) + (xarray[5] * yarray[13]) + (xarray[9] * yarray[14]) + (xarray[13] * yarray[15]),
c1 = (xarray[2] * yarray[0]) + (xarray[6] * yarray[1]) + (xarray[10] * yarray[2]) + (xarray[14] * yarray[3]),
c2 = (xarray[2] * yarray[4]) + (xarray[6] * yarray[5]) + (xarray[10] * yarray[6]) + (xarray[14] * yarray[7]),
c3 = (xarray[2] * yarray[8]) + (xarray[6] * yarray[9]) + (xarray[10] * yarray[10]) + (xarray[14] * yarray[11]),
c4 = (xarray[2] * yarray[12]) + (xarray[6] * yarray[13]) + (xarray[10] * yarray[14]) + (xarray[14] * yarray[15]),
d1 = (xarray[3] * yarray[0]) + (xarray[7] * yarray[1]) + (xarray[11] * yarray[2]) + (xarray[15] * yarray[3]),
d2 = (xarray[3] * yarray[4]) + (xarray[7] * yarray[5]) + (xarray[11] * yarray[6]) + (xarray[15] * yarray[7]),
d3 = (xarray[3] * yarray[8]) + (xarray[7] * yarray[9]) + (xarray[11] * yarray[10]) + (xarray[15] * yarray[11]),
d4 = (xarray[3] * yarray[12]) + (xarray[7] * yarray[13]) + (xarray[11] * yarray[14]) + (xarray[15] * yarray[15]);
newarray.push(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4);
return newarray;
}
var newmatrix = multiply(xmatrix, ymatrix);
$('#page1 img').css('transform', 'matrix3d(' + newmatrix[0] + ',' + newmatrix[1] + ',' + newmatrix[2] + ',' + newmatrix[3] + ',' + newmatrix[4] + ',' + newmatrix[5] + ',' + newmatrix[6] + ',' + newmatrix[7] + ',' + newmatrix[8] + ',' + newmatrix[9] + ',' + newmatrix[10] + ',' + newmatrix[11] + ',' + newmatrix[12] + ',' + newmatrix[13] + ',' + newmatrix[14] + ',' + newmatrix[15] + ')');
});
I know it's a lot of code, but if I could get a second a opinion, It would be greatly appreciated. Thanks
No plugins please.
I actually just edited the matrix() function and added this right before array.push:
if ( y = 1 ) {
a3 = a3 * -1;
c1 = c1 * -1;
}
And this fixed the issue.
I'm currently working on a Pinball game using the HTML5 Canvas and JavaScript. Right now I'm getting a hard time with the pixel by pixel collision, which is fundamental because of the flippers.
Right now my Bounding Box Collision seems to be working
checkCollision(element) {
if (this.checkCollisionBoundingBox(element)) {
console.log("colision with the element bounding box");
if (this.checkCollisionPixelByPixel(element)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
checkCollisionBoundingBox(element) {
if (this.pos.x < element.pos.x + element.width && this.pos.x + this.width > element.pos.x && this.pos.y < element.pos.y + element.height && this.pos.y + this.height > element.pos.y) {
return true;
} else {
return false;
}
}
I've tried several ways of implementing the pixel by pixel one but for some reason it does not work perfectly (on walls, on images, on sprites etc). I'll leave them here:
checkCollisionPixelByPixel(element) {
var x_left = Math.floor(Math.max(this.pos.x, element.pos.x));
var x_right = Math.floor(Math.min(this.pos.x + this.width, element.pos.x + element.width));
var y_top = Math.floor(Math.max(this.pos.y, element.pos.y));
var y_bottom = Math.floor(Math.min(this.pos.y + this.height, element.pos.y + element.height));
for (var y = y_top; y < y_bottom; y++) {
for (var x = x_left; x < x_right; x++) {
var x_0 = Math.round(x - this.pos.x);
var y_0 = Math.round(y - this.pos.y);
var n_pix = y_0 * (this.width * this.total) + (this.width * (this.actual-1)) + x_0; //n pixel to check
var pix_op = this.imgData.data[4 * n_pix + 3]; //opacity (R G B A)
var element_x_0 = Math.round(x - element.pos.x);
var element_y_0 = Math.round(y - element.pos.y);
var element_n_pix = element_y_0 * (element.width * element.total) + (element.width * (element.actual-1)) + element_x_0; //n pixel to check
var element_pix_op = element.imgData.data[4 * element_n_pix + 3]; //opacity (R G B A)
console.log(element_pix_op);
if (pix_op == 255 && element_pix_op == 255) {
console.log("Colision pixel by pixel");
/*Debug*/
/*console.log("This -> (R:" + this.imgData.data[4 * n_pix] + ", G:" + this.imgData.data[4 * n_pix + 1] + ", B:" + this.imgData.data[4 * n_pix + 2] + ", A:" + pix_op + ")");
console.log("Element -> (R:" + element.imgData.data[4 * element_n_pix] + ", G:" + element.imgData.data[4 * element_n_pix + 1] + ", B:" + element.imgData.data[4 * element_n_pix + 2] + ", A:" + element_pix_op + ")");
console.log("Collision -> (x:" + x + ", y:" + y +")");
console.log("This(Local) -> (x:" + x_0 + ", y:" + y_0+")");
console.log("Element(Local) -> (x:" + element_x_0 + ", y:" + element_y_0+")");*/
/*ball vector*/
var vector = {
x: (x_0 - Math.floor(this.imgData.width / 2)),
y: -(y_0 - Math.floor(this.imgData.height / 2))
};
//console.log("ball vector -> ("+vector.x+", "+vector.y+") , Angulo: "+ Math.atan(vector.y/vector.x)* 180/Math.PI);
// THIS WAS THE FIRST TRY, IT DIDN'T WORK WHEN THE BALL WAS GOING NORTHEAST AND COLLIDED WITH A WALL. DIDN'T WORK AT ALL WITH SPRITES
//this.angle = (Math.atan2(vector.y, vector.x) - Math.PI) * (180 / Math.PI);
// THIS WAS THE SECOND ATTEMPT, WORKS WORSE THAN THE FIRST ONE :/
//normal vector
var normal = {
x: (x_0 - (this.imgData.width / 2)),
y: -(y_0 - (this.imgData.height / 2))
};
//Normalizar o vetor
var norm = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
if (norm != 0) {
normal.x = normal.x / norm;
normal.y = normal.y / norm;
}
var n_rad = Math.atan2(normal.y, normal.x);
var n_deg = (n_rad + Math.PI) * 180 / Math.PI;
console.log("Vetor Normal -> (" + normal.x + ", " + normal.y + ") , Angulo: " + n_deg);
//Vetor Velocidade
var velocity = {
x: Math.cos((this.angle * Math.PI / 180) - Math.PI),
y: Math.sin((this.angle * Math.PI / 180) - Math.PI)
};
console.log("Vetor Velocidade -> (" + velocity.x + ", " + velocity.y + ") , Angulo: " + this.angle);
//Vetor Reflexao
var ndotv = normal.x * velocity.x + normal.y * velocity.y;
var reflection = {
x: -2 * ndotv * normal.x + velocity.x,
y: -2 * ndotv * normal.y + velocity.y
};
var r_rad = Math.atan2(reflection.y, reflection.x);
var r_deg = (r_rad + Math.PI) * 180 / Math.PI;
console.log("Vetor Reflexao -> (" + reflection.x + ", " + reflection.y + ") , Angulo: " + r_deg);
this.angle = r_deg;
return true;
}
}
}
return false;
}
}
The ball class
class Ball extends Element {
constructor(img, pos, width, height, n, sound, angle, speed) {
super(img, pos, width, height, n, sound);
this.angle = angle; //direction [0:360[
this.speed = speed;
}
move(ctx, cw, ch) {
var rads = this.angle * Math.PI / 180
var vx = Math.cos(rads) * this.speed / 60;
var vy = Math.sin(rads) * this.speed / 60;
this.pos.x += vx;
this.pos.y -= vy;
ctx.clearRect(0, 0, cw, ch);
this.draw(ctx, 1);
}
}
Assuming a "flipper" is composed of 2 arcs and 2 lines it would be much faster to do collision detection mathematically rather than by the much slower pixel-test method. Then you just need 4 math collision tests.
Even if your flippers are a bit more complicated than arcs+lines, the math hit tests would be "good enough" -- meaning in your fast-moving game, the user cannot visually notice the approximate math results vs the pixel-perfect results and the difference between the 2 types of tests will not affect gameplay at all. But the pixel-test version will take magnitudes more time and resources to accomplish. ;-)
First two circle-vs-circle collision tests:
function CirclesColliding(c1,c2){
var dx=c2.x-c1.x;
var dy=c2.y-c1.y;
var rSum=c1.r+c2.r;
return(dx*dx+dy*dy<=rSum*rSum);
}
Then two circle-vs-line-segment collision tests:
// [x0,y0] to [x1,y1] define a line segment
// [cx,cy] is circle centerpoint, cr is circle radius
function isCircleSegmentColliding(x0,y0,x1,y1,cx,cy,cr){
// calc delta distance: source point to line start
var dx=cx-x0;
var dy=cy-y0;
// calc delta distance: line start to end
var dxx=x1-x0;
var dyy=y1-y0;
// Calc position on line normalized between 0.00 & 1.00
// == dot product divided by delta line distances squared
var t=(dx*dxx+dy*dyy)/(dxx*dxx+dyy*dyy);
// calc nearest pt on line
var x=x0+dxx*t;
var y=y0+dyy*t;
// clamp results to being on the segment
if(t<0){x=x0;y=y0;}
if(t>1){x=x1;y=y1;}
return( (cx-x)*(cx-x)+(cy-y)*(cy-y) < cr*cr );
}