HTML2 Canvas drawing dashed line in a loop - javascript

Can somebody explain me why lines doesn't look similar to each other?
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.strokeStyle = "#ff0000";
ctx.setLineDash([10,10]);
for(let i = 0; i < 5; i++) {
ctx.moveTo(0, 300/5 * i);
ctx.lineTo(500, 300/5 * i);
}
ctx.closePath();
ctx.stroke();
#canvas { border: 1px solid #eaeaea}
<canvas id="canvas" width="500" height="300"/>

Related

Edit lineTo points (in canvas)

I want to move lineTo points.
How to do it?
I'm new to Canvas.
I'll give an example with Path.
This is my example:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
var line = ctx.lineTo(300, 100);
ctx.lineTo(70, 100);
ctx.lineTo(20, 20);
ctx.fillStyle = "red";
ctx.fill();
setTimeout(function() {
/*
I want something like this:
line.editpoints(300, 150);
*/
}, 3000);
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
Well, canvas as the name suggests, is a canvas (just like in paintings). You can draw on it, but you cannot move things on it as it is not "dynamic".
What you can do, though, is clear it and then draw on top at a different location.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function clearContext(ctx) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
function drawTriangle(offsetX = 0, offsetY = 0) {
ctx.beginPath();
ctx.moveTo(offsetX + 20, offsetY + 20);
var line = ctx.lineTo(offsetX + 300, offsetY + 100);
ctx.lineTo(offsetX + 70, offsetY + 100);
ctx.lineTo(offsetX + 20, offsetY + 20);
ctx.fillStyle = "red";
ctx.fill();
}
drawTriangle();
setTimeout(function() {
clearContext(ctx);
drawTriangle(50, 50);
}, 3000);
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;"></canvas>

how to make a row of triangles using loops?

How do I make a row of triangles?
Here's the code I have so far.
I'm new I don't know what to do here.
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126, 300);
ctx.lineTo(200, 400);
ctx.lineTo(50, 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You can use the iteration (i) and multiply it by the spacing you want and add it to the x value.
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = coolCanvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126+(i*170), 300);
ctx.lineTo(200+(i*170), 400);
ctx.lineTo(50+(i*170), 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You should use a variable to add to the X positions and increment as you want :
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let delta = 0;
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126 + delta, 300);
ctx.lineTo(200 + delta, 400);
ctx.lineTo(50 + delta, 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
delta += 174;
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You can create a separate function to handle drawing the triangles, then pass in the xStart as the base x-coordinate value for any triangle to be drawn. Then in the showDrawing function, run a loop and multiply the i variable to some spacing value. In your code, your triangle is 150 pixels wide and starts at x-value of 50, so I multiplied the i value by 200 for consistency in my solution code.
Additionally, I highly advise using the variable name you set (coolCanvas) as the reference to the canvas or set this variable to be named canvas instead. If you only ever set the canvas once and reference it once, you can probably skip setting the reference altogether:
let ctx = document.getElementById("canvas").getContext("2d");
function drawTriangle(ctx, xStart) {
ctx.lineWidth = 5;
ctx.strokeStyle = "blue";
ctx.fillStyle = "purple";
ctx.beginPath();
ctx.moveTo(xStart + 126, 300);
ctx.lineTo(xStart + 200, 400);
ctx.lineTo(xStart + 50, 400);
ctx.closePath();
ctx.fill()
ctx.stroke();
}
function showDrawing() {
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
drawTriangle(ctx, i * 200);
}
}
document.getElementById("draw").addEventListener("click", showDrawing);
canvas {
border: 3px solid #000000;
}
<div><button id="draw">Drawing</button></div>
<div><canvas id="canvas" width="1500" height="700"></canvas></div>

How to use: globalCompositeOperation on multiple objects in JavaScript Canvas

I'm attempting to create a circle menu in JavaScript canvas, something that would look similar to this:
Here is the code I'm using:
let canvas = document.querySelector("#canvas");
canvas.width = 500;
canvas.height = 500;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,.45)"; // color
let circlePath = [];
let centerCircle = new Path2D();
for (let t = 0; t < 8; t++) {
circlePath[t] = new Path2D();
circlePath[t].moveTo(250, 250);
circlePath[t].arc(
250,
250,
190,
Math.PI * 2 * 0.125 * t,
Math.PI * 2 * 0.125 * t + Math.PI * 2 * 0.1175
);
circlePath[t].closePath();
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.fill(centerCircle);
canvas.addEventListener("mousemove", function (event) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let t = 0; t < 8; t++) {
if (ctx.isPointInPath(circlePath[t], event.offsetX, event.offsetY)) {
ctx.fillStyle = "blue";
} else {
ctx.fillStyle = "rgba(0,0,0,.45)";
}
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
//ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
});
#canvas {
border: 1px solid #000;
background: green;
};
<canvas id="canvas"></canvas>
The problem I am having is that when I try to use ctx.globalCompositeOperation = "destination-out"; to "punch out" a hole in the midle of the arcs using the white circle, it makes all of the objects disappear.
Thank you in advance for any input provided.
Figured it out! Had to place ctx.globalCompositeOperation = "destination-out"; in the right places, followed by: ctx.globalCompositeOperation = "source-over";
Here is the updated code:
let canvas = document.querySelector("#canvas");
canvas.width = 500;
canvas.height = 500;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,.45)"; // color
let circlePath = [];
let centerCircle = new Path2D();
for (let t = 0; t < 8; t++) {
circlePath[t] = new Path2D();
circlePath[t].moveTo(250, 250);
circlePath[t].arc(
250,
250,
190,
Math.PI * 2 * 0.125 * t,
Math.PI * 2 * 0.125 * t + Math.PI * 2 * 0.1175
);
circlePath[t].closePath();
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
ctx.globalCompositeOperation = "source-over";
canvas.addEventListener("mousemove", function (event) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let t = 0; t < 8; t++) {
if (ctx.isPointInPath(circlePath[t], event.offsetX, event.offsetY)) {
ctx.fillStyle = "blue";
} else {
ctx.fillStyle = "rgba(0,0,0,.45)";
}
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
ctx.globalCompositeOperation = "source-over";
});
#canvas {
border: 1px solid #000;
background: green;
};
<canvas id="canvas"></canvas>

