Change color of an image by pixels - javascript

I want to make one third of an image red , one third green and one third blue (all by width. I mean like flag of France but with red, green and blue) but my code is doing nothing except showing the image.
function func(im) {
let w = im.getWidth();
let w1 = w / 3,
w2 = w / 3 + 1,
w3 = w / 3 + w / 3;
for (let pix of im.values()) {
let y = pix.getY();
if (y <= w1) pix.setRed(255);
else if (y > w1 && y <= w2) pix.setGreen(255);
else pix.setBlue(255);
}
}
let imm = new SimpleImage("https://i.imgur.com/yaYZaHk.jpg");
func(imm);
print(imm);

It is possible to grab the pixel data from the canvas and modify the pixels.
It's not the most elegant solution, but all you need to do is:
Determine which x-position you are at (pixel % rows)
Use that value to determine the column you are in (x / ctx.canvas.width)
Modify the correct color channel (red, green or blue) to change the intensity
Example
This is by no means a complete example, just an illustration of the concept of applying a pixel filter to canvas data.
let ctx = document.querySelector('#draw').getContext('2d')
var img = new Image()
img.addEventListener('load', (e) => drawOnLoad(ctx, img), false)
img.src = 'https://i.stack.imgur.com/hS81J.png'
function drawOnLoad(ctx, img) {
ctx.fillStyle = '#FFF'
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height)
//drawImageScaled(ctx, img)
ctx.fillStyle = '#0F0'
ctx.font = '45px Verdana'
ctx.textBaseline = 'middle'
ctx.textAlign = 'center'
ctx.fillText('Hello World', ctx.canvas.width / 2, ctx.canvas.height / 2)
applyFilter(ctx)
}
function drawImageScaled(ctx, img) {
let canvas = ctx.canvas
let cw = canvas.width, ch = canvas.height
let iw = img.width, ih = img.height
let sx = cw / iw, sy = ch / ih
let ratio = Math.min(sx, sy)
let x = (cw - iw * ratio) / 2, y = (ch - ih * ratio) / 2
ctx.clearRect(0, 0, cw, ch)
ctx.drawImage(img, 0, 0, iw, ih, x, y, iw * ratio, ih * ratio)
}
function applyFilter(ctx) {
let imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height)
let data = imageData.data
let pixels = data.length / 4
let pixelsPerRow = pixels / ctx.canvas.width
let rows = Math.ceil(pixels / pixelsPerRow)
for (let pixel = 0; pixel < pixels; pixel++) {
let x = pixel % rows
let y = Math.floor(pixel / pixelsPerRow)
let r = data[pixel * 4]
let g = data[pixel * 4 + 1]
let b = data[pixel * 4 + 2]
var avg = Math.round((r + g + b) / 3);
let px = x / ctx.canvas.width
if (px <= 0.33) {
data[pixel * 4 ] -= ((r / avg) * 127);
data[pixel * 4 + 1] -= ((g / avg) * 127);
data[pixel * 4 + 2] += ((b / avg) * 127);
} else if (px > 0.33 && px <= 0.66) {
data[pixel * 4 ] += ((r / avg) * 127);
data[pixel * 4 + 1] += ((g / avg) * 127);
data[pixel * 4 + 2] += ((b / avg) * 127);
} else {
data[pixel * 4 ] += ((r / avg) * 127);
data[pixel * 4 + 1] -= ((g / avg) * 127);
data[pixel * 4 + 2] -= ((b / avg) * 127);
}
}
ctx.putImageData(imageData, 0, 0)
}
#draw {
border: thin solid grey;
}
<canvas id="draw"></canvas>

I think you'll want to take a look at this post that uses PIL. You can just split the image into three separate images/arrays, tint each one whichever color you want, and then recombine the tinted images.

Related

Build a pyramid of balls using the canvas

