On my application I have to draw separate lines. One line solid and one line dashed. I am using the CanvasRenderingContext2D. My problem is how can I draw one dotted line and one solid line using the same context. What I have tried is:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.setLineDash([2, 2])
ctx.moveTo(50, 50); // Begin first sub-path
ctx.lineTo(200, 50);
ctx.moveTo(50, 90); // Begin second sub-path
ctx.lineTo(280, 120);
ctx.stroke();
But it draws lines as dotted. It makes sense why, because I am using the same context for both lines but I need to use the same context in my app. I just gave a minimal example. Is there a way to do this?
In a canvas I would recommend to use some sort of prototype to represent a point in your coordinate system. Then you can simply pass the points to your drawLine function and pass an additional style.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
function Point(x, y) {
this.x = x;
this.y = y;
}
function drawLine(from, to, style=[]) {
ctx.beginPath();
ctx.setLineDash(style)
ctx.moveTo(from.x, from.y);
ctx.lineTo(to.x, to.y);
ctx.stroke();
ctx.closePath();
}
drawLine(new Point(50, 50), new Point(200, 50)); // solid line
drawLine(new Point(50, 90), new Point(280, 120), [2,2]); // dashed line
<canvas id="canvas" width="500" height="500"></canvas>
Related
Say I have created a polygon-shaped image by creating a shape in HTML5 canvas and then filling it with an image, e.g. as below:
Now I want to round the corners on this hexagon.
There is a lineJoin = "round" property available but this doesn't seem to work (I believe because the shape is filled and there is no outer line to round).
Does anyone have any idea how to do this with HTML5 canvas or any other means?
Here is the code used to create the image:
var ctx = document.getElementById('myCanvas').getContext('2d');
var a = ctx.canvas.width, r = a / 5;
var side = Math.sqrt((4/3) * r * r);
// Draw your image onto the canvas (here I'll just fill the
// surface with red
var img = new Image();
img.src = "https://upload.wikimedia.org/wikipedia/commons/0/03/Mountain_Bluebird.jpg";
img.onload = function () {
var pattern = ctx.createPattern(img, "no-repeat");
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, a, a);
// Switch the blending mode
ctx.globalCompositeOperation = 'destination-in';
// Draw the hexagon shape to mask the image
ctx.beginPath();
ctx.moveTo(0, side/2);
ctx.lineTo(0, 3*side/2);
ctx.lineTo(r, 2*side);
ctx.lineTo(2*r, 3*side/2);
ctx.lineTo(2*r, side/2);
ctx.lineTo(r, 0);
ctx.closePath();
ctx.fill();
};
<canvas width="1000" height="1000" id="myCanvas"></canvas>
Just change the order you draw in and then change globalCompositeOperation to 'source-in'.
I made some adjustments because some of the corners in your code were getting clipped off but didn't adjust the image position (I hope that's easy enough to do)
Preview
You need to adjust the image position by the way like I said
Snippet
var ctx = document.getElementById('myCanvas').getContext('2d');
var a = ctx.canvas.width, r = a / 5;
var side = Math.sqrt((4/3) * r * r) - 20;
// Draw your image onto the canvas (here I'll just fill the
// surface with red
var img = new Image();
img.src = "https://upload.wikimedia.org/wikipedia/commons/0/03/Mountain_Bluebird.jpg";
img.onload = function () {
ctx.lineJoin = "round";
ctx.lineWidth = 50;
// Draw the hexagon shape to mask the image
ctx.beginPath();
ctx.moveTo(50, 50 + side/2);
ctx.lineTo(50, 50 + 3*side/2);
ctx.lineTo(50 + r, 50 + 2*side);
ctx.lineTo(50 + 2*r, 50 + 3*side/2);
ctx.lineTo(50 + 2*r, 50 + side/2);
ctx.lineTo(50 + r, 50);
ctx.closePath();
ctx.stroke();
ctx.fill();
// Switch the blending mode
ctx.globalCompositeOperation = 'source-in';
var pattern = ctx.createPattern(img, "no-repeat");
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, a, a);
};
<canvas width="1000" height="1000" id="myCanvas"></canvas>
There is no automatic way of doing this. The canvas API is pretty low-level, so it doesn't know that you've drawn a shape and want to detect where all the edges are. What you can do, but it would be a bit of a hassle to do is use bezierCurveTo. This method takes size arguments and can create curves. Combine that with your lines, and you can create rounded corners.
bezierCurveTo
You could also add circles at all the corners, with the arc method.
I need to delete the line which was previously drawn by putting another line over it. The new line should be the same color as the background.
I tried:
http://jsfiddle.net/wgenf10x/
<canvas id="canvas" style="background-color: black;">
Javascript:
var canvas = document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var screenW = canvas.width;
var screenH = canvas.height;
setColor("#ffffff");
draw();
function setColor(colorHexStr){
ctx.strokeStyle = colorHexStr;
}
function line(x1,y1,x2,y2){
ctx.moveTo(x1,y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function draw(){
setColor("white");
line(0,0,screenW, screenH);
setColor("black");
line(0,0,screenW, screenH);
}
But the white line is not completely erased. What is going wrong?
P.S. Please do not suggest clearing the whole canvas. I don't need it.
You are seeing artifacts created by canvas's automatic anti-aliasing.
Just increase the "erasing" lineWidth (ctx.lineWidth+=1;) to also over-write that anti-aliasing.
I want to know how to rotate a line in canvas.
Say I have the canvas set-up.
ctx.beginPath();
ctx.strokeStyle = "#000000";
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
ctx.closePath();
How do I rotate this line?
Thanks,
Alex
Here's how to rotate a line segment between p1 & p2 around that segment's midpoint:
The idea is to:
Save the unrotated state of the context using context.save
Set the rotation point at the midpoint of the line using context.translate
Rotate to a specified radian angle using context.rotate
Draw the line. This is the tricky part...Since the canvas is already rotated and since the canvas origin is now the line's midpoint, you must moveTo minus the line's length/2 and lineTo the lines length/2: context.moveTo(-length/2,0); and context.lineTo(length/2,0);
Restore the context to its unrotated state with context.restore
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var p1={x:75,y:75};
var p2={x:150,y:150};
var dx=p2.x-p1.x;
var dy=p2.y-p1.y;
var length=Math.sqrt(dx*dx+dy*dy);
var angle=Math.atan2(dy,dx);
var midX=(p2.x+p1.x)/2;
var midY=(p2.y+p1.y)/2;
console.log(midX,midY);
draw(angle);
requestAnimationFrame(animate);
function animate(time){
requestAnimationFrame(animate);
draw(angle);
angle+=Math.PI/30;
}
function draw(radianAngle){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(midX,midY);
ctx.rotate(radianAngle);
ctx.beginPath();
ctx.strokeStyle='red';
ctx.moveTo(-length/2,0);
ctx.lineTo(length/2,0);
ctx.stroke();
ctx.restore();
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
Note: This code shows rotation around your line's midpoint, but you can rotate around any point by using context.translate(anyRotationPointX,anyRotationPointY);
To rotate anything you can use context method - rotate().
We can't rotate line like object (like in SVG), but we can - redraw canvas with new rotated line.
var canvas = document.getElementById("example"),
ctx = example.getContext('2d'),
canvasWidth = canvas.width,
canvasHeight = canvas.height,
p1 = {x:canvasWidth/2+50,y:canvasHeight/2},
p2 = {x:p1.x,y:p1.y+100},
middlePoint = {x:(p1.x+p2.x)/2,y:(p1.y+p2.y)/2};
function rotate(degree,rotatePoint,drFunc) {
rotatePoint = rotatePoint || {x:canvasWidth/2,y:canvasHeight/2};
// Clear the canvas
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// Move registration point to the center of the canvas
ctx.translate(rotatePoint.x, rotatePoint.y);
// Rotate 1 degree
ctx.rotate((Math.PI / 180)*degree);
// Move registration point back to the top left corner of canvas
ctx.translate(-rotatePoint.x, -rotatePoint.y);
drFunc();
}
function drFunc(){
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
ctx.closePath();
}
rotate(1,middlePoint,drFunc);
Fiddle
I want to draw a line with one color, and the next line with a different color. But when I call stroke() the second time, the first line is draw again! How can I avoid it? Here's my code:
var canv = document.getElementById("canvas");
var ctx = canv.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.strokeStyle = "#FF0000";
ctx.stroke();
ctx.moveTo(100,100);
ctx.lineTo(100,200);
ctx.strokeStyle = "#999999";
ctx.stroke();
Thanks in advance!
Just insert a beginPath() in there:
var canv = document.getElementById("canvas");
var ctx = canv.getContext("2d");
ctx.moveTo(0,0);
ctx.lineTo(100,100);
ctx.strokeStyle = "#FF0000";
ctx.stroke();
cxt.beginPath(); // <---
ctx.moveTo(100,100);
ctx.lineTo(100,200);
ctx.strokeStyle = "#999999";
ctx.stroke();
That will reset your path. A stroke just strokes what exists on the path but does not clear it. You will have to manually reset the path for each new shape you want to draw.
The advantage is that you can reuse the path for fill, clip and point testing. The disadvantage is that it's easy to forget sometimes.
I'm trying to draw a graphic pattern of lines from the black to the red depending on the Y value of a wave. To find out if I'm doing it right whit the approach, I started a test in JSFiddle:
Test
var j,k;
k=255;
var green=150;
var blue=150;
var canvas=document.getElementById('canvas');
var ctx=canvas.getContext('2d');
for(j=0;j<k;j++)
{
ctx.beginPath();
ctx.moveTo(j, 0);
ctx.lineTo(j, 150);
ctx.strokeStyle = "rgb("&j&", 0, 0)";
ctx.stroke();
}
But the result is just a grey tone in all the lines, although the drawing method is inside a loop and the 'red' value is changing.
Putting #Juhana's good suggestion into practice:
var j,k;
k=255;
var green=150;
var blue=150;
var canvas=document.getElementById('canvas');
var ctx=canvas.getContext('2d');
for(j=0;j<k;j++){
ctx.beginPath();
ctx.moveTo(j, 0);
ctx.lineTo(j, 150);
ctx.strokeStyle = "rgb("+j+",0,0)";
ctx.stroke();
}