How can I get the "outline" of a Path stroke, and get the points to create a filled Path shape?

I want to retrieve the corresponding points to a 'outlinestroke' and save it as a Shape, instead of a "path with a stroke"
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineWidth = 12;
ctx.lineCap = 'round'
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
</script>
</body>
</html>
This is the result of the code:
But I want to have the Outline of this stroke, and turn it into a Path and give it a stroke.
The fill should be transparent.
And only have a small outline.
Is there a way to "trace or convert" the stroke to a outline path to get the following result:
And if this is not possible:
Before drawing, to use the given points to define the shape of a path.
Here is what I tried:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var width = 12;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineWidth = width;
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 1;
ctx.fillStyle = "#ccc";
ctx.moveTo(20-width/2, 270);
ctx.quadraticCurveTo(20-width/2, 350+width/2, 200-width/2, 270+width/2);
ctx.lineTo(200-width/2, 270-width/2);
ctx.quadraticCurveTo(20+width/2, 350-width/2, 20+width/2, 270-width/2);
ctx.lineTo(20-width/2, 270);
ctx.fillStyle = "#999";
ctx.fill();
ctx.stroke();
ctx.closePath();
Which results in the following:
There are no API features to turn a strokes outline into a path.
You can however use a composite operation to create the inner transparency.
Example
Creating outline using globalCompositeOperation = "destination-out";
The gradient is just to show it is transparent.
const OUTLINE_WIDTH = 1; // in pixels
var ctx = canvas.getContext("2d");
ctx.lineWidth = 22;
ctx.lineCap = 'round'
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
ctx.globalCompositeOperation = "destination-out";
ctx.lineWidth = 22 - OUTLINE_WIDTH * 2;
ctx.stroke();
ctx.globalCompositeOperation = "source-over"; // restore default
canvas {
border:1px solid #aaa;
background: linear-gradient(90deg, rgba(180,255,224,1) 0%, rgba(169,169,255,1) 100%);
}
<canvas id="canvas"></canvas>

Using multiple arcs to crop circle from image

I am trying to crop a circle out of 2 images and place them side by side like so:
const ctx = $('#canvas')[0].getContext("2d");
const image = new Image();
image.onload = () => {
const coords = [[115, 62.5], [495, 62.5]];
const coords2 = [[65, 12.5] , [445, 12.5]];
for(let i = 0; i < coords.length; i++) {
ctx.beginPath();
ctx.arc(coords[i][0], coords[i][1], 50, 0, Math.PI * 2, true);
ctx.clip();
ctx.drawImage(image, coords2[i][0], coords2[i][1], 100, 100);
}
};
image.src = 'https://placeholdit.imgix.net/~text?txtsize=50&w=700&h=250&bg=afeafe';
#canvas {
border:1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>
However, this is only cropping one of the images and the other one is not showing and I don't understand why?
When I comment out these lines
ctx.beginPath();
ctx.arc(coords[i][0], coords[i][1], 50, 0, Math.PI * 2, true);
ctx.clip();
It places the 2 images correctly, so the positioning is not the issue.
Fixed by saving the context before clipping it and then restoring it after clipping it like so:
const ctx = $('#canvas')[0].getContext("2d");
const image = new Image();
image.onload = () => {
const coords = [[115, 62.5], [495, 62.5]];
const coords2 = [[65, 12.5] , [445, 12.5]]
for(let i = 0; i < coords.length; i++) {
ctx.save();
ctx.beginPath();
ctx.arc(coords[i][0], coords[i][1], 50, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
ctx.drawImage(image, coords2[i][0], coords2[i][1], 100, 100);
ctx.restore();
}
};
image.src = 'https://placeholdit.imgix.net/~text?txtsize=50&w=700&h=250&bg=afeafe';
#canvas {
border:1px solid grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>

Categories

Resources