I'm having difficulties replicating the pyramid below on the canvas.
I'm struggling with the math portion on how to draw a new ball on each new line. Here is my code so far.
<canvas id="testCanvas" width="300" height="300" style="border:1px solid #d3d3d3;"></canvas>
<script>
// Access canvas element and its context
const canvas = document.getElementById('testCanvas');
const context = canvas.getContext("2d");
const x = canvas.width;
const y = canvas.height;
const radius = 10;
const diamater = radius * 2;
const numOfRows = canvas.width / diamater;
function ball(x, y) {
context.arc(x, y, radius, 0, 2 * Math.PI, true);
context.fillStyle = "#FF0000"; // red
context.fill();
}
function draw() {
for (let i = 0; i < numOfRows; i++) {
for (let j = 0; j < i + 1; j++) {
ball(
//Pos X
(x / 2),
//Pos Y
diamater * (i + 1)
);
}
}
ball(x / 2, y);
context.restore();
}
draw();
</script>
I've been stuck on this problem for a while. I appreciate any assistance you can provide.
Thank you.
I noticed that the circle do not touch. I am not sure if you need or want them to but as this presented an interesting problem I create this answer.
Distance between stacked circles.
The distance between rows can be calculated using the right triangle as shown in the following image
Where R is the radius of the circle and D is the distance between rows.
D = ((R + R) ** 2 - R ** 2) ** 0.5;
With that we can get the number of rows we can fit given a radius as
S = (H - R * 2) / D;
Where H is the height of the canvas and S is the number of rows.
Example
Given a radius fits as many rows as possible into the give canvas height.
const ctx = canvas.getContext("2d");
const W = canvas.width, H = canvas.height, CENTER = W / 2;
const cols = ["#E80", "#0B0"];
draw();
function fillPath(path, x, y, color) {
ctx.fillStyle = color;
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.fill(path);
}
function draw() {
const R = 10;
const D = ((R * 2) ** 2 - R ** 2) ** 0.5;
const S = (H - R * 2) / D | 0;
const TOP = R + (H - (R * 2 + D * S)) / 2; // center horizontal
const circle = new Path2D();
circle.arc(0, 0, R, 0, Math.PI * 2);
var y = 0, x;
while (y <= S) {
x = 0;
const LEFT = CENTER - (y * R);
while (x <= y) {
fillPath(circle, LEFT + (x++) * R * 2, TOP + y * D, cols[y % 2]);
}
y ++;
}
}
canvas {
border:1px solid #ddd;
}
<canvas id="canvas" width="300" height="180"></canvas>
Radius to fit n rows of stacked circles
Or if you have the height H and the number of rows S you want to fit. As shown in next image.
We want to find R given H and S we rearrange for H and solve the resulting quadratic with
ss = S * S - 2 * S + 1;
a = 4 / ss;
b = -4 * H / ss;
c = H * H / ss;
R = (-b-(b*b - 4 * a * c) ** 0.5) / (2 * a); // the radius
Example
Given the number of rows (number input) calculates the radius that will fit that number of rows
const ctx = canvas.getContext("2d");
const W = canvas.width, H = canvas.height, CENTER = W / 2;
rowsIn.addEventListener("input", draw)
const cols = ["#DD0", "#0A0"];
draw();
function fillPath(path, x, y, color) {
ctx.fillStyle = color;
ctx.setTransform(1, 0, 0, 1, x, y);
ctx.fill(path);
}
function draw() {
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,W,H);
const S = Number(rowsIn.value);
const ss = S * S - 2 * S + 1;
const a = 4 / ss - 3, b = -4 * H / ss, c = H * H / ss;
const R = (- b - ((b * b - 4 * a * c) ** 0.5)) / (2 * a); // the radius
const TOP = R;
const D = ((R * 2) ** 2 - R ** 2) ** 0.5;
//const S = (H - R * 2) / D;
const circle = new Path2D();
circle.arc(0, 0, R, 0, Math.PI * 2);
var y = 0, x;
while (y < S) {
x = 0;
const LEFT = CENTER - (y * R);
while (x <= y) {
fillPath(circle, LEFT + (x++) * R * 2, TOP + y * D, cols[y % 2]);
}
y ++;
}
}
canvas {
border:1px solid #ddd;
}
<canvas id="canvas" width="300" height="180"></canvas>
<input type="number" id="rowsIn" min="3" max="12" value="3">Rows
How you can approach this problem is by breaking it down into one step at a time.
On (1)st row draw 1 circle
On (2)nd row draw 2 circles
On (3)rd row draw 3 circles
And so on...
Then you have to figure out where to draw each circle. That also you can break down into steps.
1st-row 1st circle in the center (width)
2nd-row 1st circle in the center minus diameter
2nd-row 2nd circle in the center plus diameter
and so on.
Doing this way you will find a pattern to convert into 2 for loops.
Something like this:
//1st row 1st circle
ball(w/2,radius * 1, red);
//2nd row 1st circle
ball(w/2 - radius,radius * 3, blue);
//2nd row 2nd circle
ball(w/2 + radius,radius * 3, blue);
The code below shows each step how each ball is drawn. I have also done few corrections to take care of the numberOfRows.
const canvas = document.getElementById('testCanvas');
const context = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const radius = 10;
const diamater = radius * 2;
const numOfRows = Math.min(h / diamater, w / diamater);
const red = "#FF0000";
const blue = "#0000FF";
var k = 1;
function ball(x, y, color) {
setTimeout(function() {
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, true);
context.fillStyle = color;
context.fill();
}, (k++) * 250);
}
for (var i = 1; i <= numOfRows; i++) {
for (var j = 1; j <= i; j++) {
var y = (i * radius * 2) - radius;
var x = (w / 2) - ((i * radius) + radius) + (j * diamater);
ball(x, y, i % 2 ? red : blue);
}
}
<canvas id="testCanvas"
width="300" height="180"
style="border:1px solid #d3d3d3;"></canvas>

