Hacker News new | ask | show | jobs
by kevsim 2705 days ago
I think a description of why canvas was used would be nice in the README. My (probably naive) view is that browsers are pretty good at table-ish layouts so it’d be great to know why canvas was chosen.
7 comments

> My (probably naive) view is that browsers are pretty good at table-ish layouts so it’d be great to know why canvas was chosen.

The browser certainly makes this convenient... until you have more than a few thousand cells. At some point even just having the whole table loaded into the DOM is too layout and memory intensive (except on servo, sometimes).

When you try, then, to work around those limitations, continuing to use the DOM for it becomes impractical. This gets especially difficult with a spreadsheet, where row and column size is user defined, and thus a scroll offset is a sum of all of those sizes.

I've done this several times, so I eventually settled on a bucketed, run-length encoded cache of row and column sizes, but keeping this data structure current was a mess. The mess further escalated since eventually I worked on an application where the row and column sizes could change in a different chunk with a network update, and that would need to be reconciled somehow.

You don’t have to render 1000s of table cells. You only render the visible cells and replace the content when scrolling.
Tables are also extremely performant in internet explorer, where table rendering is gpu accelerated.
Yes, if you can determine the natural height of every preceding row, the position of the next cell is a vector reduction of the previous heights. You still run in to memory limitations though (unless they've produced some incredible magical compaction scheme which can extract hidden classes from DOM structures, which I can't imagine happened without my knowing it since last I looked at tables in IE [spring 2017]).
good
I've tried to do what OP did more than a couple times using native HTML tables (for the same reason you suggest) and I've found it to be nearly impossible. Trying to force a table to keep columns one specific width and not jump around every time you change one of the cells is somewhere between an exercise in futility and not worth the pain. I think OP went the right way here.
What about CSS grid? I did a very basic one https://caub.github.io/misc/sheet without resizable columns, but I believe it'd work more easily than with tables
If by table-ish layouts you mean using the <table> element to render something like this then browsers might be OK at it but the <table> woefully inadequate to do anything more than the most basic table renderings. Virtual scrolling or frozen rows/columns is a lot of manual work to do on top of a <table>.
Plus I crashed safari on an ipad with a simple page with a table of a few tens thousand rows.
In my experience, 10K+ rows could even crash a desktop browser.
You make a lot of trade-offs by picking either Canvas or the DOM to render your web app. If you do pick the DOM you will probably abstract out all the DOM operations anyway. But if you pick the Canvas you have to implement everything yourself. With DOM you can do very nice stuff using CSS. The browser (DOM) comes with everything you need "out of the box", but interacting with the DOM, and make it do stuff that are not specified - it will be very "hacky", and you have to deal with different browsers (mobile browsers) working differently.
Every DOM cell is a very large object with thousands of properties (most of which a spreadsheet will never use). A cell in a spreadsheet contains a handful of properties and immediate render works much better for less complex layouts (VS Code moved from DOM to Canvas in the terminal because layout performance was better with much less complexity).

Another big reason is wasm. It would be a big performance increase to write the layout engine in Rust/wasm. Native performance would be great.

1 canvas performance is higher than dom rendering

2 easy to write code

github.com/xspreadsheet used table

Dom gives you a lot more though. Hit testing and events, css text alignment and wrapping.

In general, unless you are doing something very simple, replicating the dom and css engine with canvas is an uphill battle.

That being said, I love that the xterm terminal uses a canvas renderer and now going to move to a webgl renderer. Terminal like UI with monospaced fonts are an excellent candidate for low level rendering.

How is canvas rendering performance higher than dom rendering when you’re rendering boxes and text...
All DOM update and layout algorithms are O(N) complex (at best). So as less DOM elements you have as more responsive your UI is.

As an ultimate solution - to remove DOM at all and replace it by <canvas>. Minimization of updates is developer's business in this case. Presumably he/she will be able to do it better other than to walk through all DOM elements while handling, say this:

   html:hover span { color:red; }
You only need as many DOM nodes as it takes to cover the viewport.

You can style them such a way that updates do not cause re-layout, except for auto-sized cells.