-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integer only coordinate space mode. #29
Comments
Disclaimer, I know nothing about GDI. What you describe applies only to strokes. The actual issue is that strokes in the Canvas2d API just like in many graphics APIs can only be "centered", i.e they'll spread from both inside and outside of the path. |
How do you know that this a matter of how “stroking” works ? I’m asking seriously. Are you aware of any authoritative reference defining “stroking”. I actually tried several searches and as I understand it "stroking" is about “materializing” the abstract line in a path and I can see how the choice of alignment comes into play when working with a wireframe you can actually see like in adobe illustrator and I’m not dismissing this. However, I’m not quite sure "alignment" is a “feature” of stroke. Like stroke may very well mean “Pen” so I disagree that the actual issue is "stroke" in fact it’s not an issue at all if one chooses to think about the canvas as Cartesian system with infinite points on either axis and stroke having alignment, but this does not necessarily exclude an additional approach where the canvas is viewed as what it is which is grid of pixels where each pixel can be identified by intersection of row, column. IMHO This one-to-one correspondence can very much simplifies things thus I suggested an additional mode of operation that is restricted to a whole number Cartesian system. I think a side-by-side comparison shows it all: Here is 50x50 grid cell using the canvas Api. Note that for some reason the bottom right pixel is slightly gray in color
Here is 50x50 grid cell using Gdi.
|
https://html.spec.whatwg.org/multipage/canvas.html#trace-a-path
You have this "one-to-one correspondence" with |
I understand what you’re saying, and if “trace-a-path” == “stroke” then so be it. I’m not arguing with the the standard (although it would be clearer if they used the word “stroke” there). I’m not arguing about the definition of “stroke”. The only reason I alluded to it is because that's how you display a LineTo (not a rectangle of width 1). I’m not proposing to redefine what stroke means but rather add a mode/api without stroke, modeled after a discrete Cartesian grid where coordinates refer to pixels which are rectangles with width and height of unit length (not points). Example:
I’m not saying this is “better” but can be simpler to reason about when working with straight lines as apposed to thinking about the interval between points in a continuous Cartesian Grid when stroking lines. Like if I want to display a line - on the screen - from 0,0 to 0,9 then I think its more intuitive to think about drawing a line from the first pixel down 9 pixels as apposed to thinking about how filling an area between imaginary points map to display pixels. |
And would that be simpler to reason about for the 99.9% of cases where paths aren't a grid on cartesian coordinates? I mean, what does this mean for a circle? For an oblique line? Etc. (Also, the trace a path algorithm I linked to is part of the stroke-steps one). |
BTW, it is even suggested not use floating-point coordinates for performance reasons. "Avoid floating-point coordinates and use integers instead" I assume this is not strictly about drawImage since I can clearly see that anti aliasing is applied when I draw a tilted line between whole coordinates. |
I'm not sure this is entirely related but ... A use case I have. I get that it's niche. I want to make ASCII graphs. I did this by making a function makeGraph(width, height) {
const data = new Uint8Array(width * height);
return {
width,
height,
plot(x, y, c) {
if (x >= 0 && x < width && y >= 0 && y < height) {
const offset = (height - (y | 0) - 1) * width + (x | 0);
data[offset] = c;
}
},
toString(conversion, {border} = {border: false}) {
const lines = [];
const end = `+${''.padEnd(width, '-')}+`;
const edge = border ? '|' : '';
if (border) {
lines.push(end);
}
for (let y = 0; y < height; ++y) {
const offset = y * width;
lines.push(`${edge}${[...data.subarray(offset, offset + width)].map(v => conversion[v]).join('')}${edge}`);
}
if (border) {
lines.push(end);
}
return lines.join('\n');
},
};
} I then use it like this
Which produces
If I had a mode for the canvas2D API that didn't anti-alias so it only stored the exact colors I specified, then I could use the gitspeaks mentioned "brushes". In Photoshop you can stroke with a "brush" or with a "pencil" It would be nice if you could do similar with the canvas 2d API. To be clear, I'm not specifically asking to stroke with "pixels" like photoshop. i'm just saying there are use cases for not anti-aliasing. Photoshop has the ability to create a "path" and "stroke" it. Which seems analogous to the terms used by Canvas 2D. It has the option to stroke with some option that doesn't anti-alias. It would be nice to have the same ability in Canvas 2D. |
I’m migrating a Windows GDI application to HTML using Canvas and I stumbled across the fact that canvas uses a fractional coordinate space which requires “moving” to the mid of a pixel in order to draw vertical and horizontal lines of width 1.
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors
Unfortunately, I couldn’t find any article explaining the motivation behind the use of fractional units in the canvas but after reviewing numerous canvas code examples on the web I noticed that’s its pretty common to see people adding 0.5 when drawing lines, so while I assume there are probably good reasons and uses cases for using fractional pixels (I’m far from an expert on this), perhaps it is equally applicable to have an integer only pixel mode (like in GDI) for simple cases where it is possible to establish a one-to-one mapping between whole number points on the Cartesian system and 1x1 squares on the canvas grid.
The text was updated successfully, but these errors were encountered: