javascript - Get canvas stroke points - javascript

How can I get the black points from a canvas stroke?
Here - https://jsfiddle.net/dsu3Lmfm/2/ - all points from the canvas are black.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineTo(20, 100);
ctx.lineTo(70, 100);
ctx.closePath();
ctx.stroke();
var imageData = ctx.getImageData(0, 0, c.width, c.height);
var pix = imageData.data;
// Loop over each pixel and get the black pixels
for (var i = 0, n = pix.length; i < n; i += 4) {
if (pix[i] === 0 && pix[i+1] === 0 && pix[i+2] === 0) {
var x = (i / 4) % c.width;
var y = (i / 4) / c.width;
console.log("x=" + parseInt(x, 10) + ", y=" + parseInt(y, 10));
}
}

Related

How to get the border of an imageData?

I am getting a figure from an imageData that looks like this:
How could I get the edges of that figure? so that it looks more or less like this:
I have tried to validate for each pixel that the previous, next, top and bottom pixel is transparent in order to save that pixel and then draw on another canvas
var context = canvas.getContext("2d");
var pixelData = context.getImageData(0, 0, canvas.width, canvas.height);
var result = []
for (let index = 0; index < pixelData.data.length; index += 4) {
if (pixelData.data[index] != 0) {
if ((pixelData.data[index + canvas.width * 4]) == 0 || (pixelData.data[index - canvas.width * 4]) == 0 || pixelData.data[index - 4] == 0 || pixelData.data[index + 4] == 0) {
var x = index / 4 % canvas.width
var y = (index / 4 - x) / canvas.width;
result.push({ x: x, y: y })
}
}
}
context.clearRect(0, 0, canvas.width, canvas.height)
context.beginPath()
result.forEach(point => {
context.lineTo(point.x, point.y)
})
context.strokeStyle = "#000"
context.stroke()
But this does not seem to work very well.
How could I obtain the edge or, failing that, the polygon that is formed in that figure?
Expanding on my question in the comments ...
Your if statement is detecting sequentially, so drawing lines on the order it was detected will not have the desired effect.
Below is some sample code, Just drawing letter "W" and apply your algorithm to detect the edge, I added some transparency so you can see the output of your lines in action, it should look like:
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
context.font = "99px Arial";
context.fillStyle = "red"
context.fillText("W", 20, 70)
var pixelData = context.getImageData(0, 0, canvas.width, canvas.height);
var result = []
for (let index = 0; index < pixelData.data.length; index += 4) {
if (pixelData.data[index] != 0) {
if ((pixelData.data[index + canvas.width * 4]) == 0 || (pixelData.data[index - canvas.width * 4]) == 0 || pixelData.data[index - 4] == 0 || pixelData.data[index + 4] == 0) {
var x = index / 4 % canvas.width
var y = (index / 4 - x) / canvas.width;
result.push({ x, y })
}
}
}
context.strokeStyle = "blue"
context.globalAlpha = 0.5
context.beginPath()
result.forEach(point => {
context.lineTo(point.x, point.y)
})
context.stroke()
<canvas id="canvas" width=100 height=100></canvas>
...But if instead of lines we draw small dots, we get a very different picture.
var canvas = document.getElementById('canvas');
var context = canvas.getContext("2d");
context.font = "99px Arial";
context.fillStyle = "red"
context.fillText("W", 20, 70)
var pixelData = context.getImageData(0, 0, canvas.width, canvas.height);
var result = []
for (let index = 0; index < pixelData.data.length; index += 4) {
if (pixelData.data[index] != 0) {
if ((pixelData.data[index + canvas.width * 4]) == 0 || (pixelData.data[index - canvas.width * 4]) == 0 || pixelData.data[index - 4] == 0 || pixelData.data[index + 4] == 0) {
var x = index / 4 % canvas.width
var y = (index / 4 - x) / canvas.width;
result.push({ x, y })
}
}
}
context.strokeStyle = "blue"
context.globalAlpha = 0.5
result.forEach(point => {
context.beginPath()
context.arc(point.x, point.y, 1, 0, 2 * Math.PI)
context.stroke()
})
<canvas id="canvas" width=100 height=100></canvas>
You do have the edge in the var result but that is not a polygon, so you can not do lines between the points or you get something else like we see in the first code snippet. If you want to transform that into a polygon, you will have to sort that array by the points proximity to each other, but that is another question...

How to transalate hexagon in canvas html using typescript

i drew a hexagon on canvas in html and i want to tranaslate the hexagon in canvas when i use a translate method it doesn't translate the hexagon but when i translate it does translate when i use the rectangle .
var canvas:HTMLCanvasElement = document.getElementById("myCanvas");
var context:CanvasRenderingContext2D = canvas.getContext("2d");
var x = 300;
var y = 100;
context.beginPath();
context.moveTo(x, y);
x = x + 120;
y = y + 100;
context.lineTo(x, y);
y = y + 120;
context.lineTo(x, y);
x = x - 125;
y = y + 100;
context.lineTo(x, y);
x = x - 125;
y = y - 100;
context.lineTo(x, y);
y = y - 120;
context.lineTo(x, y);
x = x + 130;
y = y - 100;
context.lineTo(x, y);
context.strokeStyle = "red";
context.lineWidth = 4;
context.fillStyle = "blue";
context.fill();
context.translate(400,400);
context.fillStyle = "blue";
context.fill();
context.save();
context.fillRect(10, 10, 100, 50);
context.translate(70, 70);
context.fillRect(10, 10, 100, 50);
Edit 1:
according to the #helder gave the answer I've made the changes but translate is not working
function hexagon(x:number, y:number, r:number, color:string) {
context.beginPath();
var angle = 0
for (var j = 0; j < 6; j++) {
var a = angle * Math.PI / 180
var xd = r * Math.sin(a)
var yd = r * Math.cos(a)
context.lineTo(x + xd, y + yd);
angle += 360 / 6
}
context.fillStyle = color;
context.fill();
context.translate(70,70);
context.fill();
}
hexagon(100, 100, 50, "red")
I would try to create a function that draws the hexagon that way you don't have to use translate.
See below
c = document.getElementById("canvas");
context = c.getContext("2d");
function hexagon(x, y, r, color) {
context.beginPath();
var angle = 0
for (var j = 0; j < 6; j++) {
var a = angle * Math.PI / 180
var xd = r * Math.sin(a)
var yd = r * Math.cos(a)
context.lineTo(x + xd, y + yd);
angle += 360 / 6
}
context.fillStyle = color;
context.fill();
}
hexagon(50, 50, 30, "red")
hexagon(40, 40, 10, "blue")
hexagon(60, 60, 10, "lime")
<canvas id=canvas >
Here is a break down of function hexagon(x, y, r, color)
it takes the center of the hexagon (x,y) a radius (r) and color
we loop over the six vertices and draw lines
the calculations are just a bit of trigonometry nothing fancy
With that we can draw hexagons at any location we want.
and that same function you can easily refactor to draw an octagon or other polygons.
Here is an animated version of those hexagons
c = document.getElementById("canvas");
context = c.getContext("2d");
delta = 0
function hexagon(x, y, r, color) {
context.beginPath();
var angle = 0
for (var j = 0; j < 6; j++) {
var a = angle * Math.PI / 180
var xd = r * Math.sin(a)
var yd = r * Math.cos(a)
context.lineTo(x + xd, y + yd);
angle += 360 / 6
}
context.fillStyle = color;
context.fill();
}
function draw() {
context.clearRect(0, 0, c.width, c.height)
var xd = 10 * Math.sin(delta)
var yd = 10 * Math.cos(delta)
hexagon(50 - xd, 50 - yd, 30, "red")
hexagon(40 + xd, 40 + yd, 10, "blue")
delta += 0.2
}
setInterval(draw, 100);
<canvas id=canvas>
As you can see there is no need to use translate

javascript canvas - generating a dynamic grid of squares on a canvas