How to draw arc on canvas HTML5 without interpolation?

I am using the following code to draw on HTML5 canvas:
const context = canvas.getContext('2d');
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = color;
context.fill();
context.closePath();
However, if I print unique values:
console.log(new Set(context.getImageData(0, 0, canvas.width, canvas.height).data))
I can see that the color that I use in fillStyle gets interpolated.
I tried to disable interpolation/smoothing by adding the following flags:
context.imageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.mozImageSmoothingEnabled = false;
However, it does not help. I would highly appreciate if you could advise me how to fix the issue.
The is no native way to draw circles that are pixelated. To do that you must render each pixel manually.
There are several methods you can use to do this. The most common have some additional artifacts (like inconsistent line width) that are hard to avoid.
The following function draw a circle using a modification of the Berzingham line algorithm (also good for rendering pixelated lines) called the Midpoint circle algorithm
Unfortunately most of the methods that can draw arbitrary lines and circle are slow. The two mentioned above are the fastest standard methods I know about.
Example
The example defines 3 functions to draw pixelated circles
pixelPixelatedCircle (Red outer circles and single blue in example) draws a single pixel wide circle using the current fill style
fillPixelatedCircle (Red inner circle in example) draws a a solid circle using the current fill style
strokePixelatedCircle (Black circles in example) draws a circle line with a width. Not the width only works when it is >= 2. If you want a single pixel width use the first function. Also not that this function uses a second canvas to render the circle
The example draws all three types
The outer red circle drawn using pixelPixelatedCircle are to demonstrate that the quality of the circles are consistent. There should be alternating 1 pixel width circles, red and dark red. and an outer blue just touching the canvas edge circles.
For circles less than radius of 2 use ctx.rect as the outcome will be the same.
Note the circle radius is an integer thus a circle radius 1000 will be identical to circle radius 1000.9 The sample applies to the circle center. To be able to have sub pixel positioning and radius will need another algorithm which is slower and has lower quality lines.
Note I added a simple zoom canvas so I could see the results better, I was going to remove it but left it in just for interested people. It is not crucial to the answer.
const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const size = Math.min(w, h);
const circleWorkCanvas = document.createElement("canvas");
const cCtx = circleWorkCanvas.getContext("2d");
function resizeCircleCanvas(ctx) {
if (circleWorkCanvas.width !== ctx.canvas.width || circleWorkCanvas.height !== ctx.canvas.height) {
circleWorkCanvas.width = ctx.canvas.width;
circleWorkCanvas.height = ctx.canvas.height;
}
}
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.35, 5);
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.3, 4);
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.25, 3);
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.2, 2);
ctx.fillStyle = "red";
fillPixelatedCircle(ctx, w / 2, h / 2, size * 0.15);
ctx.fillStyle = "blue";
pixelPixelatedCircle(ctx, w / 2, h / 2, size * 0.38);
ctx.fillStyle = "blue";
pixelPixelatedCircle(ctx, w / 2, h / 2, size * 0.5);
ctx.fillStyle = "red";
for(let v = 0.40; v < 0.49; v += 1 / size) {
ctx.fillStyle = "#600"
pixelPixelatedCircle(ctx, w / 2, h / 2, size * v);
ctx.fillStyle = "#F00"
v += 1 / size;
pixelPixelatedCircle(ctx, w / 2, h / 2, size * v );
}
function strokePixelatedCircle(ctx, cx, cy, r, lineWidth) {
resizeCircleCanvas(ctx);
cCtx.clearRect(0, 0, cCtx.canvas.width, cCtx.canvas.height);
cCtx.globalCompositeOperation = "source-over";
cCtx.fillStyle = ctx.strokeStyle;
fillPixelatedCircle(cCtx, cx, cy, r + lineWidth / 2);
cCtx.globalCompositeOperation = "destination-out";
fillPixelatedCircle(cCtx, cx, cy, r - lineWidth / 2);
cCtx.globalCompositeOperation = "source-over";
ctx.drawImage(cCtx.canvas, 0, 0);
}
function fillPixelatedCircle(ctx, cx, cy, r){
r |= 0; // floor radius
ctx.setTransform(1,0,0,1,0,0); // ensure default transform
var x = r, y = 0, dx = 1, dy = 1;
var err = dx - (r << 1);
var x0 = cx - 1| 0, y0 = cy | 0;
var lx = x,ly = y;
ctx.beginPath();
while (x >= y) {
ctx.rect(x0 - x, y0 + y, x * 2 + 2, 1);
ctx.rect(x0 - x, y0 - y, x * 2 + 2, 1);
if (x !== lx){
ctx.rect(x0 - ly, y0 - lx, ly * 2 + 2, 1);
ctx.rect(x0 - ly, y0 + lx, ly * 2 + 2, 1);
}
lx = x;
ly = y;
y++;
err += dy;
dy += 2;
if (err > 0) {
x--;
dx += 2;
err += (-r << 1) + dx;
}
}
if (x !== lx) {
ctx.rect(x0 - ly, y0 - lx, ly * 2 + 1, 1);
ctx.rect(x0 - ly, y0 + lx, ly * 2 + 1, 1);
}
ctx.fill();
}
function pixelPixelatedCircle(ctx, cx, cy, r){
r |= 0;
ctx.setTransform(1,0,0,1,0,0); // ensure default transform
var x = r, y = 0, dx = 1, dy = 1;
var err = dx - (r << 1);
var x0 = cx | 0, y0 = cy | 0;
var lx = x,ly = y;
var w = 1, px = x0;
ctx.beginPath();
var rendering = 2;
while (rendering) {
const yy = y0 - y;
const yy1 = y0 + y - 1;
const xx = x0 - x;
const xx1 = x0 + x - 1;
ctx.rect(xx, yy1, 1, 1);
ctx.rect(xx, yy, 1, 1);
ctx.rect(xx1, yy1, 1, 1);
ctx.rect(xx1, yy, 1, 1);
if (x !== lx){
const yy = y0 - lx;
const yy1 = y0 + lx - 1;
const xx = x0 - ly;
w = px - xx;
const xx1 = x0 + ly - w;
ctx.rect(xx, yy, w, 1);
ctx.rect(xx, yy1, w, 1);
ctx.rect(xx1, yy, w, 1);
ctx.rect(xx1, yy1, w, 1);
px = xx;
}
lx = x;
ly = y;
y++;
err += dy;
dy += 2;
if (err > 0) {
x--;
dx += 2;
err += (-r << 1) + dx;
}
if (x < y) { rendering -- }
}
ctx.fill();
}
const ctxZ = canvasZoom.getContext("2d");
canvas.addEventListener("mousemove",(event) => {
ctxZ.clearRect(0,0,30,30);
ctxZ.drawImage(canvas, -(event.pageX-10), -(event.pageY-10));
});
canvas {border: 1px solid black}
#canvasZoom {
width: 300px;
height: 300px;
image-rendering: pixelated;
}
<canvas id="canvas" width="300" height="300"></canvas>
<canvas id="canvasZoom" width="30" height="30"></canvas>
There doesn't appear to be a built-in setting that I can find, but you can loop through the image data and set the individual pixels if they are within some threshold of what you want.
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.beginPath();
context.arc(250, 250, 250, 0, 2 * Math.PI, false);
context.fillStyle = 'rgb(255, 0, 0)';
context.fill();
context.closePath();
console.log(getDistinctColors(context).length + " distinct colors before filter");
solidifyColor(context, 255, 0, 0);
console.log(getDistinctColors(context).length + " distinct colors aftrer filter");
function solidifyColor(context, r, g, b, threshold = 3) {
const imageData = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
for (let i = 0; i < imageData.data.length; i += 4) {
var rDif = Math.abs(imageData.data[i + 0] - r);
var bDif = Math.abs(imageData.data[i + 1] - b);
var gDif = Math.abs(imageData.data[i + 2] - g);
if (rDif <= threshold && bDif <= threshold && gDif <= threshold) {
imageData.data[i + 0] = r;
imageData.data[i + 1] = g;
imageData.data[i + 2] = b;
imageData.data[i + 3] = 255; // remove alpha
}
}
context.putImageData(imageData, 0, 0);
}
function getDistinctColors(context) {
var colors = [];
const imageData = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
for (let i = 0; i < imageData.data.length; i += 4) {
colors.push([
imageData.data[i + 0], // R value
imageData.data[i + 1], // G value
imageData.data[i + 2], // B value
imageData.data[i + 3] // A value
]);
}
return [...new Set(colors.map(a => JSON.stringify(a)))].map(a => JSON.parse(a));
}
<canvas id=canvas width=500 height=500></canvas>

