HTML5 canvas line width less that 1 pixel
Although it doesn't make much sense, you can acheive that with using a regular 1-pixel line with a 50% scaled canvas (but again it's a 1-pixel rendition, read below). See this snippet:
var canvas = document.querySelector('canvas');var context = canvas.getContext('2d');
function scale() { context.scale(0.5, 0.5); draw();}
function draw() { context.beginPath(); context.moveTo(100, 150); context.lineTo(450, 50); context.stroke();}
draw()
<canvas width="400" height="150"></canvas><button onclick="scale()">Scale down</button>
Canvas Line Width too thick
Opacity is how a canvas creates the appearance of lines narrower than a pixel, because a pixel is (by definition) the smallest unit a canvas works with.
That doesn't mean all hope is lost, however, because this is only a problem depending on what you mean by "pixel".
There's the CSS unit px
, which corresponds to what used to be the smallest actual pixels available on video display devices, typically in the range of 72-96 per inch (28-38 per cm).
And then there are actual device pixels, which are now often half as small or smaller.
The trick to getting sharper lines with a canvas when you've got high-res device pixels is scaling. Use this to figure how much you can effectively scale:
const scaling = window.devicePixelRatio || 1;
Suppose the value here is 2 (as it is on my current laptop). If you want to create a canvas that occupies, say, 400px by 300px, create an 800x600 canvas. Then use CSS styling width: 400px; height: 300px
on your canvas.
Now you'll be able to create sharp half-width lines so long as the device you're drawing to supports the higher resolution.
I use this trick many places in the Angular app at https://skyviewcafe.com/. There's a link there to the source code if you want to dig through it to find examples of high-res canvas drawing.
Please note!
You're either have to specify a lineWidth
of 1 when you mean half-width, or use canvas scaling like this:
const context = this.canvas.getContext('2d');
context.scale(scaling, scaling);
Be careful with context.scale()
— its effects are cumulative. If you execute context.scale(2, 2)
twice in a row with the same context, your scaling factor will be 4, not 2.
context.setTransform(1, 0, 0, 1, 0, 0);
...resets the scaling factor if you want to call context.scale()
more than once, without the effect being cumulative.
HTML5 Canvas - create striped canvas with lineWidth and createPattern()
Code logic problems
The size of the pattern needs to match the slope of the line. That size must be expanded to allow for a set spacing between the lines.
Your code has a fixed size that does not match the slope of either of the lines you draw.
The lines you draw are both in different directions. You will never get them to create a repeatable pattern.
The code you have given is too ambiguous for me to understand what you wish to achieve thus the example adds some constraints that considers my best guess at your requirements.
Tileable striped pattern
The function in the example below creates a striped repeatable (tilded) pattern.
The function createStripedPattern(lineWidth, spacing, slope, color)
requires 4 arguments.
lineWidth
width of the line to drawspacing
distance between lines. Eg if lineWidth is 5 and spacing is 10 then the space between the lines is the same width as the line.slope
The slope of the line eg 45 degree slope is 1. I have only tested value >= 1 and am not sure if it will work below 1.Nor have I tested very large slopes. The point of the example is to show how to draw the line on the pattern to repeat without holes.
color
Color of line to draw.
The function works by creating a canvas that will fit the constraints given by the arguments. It then draws a line from the top left to bottom right corners. This leaves a gap in the repeating pattern at the top right and bottom left corners.
To fill the missing pixels two more lines are drawn. One through the top right corner and the other through the bottom left.
Note you could also just copy the canvas onto itself (offset to the corners) to fill the missing corner pixels. For pixel art type patterns this may be preferable.
Note that canvas sizes are integer values and lines are rendered at sub pixel accuracy. For very small input values there will be artifact as the relative error between the canvas (integer) pixel size and required (floating point) size grows larger
Example
The example contains the function to create the pattern as outlined above and then renders some examples.
The first canvas has inset patterns with each pattern increasing the line width will keeping the spacing and slope constant.
The second canvas just fills with a fixed lineWidth as 4, spacing as 8 and a slope of 3
function createAARotatedPattern(lineWidth, spacing, ang, color) {
const can = document.createElement('canvas');
const w = can.width = 2;
const h = can.height = spacing;
const ctx = can.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(0, 0, 2, lineWidth);
const pat = ctx.createPattern(can, 'repeat');
const xAx = Math.cos(ang);
const xAy = Math.sin(ang);
pat.setTransform(new DOMMatrix([xAx, xAy, -xAy, xAx, 0, 0]));
return pat;
}
function createStripedPattern(lineWidth, spacing, slope, color) {
const can = document.createElement('canvas');
const len = Math.hypot(1, slope);
const w = can.width = 1 / len + spacing + 0.5 | 0; // round to nearest pixel
const h = can.height = slope / len + spacing * slope + 0.5 | 0;
const ctx = can.getContext('2d');
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.beginPath();
// Line through top left and bottom right corners
ctx.moveTo(0, 0);
ctx.lineTo(w, h);
// Line through top right corner to add missing pixels
ctx.moveTo(0, -h);
ctx.lineTo(w * 2, h);
// Line through bottom left corner to add missing pixels
ctx.moveTo(-w, 0);
ctx.lineTo(w, h * 2);
ctx.stroke();
return ctx.createPattern(can, 'repeat');
};
function fillWithPattern(canvas, pattern, inset = 0) {
const ctx = canvas.getContext('2d');
ctx.clearRect(inset, inset, canvas.width - inset * 2, canvas.height - inset * 2);
ctx.fillStyle = pattern;
ctx.fillRect(inset, inset, canvas.width - inset * 2, canvas.height - inset * 2);
return canvas;
}
fillWithPattern(targetCanvas, createStripedPattern(2, 6, 2, "#000"));
fillWithPattern(targetCanvas, createStripedPattern(3, 6, 2, "#000"), 50);
fillWithPattern(targetCanvas, createStripedPattern(4, 6, 2, "#000"), 100);
fillWithPattern(targetCanvas1, createStripedPattern(4, 8, 3, "#000"));
var y = 0;
var ang = 0;
const ctx = targetCanvas2.getContext('2d');
while (y < targetCanvas2.height) {
ctx.fillStyle = createAARotatedPattern(2, 5, ang, "#000");
ctx.fillRect(0, y, targetCanvas2.width, 34);
y += 40;
ang += 2 * Math.PI / (targetCanvas2.height / 40);
}
<canvas id="targetCanvas" width="300" height="300"></canvas>
<canvas id="targetCanvas1" width="300" height="300"></canvas>
<canvas id="targetCanvas2" width="300" height="600"></canvas>
Incorrect line position with HTML Canvas when lineWidth is not set to 1
The fill is the root cause of your problems
const geometryParsed = [ { geom: [{ x:78, y:132 }, { x:59, y:132 }, { x:59, y:183 }, { x:78, y:183 }, { x:78, y:132 }] }, { geom: [{ x:97, y:132 }, { x:78, y:132 }, { x:78, y:166 }, { x:97, y:166 }, { x:97, y:132 }] },];
const canv = document.getElementById("canvas");const context = canv.getContext("2d");
context.translate(-50, -100)context.lineWidth = 2;for (let k = 0; k < geometryParsed.length; k++) { const geometry = geometryParsed[k].geom; context.beginPath(); context.moveTo(geometry[0].x, geometry[0].y); for (let i = 1; i < geometry.length; i++) { context.lineTo(geometry[i].x, geometry[i].y); } context.stroke();}
context.translate(80, 0)context.lineWidth = 4;for (let k = 0; k < geometryParsed.length; k++) { const geometry = geometryParsed[k].geom; context.beginPath(); context.moveTo(geometry[0].x, geometry[0].y); for (let i = 1; i < geometry.length; i++) { context.lineTo(geometry[i].x, geometry[i].y); } context.stroke(); context.fillStyle = "white"; context.fill();}
<canvas id="canvas" width="476px" height="170px"></canvas>
Line Width in Canvas
Happily (and Sadly) you have correctly implemented "pixel-snapping" when you add/subtract .5 pixels to get your lines to align with pixel boundaries. Unlike Photoshop, there is no option to automatically pixel snap in canvas. ...I feel your pain!
How to make line width for custom line in html5 canvas
A context.beginPath()
is missing between
context.lineWidth = 1;
context.stroke(); // Draw it
and
context.lineTo(lrectx, lrecty);
context.lineWidth = 8;
context.strokeStyle = "#ddd";
context.stroke();
Without the beginPath
call you are simply re-stroking all or the paths and subpaths already defined with the new stroke style and width.
The general answer to the second part of your question is that you don't get to do this.
Painting a canvas is equivalent to drawing an image. You can work out where the mouse is over the image, but you would then need to work out (in your program) if the mouse is over some pixels you want to change and redraw the canvas if it is.
If you want to use CSS :hover
pseudo classes to change presentation you will need to construct the source code of an SVG element for the graphic, create the element from the source code generated, and supply appropriate CSS for the SVG element's child nodes that will be affected by mouse position.
HTML5 Canvas — Line too thick
You don't need to use 0.5 , when the lineWidth is 4 you must use:
2
instead of0
(w-2)
instead ofw
(h-2)
instead ofh
var canvas = document.getElementById("c"), c = canvas.getContext("2d"), w = canvas.width, h = canvas.height, hallwayWidth = w * 0.10, /*18px*/ l = 2;
c.beginPath(); c.lineWidth = l*2; c.moveTo(l,l); c.lineTo(w / 3, l); c.moveTo(l, l); c.lineTo(l, h-l); c.moveTo(w-l, l); c.lineTo(w-l, h-l); c.moveTo(w / 3 + hallwayWidth, l); c.lineTo(w-l, l); c.moveTo(l, h-l); c.lineTo(w / 2, h-l); c.moveTo(w / 2 + hallwayWidth, h-l); c.lineTo(w-l, h-l);
/*code for thick line*/ c.moveTo(hallwayWidth, l); c.lineTo(hallwayWidth, w / 3);
c.stroke();
canvas { display: block; margin: 0 auto; margin-top: 50px; /* border: 1px solid red; */ background:red;}
<canvas id="c" width="200" height="200"></canvas>
Related Topics
What HTML/CSS Attributes Are Mail Safe
What Does "<HTML Xmlns="Http://Www.W3.Org/1999/Xhtml">" Do
How to Construct a Table Header Than Spans Multiple Rows in HTML
Is It Okay to Add Id/Class to <Link> Tag
Placing an Image to The Top Right Corner - CSS
Using Images Inside <Button> Element
How to Make a Div 100% of Window Height
What's The Key Difference Between HTML 4 and HTML 5
How to Center a Navigation Bar with CSS or HTML
Which Inline HTML Styles Does Github Markdown Accept
Automatic Retina Images for Web Sites
How to Make My Navi-Bar The Same Across My HTML