don't use center-aligned strokes for bars
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.5k
- Forks
- 463
- PR merge metrics
- No merged PRs in 30d
Description
not quite sure if this is a net positive or not, but drawing crisp bars with canvas-native strokes is a real pain in the ass with a lot of accidental edge cases. for a long time i've been trying to figure out how to do performant masking in canvas (the opposite of clipping) for uPlot's purposes. today i finally figured it out.
- the first one is just what canvas does natively.-
- the second if we add some math, but it still bleeds stroke and can end up accidentally anti-aliased (non crisp). this is what uPlot currently does.
- the last is the holy grail, where the stroke is drawn using an additional fill with a mask. the math is simple and always exact, and never bleeds.
https://jsfiddle.net/eaLfo8zn/

<canvas id="can2" width="300" height="150"></canvas>
<canvas id="can3" width="300" height="150"></canvas>
<canvas id="can1" width="300" height="150"></canvas>
canvas {
image-rendering: pixelated;
}
let strokeWidth = 9;
var c = document.getElementById("can1");
var ctx = c.getContext("2d");
let s = new Path2D();
let f = new Path2D();
s.rect(0, 0, 150, 100);
f.rect(0 + strokeWidth, 0 + strokeWidth, 150 - strokeWidth * 2, 100 - strokeWidth * 2);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.moveTo(75 + 0.5, 0);
ctx.lineTo(75 + 0.5, 100);
ctx.stroke();
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.fill(f);
ctx.fillStyle = "rgba(0,0,255,0.5)";
s.addPath(f);
ctx.fill(s, 'evenodd');
var c2 = document.getElementById("can2");
var ctx2 = c2.getContext("2d");
ctx2.strokeStyle = 'black';
ctx2.lineWidth = 1;
ctx2.moveTo(75 + 0.5, 0);
ctx2.lineTo(75 + 0.5, 100);
ctx2.stroke();
let s2 = new Path2D();
s2.rect(0, 0, 150, 100);
ctx2.lineWidth = strokeWidth;
ctx2.fillStyle = "rgba(255,0,0,0.5)";
ctx2.fill(s2);
ctx2.strokeStyle = "rgba(0,0,255,0.5)";
ctx2.stroke(s2);
var c3 = document.getElementById("can3");
var ctx3 = c3.getContext("2d");
ctx3.strokeStyle = 'black';
ctx3.lineWidth = 1;
ctx3.moveTo(75 + 0.5, 0);
ctx3.lineTo(75 + 0.5, 100);
ctx3.stroke();
let s3 = new Path2D();
s3.rect(0 + strokeWidth / 2, 0 + strokeWidth / 2, 150 - strokeWidth, 100 - strokeWidth);
ctx3.lineWidth = strokeWidth;
ctx3.fillStyle = "rgba(255,0,0,0.5)";
ctx3.fill(s3);
ctx3.strokeStyle = "rgba(0,0,255,0.5)";
ctx3.stroke(s3);
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the three canvas stroke examples in the linked JSFiddle and compare them with the current bar rendering. Read the issue's canvas masking example first; done means bars no longer rely on center-aligned strokes and render crisp edges without bleeding or accidental anti-aliasing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- data-visualization
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100