I am working on a simple program in JS that creates a grid of squares on a canvas of any size. I am able to generate half the grid but for some reason my other half does not appear on the screen.
could anyone see a potentially flaw in my logic?
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="500px" height="500px" style="border:1px solid #d3d3d3;">
</canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var x = 0;
ctx.fillStyle = "black";
ctx.fillRect(x, 0, canvas.width / 2, canvas.height);
while (x < canvas.width / 2) {
var y = 0;
while (y < canvas.height) {
ctx.beginPath();
ctx.fillStyle = "#77f442";
ctx.fillRect(x + 30, y + 10, 20, 20);
ctx.stroke();
y = y + 50;
}
x = x + 50;
}
//var x = canvas.width / 2;
while ((x >= (canvas.width / 2)) && (x < canvas.width)) {
var y = 0;
while ((y >= (canvas.height)) && (y < canvas.height)) {
ctx.beginPath();
ctx.fillStyle = "#77f442";
ctx.fillRect(x + 10, y + 10, 20, 20);
ctx.stroke();
y = y + 50;
}
x = x + 50;
}
</script>
</body>
</html>
I had a logic error where I was checking for (y >= (canvas.height)
the fix was to use < instead of >=
correct code:
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var x = 0;
ctx.fillStyle = "black";
ctx.fillRect(x, 0, canvas.width / 2, canvas.height);
while (x < canvas.width) {
if (x < canvas.width / 2) {
var y = 0;
while (y < canvas.height) {
ctx.beginPath();
ctx.fillStyle = "#77f442";
ctx.fillRect(x + 30, y + 10, 20, 20);
ctx.stroke();
y = y + 50;
}
x = x + 50;
}
else if (x == canvas.width / 2)
{
while ((x >= (canvas.width / 2)) && (x < canvas.width)) {
var y = 0;
while ((y <= (canvas.height))) {
ctx.beginPath();
ctx.fillStyle = "#77f442";
ctx.fillRect(x , y + 10, 20, 20);
ctx.stroke();
y = y + 50;
}
x = x + 50;
}
}
}
</script>

How to i can see canvas log?

I am developing agario. İ want make countdown for game round but countdown not visible in canvas.
function drawGameScene() {
if (!lastCalledTime) {
lastCalledTime = Date.now();
fps = 60;
displayfps = fps;
} else {
delta = (Date.now() - lastCalledTime) / 1000;
lastCalledTime = Date.now();
fps = 1 / delta;
}
var a, oldtime = Date.now();
++cb;
timestamp = oldtime;
if (0 < playerCells.length) {
calcViewZoom();
var c = a = 0;
for (var d = 0; d < playerCells.length; d++) {
playerCells[d].updatePos();
a += playerCells[d].x / playerCells.length;
c += playerCells[d].y / playerCells.length;
}
posX = a;
posY = c;
posSize = viewZoom;
nodeX = (nodeX + a) / 2;
nodeY = (nodeY + c) / 2
} else {
nodeX = (29 * nodeX + posX) / 30;
nodeY = (29 * nodeY + posY) / 30;
viewZoom = (9 * viewZoom + posSize * viewRange()) / 10;
}
buildQTree();
mouseCoordinateChange();
xa || ctx.clearRect(0, 0, canvasWidth, canvasHeight);
if (xa) {
if (showDarkTheme) {
ctx.fillStyle = '#111111';
ctx.globalAlpha = .05;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.globalAlpha = 1;
}
else if (pembetema) {
ctx.fillStyle = '#ff4081';
ctx.globalAlpha = .05;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.globalAlpha = 1;
}else if (yesiltema) {
ctx.fillStyle = '#40ff58';
ctx.globalAlpha = .05;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.globalAlpha = 1;
}else if (default_tema) {
ctx.fillStyle = '#F2FBFF';
ctx.globalAlpha = .05;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.globalAlpha = 1;
}
} else {
drawGrid();
}
nodelist.sort(function (a, b) {
return a.size == b.size ? a.id - b.id : a.size - b.size
});
ctx.save();
ctx.translate(canvasWidth / 2, canvasHeight / 2);
ctx.scale(viewZoom, viewZoom);
ctx.translate(-nodeX, -nodeY);
if (transparentRender == true) {
ctx.globalAlpha = 0.6;
} else {
ctx.globalAlpha = 1;
}
/*drawBorders(ctx);*/
for (d = 0; d < Cells.length; d++) Cells[d].drawOneCell(ctx);
for (d = 0; d < nodelist.length; d++) nodelist[d].drawOneCell(ctx);
//console.log(Cells.length);
if (drawLine) {
drawLineX = (3 * drawLineX + lineX) /
4;
drawLineY = (3 * drawLineY + lineY) / 4;
ctx.save();
ctx.strokeStyle = "#FFAAAA";
ctx.lineWidth = 10;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.globalAlpha = .5;
ctx.beginPath();
for (d = 0; d < playerCells.length; d++) {
ctx.moveTo(playerCells[d].x, playerCells[d].y);
ctx.lineTo(drawLineX, drawLineY);
}
ctx.stroke();
ctx.restore()
}
// border -->
ctx.strokeStyle = '#00D1DF';
ctx.lineWidth = 25;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.beginPath();
ctx.moveTo(leftPos,topPos);
ctx.lineTo(rightPos,topPos);
ctx.lineTo(rightPos,bottomPos);
ctx.lineTo(leftPos,bottomPos);
ctx.closePath();
ctx.stroke();
// <--
ctx.restore();
///////////////////////////////////////// MY COUNTDOWN CODES ////////////////////////////////////////////////
ctx.globalAlpha = 1;
ctx.fillStyle = "#0000FF";
ctx.font = "30px Roboto";
if(this.countdown < 3600){
var countDownStr = "";
var min = Math.floor(this.countdown/60);
if ( min < 10 ){
countDownStr += "0";
}
countDownStr += min+":";
var sec = this.countdown%60;
if ( sec<10 ){
countDownStr += "0";
}
countDownStr += sec;
ctx.fillText(countDownStr, ((canvasWidth - ctx.measureText(countDownStr).width) * 0.5), 30);
}
///////////////////////////////////////// MY COUNTDOWN CODES ////////////////////////////////////////////////
lbCanvas && lbCanvas.width && ctx.drawImage(lbCanvas, canvasWidth - lbCanvas.width - 10, 10); // draw Leader Board
if (!hideChat)
{
if ((chatCanvas != null)&&(chatCanvas.width > 0)) ctx.drawImage(chatCanvas, 0, canvasHeight - chatCanvas.height - 50); // draw Chat Board
}
var mass = calcUserScore();
userScore = Math.max(userScore, mass);
if (0 != userScore) {
kb();
if (null == scoreText) {
scoreText = new UText(24, '#FFFFFF');
}
var boxOpacity = .25;
scoreText.setValue("Score: " + ~~(userScore / 100));
c = scoreText.render();
w = c.width;
ctx.globalAlpha = boxOpacity;
ctx.fillStyle = "#000000";
ctx.fillRect(10, 10, w + 10, 34);
ctx.globalAlpha = 1;
ctx.drawImage(c, 15, 15);
scoreText.setValue("Mass: " + ~~(mass / 100));
c = scoreText.render();
w = c.width;
ctx.fillStyle = "rgba(0,0,0, " + boxOpacity;
ctx.fillRect(10, 50, w + 10, 34);
ctx.drawImage(c, 15, 55);
}
drawSplitIcon(ctx);
drawTouch(ctx);
drawMap();
var deltatime = Date.now() - oldtime;
deltatime > 1E3 / 60 ? z -= .01 : deltatime < 1E3 / 65 && (z += .01);
.4 > z && (z = .4);
1 < z && (z = 1)
}
I added a comment line to where the countdown was. Where is the problem ? I am going crazy. I added a comment line to where the countdown was. Where is the problem ? I am going crazy. i need add "ctx.save()" or "ctx.restore()" codes ? What i need do ?

Simple shape transformation star -> circle canvas

I was just wondering if it is possible to transform between two shapes using just canvas.
ie: star to a cirle.
this is what I have so far:
var canvas,
ctx,
length = 15;
canvas = document.getElementById("star");
ctx = canvas.getContext("2d");
ctx.translate(30, 30);
ctx.rotate((Math.PI * 1 / 10));
for (var i = 5; i--;) {
ctx.lineTo(0, length);
ctx.translate(0, length);
ctx.rotate((Math.PI * 2 / 10));
ctx.lineTo(0, -length);
ctx.translate(0, -length);
ctx.rotate(-(Math.PI * 6 / 10));
}
ctx.lineTo(0, length);
ctx.closePath();
ctx.fill();
Here is a basic transition in pure canvas. Using arcs instead of lines is left as an exercise for the reader ;)
http://jsfiddle.net/pD9CM/
var canvas,
ctx,
length = 15;
canvas = document.getElementById("star");
ctx = canvas.getContext("2d");
var max = 50;
var inset = 0;
var direction = +1;
function draw() {
ctx.clearRect(0, 0, 300, 300);
ctx.beginPath();
var i = 11
while (i--) {
var angle = (i/10) * Math.PI * 2;
var distance = (i % 2 === 0) ? (max - inset) : max;
var pt = point(angle, distance);
if (i === 0) ctx.moveTo(pt.x + 150, pt.y + 150);
else ctx.lineTo(pt.x + 150, pt.y + 150);
}
ctx.fill();
if (inset < 0 || inset > 30) direction = -direction;
inset += direction;
}
function point(angle, distance) {
return {
x: Math.cos(angle) * distance,
y: Math.sin(angle) * distance
};
}
setInterval(draw, 20);

Categories

Resources