How can i get random colors for each object in canvas with JS?

I would like to get random colors for each object in canvas how can i do that, I have tried this:
for (var i = 0; i < 100; i++) {
var raza = (Math.random() - 0.001) * 30;
var x = Math.random() * (innerWidth - raza * 2) + raza;
var y = Math.random() * (innerHeight - raza * 2) + raza;
var dx = (Math.random() - 0.5) * 4; //calcul viteza X
var dy = (Math.random() - 0.5) * 4; //calcul viteza Y
var color = c.strokeStyle = "#" + ((1 << 24) * Math.random() | 0).toString(12);
cercArray.push(new Circle(x, y, dx, dy, raza, color));
}
Lots of different ways to do this, here is an example using HSL.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
let lastDate = Date.now() - 500;
function draw() {
requestAnimationFrame(draw);
const color = {
h: Math.floor(Math.random() * 360),
s: Math.floor(Math.random() * 100),
v: Math.floor(Math.random() * 100)
};
if (lastDate + 500 < Date.now()) {
lastDate = Date.now();
ctx.fillStyle = `hsl(${color.h},${color.s}% ,${color.v}%)`;
ctx.fillRect(0, 0, 100, 100);
}
}
draw();
<canvas></canvas>

cloning element javascript

var canvas = document.createElement('canvas')
canvas.width = 900
canvas.height = 600
canvas.style.backgroundColor = '#d9d9d9'
document.body.appendChild(canvas)
var ctx = canvas.getContext('2d')
//defining the moving square
var RADIUS = 7
var SPEED = 1.5
//startposition
let pos = [Math.floor(Math.random() * 900) + 1, Math.floor(Math.random() * 600) + 1]
//coordinates
let direction = [0, 1]
//defining what will happen if the square touches the borderlines
setInterval(function() {
if(pos[0] <= RADIUS || pos[0] >= canvas.width - RADIUS ||
pos[1] <= RADIUS || pos[1] >= canvas.height - RADIUS) {
pos =[Math.floor(Math.random() * 900) + 1, Math.floor(Math.random() * 600) + 1]
}
pos[0] += direction[0] * SPEED
pos[1] += direction[1] * SPEED
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = "#6666ff"
ctx.fillRect(pos[0] - RADIUS, pos[1] - RADIUS, 2 * RADIUS, 2 * RADIUS)
}, 20)
setInterval(function() {
const randomAngle = Math.random() * 2 * Math.PI
direction = [Math.cos(randomAngle), Math.sin(randomAngle)]
}, 500)
So I have this Code and now want that the box that moves around can duplicate after lets say 15 seconds. also the duplication also has to duplicate again after the same amount of time. I came across this:
var item01 = item.cloneNode(true);
but don't find a proper way to implement it.

