edemaine / cocreate

Cocreate Shared Whiteboard/Drawing
MIT License
209 stars 27 forks source link

Better rendering of pen strokes #156

Closed mehtank closed 3 years ago

mehtank commented 3 years ago

Is there a reason why there's a separate polyline renderer vs pen renderer? I can just s/renderPen/renderPoly/ here (with no other changes):

https://github.com/edemaine/cocreate/blob/ab69573e3ed8a0288a8d6c70787a8b1e74515cd1/client/RenderObjects.coffee#L383-L384

The output looks basically the same, and that can make it much easier to implement line styles (#61, which could supercede highlighter mode effe32c?) uniformly across all tools.

edemaine commented 3 years ago

The issue is that pen strokes have varying stroke width (via w), when you're using a pressure-sensitive pen. SVG has no support for such polylines. Eventually I plan to render pen objects via <path> (computing the outline of the stroke)... Inkscape's PowerStroke does this, so perhaps we could use their code.

For now, we should optimize the common case where all points have the same w value. The renderer can keep track, for each pen object, whether the ws are all the same. As long as it's true, it can render a path object. If it changes to false, it can switch to the current rendering.

We might also want to remove the circle objects (and add linecaps to the line objects) to save a factor of 2.

edemaine commented 3 years ago

I changed the default pen rendering from alternating line and circle objects to just use line objects, where the lines have a stroke-endcap of round. I had experimented with this before, but didn't like how the line widths were a smoothed version of the original data (they took the average of the two incident sample points). Now I just use the second point's sample width, which delays responsiveness a tiny amount but doesn't have any smoothing.

Here's a before and after comparison. You can see that the beginning of the fast strokes (in the lower right) get thicker, but everything else looks the same.

before image

after image

This reduces the number of DOM elements by a factor of two, so should help. I'm making this post largely to document the visual difference.

edemaine commented 3 years ago

I implemented <polyline>-based drawing of pen strokes with no pressure information (all w = 1).

For fast appending to live-drawn strokes, I still use a separate DOM element for each batch of points from a pen stroke. Reloading the page will replace the entire pen stroke with a single <polyline> instead of one <polyline> per batch.

I think we can call this done for now. The remaining part, outlining a pressure-sensitive pen stroke, can be left to #30.