4

Is there any way to draw a rectangle whose composing lines have width thinner than 1 pixel?

This code works perfectly, as expected:

// context is a HTML5 canvas 2D context
context.lineWidth = 1;
context.strokeStyle = "black";
context.rect(0, 0, 20, 20);
context.stroke();

It draws a nice rectangle.

But, if I try to draw a rectangle with thinner lines:

// See line width
context.lineWidth = 0.5;
context.strokeStyle = "black";
context.rect(0, 0, 20, 20);
context.stroke();

It still draws a rectangle whose borders have 1 pixel width.

I'm dealing with the canvas object here, and not CSS, where you have ways to "simulate" this.

diegoesp
  • 113
  • 1
  • 10
  • 2
    How do you represent a 0.5 pixel line on your screen? – Shomz Feb 10 '16 at 00:28
  • Right :) I suppose I was thinking on some way of drawing thinner lines, like, for example, when you use CSS styles. I've looked around and I don't think I can use alternate units. – diegoesp Feb 10 '16 at 00:30
  • Possible duplicate of [CSS border less than 1px](http://stackoverflow.com/questions/13891177/css-border-less-than-1px) – BSMP Feb 10 '16 at 00:32
  • You might as well ask for half an atom. I forget what happens when you divide those though. – zero298 Feb 10 '16 at 00:39
  • JDX is a framework that emulates functionality of canvas, there you may set <1 px by defining a css class http://js2dx.com – Gonki Jun 23 '19 at 02:38

1 Answers1

3

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>

But again, I wonder how you expect the half-pixel line to look on your screen, antialiasing?

Right :) I suppose I was thinking on some way of drawing thinner lines, like, for example, when you use CSS styles. I've looked around and I don't think I can use alternate units.

There's no way to make something that's smaller than the smallest component unit, in our case a pixel. You can mimic the thinner look by transparency, or opacity, or even some sort of antialiasing (which again relies on transparency or the colouring of the neighbouring pixels), but not by trying to go below one pixel.

I agree, there is a sub-pixel rendering mode in browsers, for example, when you work with percentages, but in the end, the browser just renders full pixels with some of the modification I've described above.


And you know if you could render unit smaller than pixels, you'd technically have infinite resolutions on displays. I wish it was possible. :)

Shomz
  • 37,421
  • 4
  • 57
  • 85
  • Hey, no problem! I hope you can use the scaled version to achieve what you want. – Shomz Feb 10 '16 at 00:41
  • 1
    @Shomz the canvas API does render at sub pixel resolutions, down to 0.03 pixels. Try 'ctx.fillStyle = "#FFF"; ctx.fillRect(0,0,0.03,1);d = ctx.getImageData(0,0,1,1).data;` will give you `[255,255,255,1]` width of 0.5 will give [255,255,255,113]. I use subpixel rendering all the time, the rendering API does a very good job of representing sub pixel drawings. – Blindman67 Feb 10 '16 at 03:13
  • @Blindman67 I know, you can also see it in my scaling example, but I was referring to how would you represent the sub-pixels on your monitor because OP wants to draw lines thinner than 1px. – Shomz Feb 10 '16 at 03:18
  • 2
    The problem is (maybe), even if you specify 1px, the line is drawn with 2 pixels. See https://stackoverflow.com/questions/13879322/drawing-a-1px-thick-line-in-canvas-creates-a-2px-thick-line – Fredo May 25 '20 at 09:04
  • @Fredo, right, but OP wanted a line thinner than 1px. – Shomz May 25 '20 at 13:47