adding custom animation in canvas html5

this might be somewhat difficult but i wil still ask, so i made a starfield ,now what i want to do is to have my stars( a pair each) connected to eachother by a line ,now this line will expand as the stars move forward and disappear when the stars move out of the canvas .any help would be appreciated here this is difficult i have the logic but i seem unable to follow the correct way to implement it
function randomRange(minVal, maxVal) {
return Math.floor(Math.random() * (maxVal - minVal - 1)) + minVal;
}
function initStars() {
for (var i = 0; i < stars.length; i++) {
stars[i] = {
x: randomRange(-25, 25),
y: randomRange(-25, 25),
z: randomRange(1, MAX_DEPTH)
}
}
}
function degToRad(deg) {
radians = (deg * Math.PI / 180) - Math.PI / 2;
return radians;
}
function animate() {
var halfWidth = canvas.width / 2;
var halfHeight = canvas.height / 2;
ctx.fillStyle = "rgb(0,0,0)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < stars.length; i++) {
stars[i].z -= 0.2;
if (stars[i].z <= 0) {
stars[i].x = randomRange(-25, 25);
stars[i].y = randomRange(-25, 25);
stars[i].z = MAX_DEPTH;
}
var k = 128.0 / stars[i].z;
var px = stars[i].x * k + halfWidth;
var py = stars[i].y * k + halfHeight;
if (px >= 0 && px <= 1500 && py >= 0 && py <= 1500) {
var size = (1 - stars[i].z / 32.0) * 5;
var shade = parseInt((1 - stars[i].z / 32.0) * 750);
ctx.fillStyle = "rgb(" + shade + "," + shade + "," + shade + ")";
ctx.beginPath();
ctx.arc(px, py, size, degToRad(0), degToRad(360));
ctx.fill();
}
}
}
function animate() {
var halfWidth = canvas.width / 2;
var halfHeight = canvas.height / 2;
ctx.fillStyle = "rgb(0,0,0)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < stars.length; i++) {
stars[i].z -= 0.2;
if (stars[i].z <= 0) {
stars[i].x = randomRange(-25, 25);
stars[i].y = randomRange(-25, 25);
stars[i].z = MAX_DEPTH;
}
var k = 128.0 / stars[i].z;
var px = stars[i].x * k + halfWidth;
var py = stars[i].y * k + halfHeight;
if (px >= 0 && px <= 1500 && py >= 0 && py <= 1500) {
var size = (1 - stars[i].z / 32.0) * 5;
var shade = parseInt((1 - stars[i].z / 32.0) * 750);
ctx.fillStyle = "rgb(" + shade + "," + shade + "," + shade + ")";
ctx.beginPath();
ctx.arc(px, py, size, degToRad(0), degToRad(360));
ctx.fill();
}
}
}
<!DOCTYPE html5>
<html>
<head>
<title>stars</title>
<script src="convergis.js"></script>
<script>
MAX_DEPTH = 32;
var canvas, ctx;
var stars = new Array(500);
window.onload = function() {
canvas = document.getElementById("tutorial");
if( canvas && canvas.getContext ) {
ctx = canvas.getContext("2d");
initStars();
setInterval(animate,17);
}
}
</script>
</head>
<body>
<canvas id='tutorial' width='1500' height='1500'>
</canvas>
</body>
</html>
You could just say you want a lightspeed effect!
One way very cheap way to do it is to paint the background with some transparency. You can also render a set of points close together in order to make the illusion of the effect.
The good way to do it is shaders since they will allow you to add glow and some other nice image trickery that will make it look better. Here is a good example: https://www.shadertoy.com/view/Xdl3D2
Below I used the canvas api lineTo and even with a fixed line width, it's a pretty good final result.
var MAX_DEPTH = 64;
var LINELENGTH = 0.1;
var stars = new Array(500);
var canvas = document.getElementById("tutorial");
canvas.width = innerWidth;
canvas.height = innerHeight;
var ctx = canvas.getContext("2d");
initStars();
setInterval(animate,17);
function randomRange(minVal, maxVal) {
return Math.floor(Math.random() * (maxVal - minVal - 1)) + minVal;
}
function initStars() {
for (var i = 0; i < stars.length; i++) {
stars[i] = {
x: randomRange(-25, 25),
y: randomRange(-25, 25),
z: randomRange(1, MAX_DEPTH)
}
}
}
function degToRad(deg) {
radians = (deg * Math.PI / 180) - Math.PI / 2;
return radians;
}
function animate() {
var halfWidth = canvas.width / 2;
var halfHeight = canvas.height / 2;
ctx.fillStyle = "rgba(0,0,0,1)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < stars.length; i++) {
stars[i].z -= 0.5;
if (stars[i].z <= 0) {
stars[i].x = randomRange(-25, 25);
stars[i].y = randomRange(-25, 25);
stars[i].z = MAX_DEPTH;
}
var k = 254.0 / stars[i].z;
var px = stars[i].x * k + halfWidth;
var py = stars[i].y * k + halfHeight;
if (px >= 0 && px <= 1500 && py >= 0 && py <= 1500) {
var size = (1 - stars[i].z / 32.0) * 2;
var shade = parseInt((1 - stars[i].z / 32.0) * 750);
ctx.strokeStyle = "rgb(" + shade + "," + shade + "," + shade + ")";
ctx.lineWidth = size;
ctx.beginPath();
ctx.moveTo(px,py);
var ox = size * (px - halfWidth) * LINELENGTH;
var oy = size * (py - halfHeight) * LINELENGTH;
ctx.lineTo(px + ox, py + oy);
ctx.stroke();
}
}
}
<canvas id='tutorial' width='1500' height='1500'></canvas>

Categories