[HN Gopher] Easy SVG sparklines ___________________________________________________________________ Easy SVG sparklines Author : alexpls Score : 296 points Date : 2023-07-10 10:59 UTC (12 hours ago) (HTM) web link (alexplescan.com) (TXT) w3m dump (alexplescan.com) | Lockal wrote: | But SVG is slower than Canvas. The main use case for sparklines | is embedding them into cells, many hundreds or even thousands of | them [1]. With hundreds of SVG files page becomes becomes visibly | slower (first paint, scroll, interactions). I suggest to invest | some time and check canvas solution too. | | [1]: https://www.google.com/search?q=sparkline&tbm=isch | dspillett wrote: | If pure client-side performance is key, and you can afford a | little extra bandwidth, then go a little further and pre-draw | server-side and transfer as date:uri images. Then you are not | relying on JS running on the client to draw on the canvases. | Not an option if you need things drawn more dynamically client- | side, in response to user changes/filters/etc without a server | round-trip, of course. | | Though in any case if you have thousands of sparklines in cells | I'd question if the display is actually useful to anyone. | | Unless it is a large table of data you are presenting in which | case thousands of rows has display time issues in my experience | anyway. I have in mind a CSV preview on one of our support | dashboards which takes a noticeable time to render when given a | client import of ~8,000 rows and ~15 columns and that is not a | lot more than a plain HTML table. | lazyjeff wrote: | There's an open source project I was briefly involved in called | SSVG [1] that renders the SVG as Canvas to speed it up | drastically, especially on Chrome. It works as a simple one- | line js drop in for many common visualization examples [2]. | | [1] https://ssvg.io/ [2] https://ssvg.io/examples | xyzzy_plugh wrote: | Of course SVG is slower than Canvas. SVG is fundamentally much | more powerful. Canvas is just a pixel buffer. You know what's | even faster than Canvas? JPEG. | | Of course these tools have different use cases. Handling | scaling events and interactivity with Canvas is far, far more | laborious. | | The great thing about SVG (and to a lesser extent JPEGs) is | that you can produce them anywhere, not just in a browser with | a JavaScript VM. | XCSme wrote: | > You know what's even faster than Canvas? JPEG | | Is that true? Isn't canvas a bitmap whereas JPEG requires | decoding? | jancsika wrote: | What's the fastest way to deliver the bitmap to the canvas? | XCSme wrote: | Hardcode the RGB array? | thehappypm wrote: | Hard to imagine that pure-HTML SVG is really slower than Canvas | which relies on JS.. | TeMPOraL wrote: | Especially if we're talking using "many hundreds or even | thousands of them" on a page. | klysm wrote: | Canvas is faster _because_ it relies on JS. It's a much | dumber and stateful API - the browser has to do much less | work. | fuzzy2 wrote: | Ah, but Canvas does _not_ rely on JS. You would _update_ it | using JS, yes. When you don't update it, it's just another | image. Browsers are quite good at images. | | In the end, I think it's down to the complexity of the graph | and the dimensions (in pixels, because images need memory, | too). | thehappypm wrote: | How do you draw an image on a canvas without JS? | fuzzy2 wrote: | You don't. My point is: After drawing, the canvas is | "inert". Rendering to the canvas once is probably more or | less as expensive as rendering the SVG once. However, the | SVG will probably be rendered a lot more than once. The | page developer cannot control it either, the browser | decides what's best. | Lockal wrote: | It is, it is! SVG is DOM, with event handling on every node, | with attempts to apply CSS rules. Canvas for non-interactive | charts is just "draw once and forget". It is a sequence of | moveTo + lineTo, then you have a bitmap and nothing else. | Extremely basic graphics, modern JS engines will handle it in | the blink of an eye. | | I don't even mention the fact that article suggests to return | each SVG sparkline in a separate request. | thehappypm wrote: | Guess it depends on your definition of performance. | zagrebian wrote: | In that case, browsers should optimize SVG more. | klysm wrote: | SVG could never be as fast as canvas. | llm_nerd wrote: | SVG is a series of drawing commands (with transformations, | filters, and so on). Which is exactly what canvas is. With | appropriate layer caching of course it can be 100% as fast | if the rudiments are similar and in the same context[1], | and on many platforms it is. Chromium derivatives have a | particularly slow implementation of SVG and it has tainted | the whole realm. | | [1] Obviously if you're zooming and transforming and | animating layers there is going to be a cost, but that | should be compared with doing the same with a canvas. | klysm wrote: | Canvas is just a pixel buffer. Even with sufficient | caching SVG would be slower because there's more work to | do with parsing, etc. | llm_nerd wrote: | Canvas is a pixel buffer... _and_ a set of drawing | rudiments to imperatively actually make that pixel buffer | useful. If you were actually just using canvas as a pixel | buffer it would be catastrophically slow. | | SVG is a pixel buffer and a set of drawing rudiments to | imperatively _or_ declaratively actually make that pixel | buffer useful. | | The distinction you are drawing between these is | sophistry. | postalrat wrote: | SVG is a pixel buffer the same way html is a pixel | buffer. It can have multiple types of animations, hover | states, etc. | klysm wrote: | No the distinction is important and directly related to | performance. Supporting the canvas API requires fewer CPU | instructions to get to pixels on the screen. The browser | has to do a lot more work to turn SVG into pixels | drewcoo wrote: | > The main use case for sparklines is embedding them into cells | | Says who? Citation? | tripflag wrote: | This is only an issue on chrome-based browsers; performance in | Firefox is much closer to what you would expect. You can/could | (late 2022) reliably crash chrome by displaying 1000+ unique | SVG files on one page, with each SVG simply displaying a single | line of text. My current workaround is rendering the SVGs to | png serverside if the client is chrome-based, as canvas feels | like the wrong solution. | dylan604 wrote: | Since the vast majority of users are a chromium based | browser, doesn't this put the burden on your server pretty | much all of the time? why even bother with code to do 2 | different things when the other thing is such a niche segment | of users? | tripflag wrote: | True; so the server-side rendering is tuned for minimal | server load, with the resulting output being heavily | degraded. Still good enough for its purpose, and Firefox | gets the bonus hi-res thumbnails :-) | josephcsible wrote: | This kind of thinking is how we ended up with the IE6 | disaster. | dylan604 wrote: | That's my point of having the logic to do multiple | workflows based on browser type. | wryanzimmerman wrote: | I find it hard to imagine a use-case for thousands of | sparklines on screen at the same time! And if it's not on | screen, you don't need to render it. | | Instead of using svg files, just include them in the html, and | make them simple. Each svg sparkline only needs to be two | elements (the <svg> tag and one <path>), which is crazy | efficient. | | Canvas uses one element, instead of two, but you have to create | a custom implementation of path rendering and do all that work | in JavaScript instead of native browser APIs. | | Canvas pulls ahead with drawing complex images where you have a | single pixel buffer representing thousands of individual | "shapes" because the DOM itself is optimized for interaction, | not just drawing pixels, but I think that's a different use- | case from sparklines. | esafak wrote: | A spreadsheet with numerous sparklines per row would get you | there. | umtksa wrote: | love it and tried it on node-red to add a simmple sparkline to my | dashboard | CamperBob2 wrote: | I've always thought it would be neat to use sparklines to display | trends in comment scores. You could see if a comment was | monotonically being voted up or down or if it's considered | controversial, and if so, to what extent. It would help | distinguish between bandwagon/brigading activity and genuine | organic rejection or appeal. | | And it's often interesting to see trends or cycles emerge as | people in different geographical regions wake up and log on. Some | comments play much better in the US than in Asia or the EU and | vice versa, and sparklines would be a good way to observe that. | bencevans wrote: | I've recently used this approach for generating Open Graph images | for display when a link to the site is used on Twitter, WhatsApp, | Facebook, etc [1]. I was pleasantly surprised at how quickly | something could be implemented. The last time I'd done something | similar was using Cairo and needing to write more of the scaling | dynamics. I don't think I ever got it to adjust to dynamic | content very well. This time I put together a prototype in | Inkscape, converted it to a template and render it to PNG with | Sharp [2]. | | [1]: https://hntrends.net/api/og?word=twitter [2]: | https://github.com/lovell/sharp | leeoniya wrote: | this works well when you have a few sparklines with a dozen | datapoints each, but less well when you have many sparklines with | hundreds of datapoints. | Gordonjcp wrote: | You're populating a tiny template with a tiny list of numbers | to produce a tiny plaintext document that will cache like | Scrooge McDuck. | | Why do you think this is going to be a problem? | 082349872349872 wrote: | I'd bet an SVG <path> can easily handle hundreds, if not | thousands, of datapoints. | solardev wrote: | Then you have to deal with scaling, responsiveness, data | decimation, etc. It's not really a good idea to just have a | multi thousand point line chat rendered real tiny | nkozyra wrote: | If you know what size you're dealing with it's not a huge | deal. You can quantize the data and for (small) sparklines | that's probably fine because most people view them as | miniature glimpses at data rather than granular and | accurate. | thehappypm wrote: | +1, the whole point of a sparkline is to compactly show a | trend. Packing a gazillion data points is not the right | use | solardev wrote: | Totally. I just mean that logic has to live somewhere, | whether in client-side JS or a server. It's not a great | practice to just blindly render SVGs out of raw data. | 082349872349872 wrote: | Aha, I misunderstood -- I'd thought you were thinking of | rendering multiple small SVGs. | | Good point, although decimation for sparklines shouldn't | be that difficult: I've done completely stupid decimation | (recursively split stopping whenever linear fit is close | enough) for live GPS traces and (because people are only | using them qualitatively) no one ever complained. | leeoniya wrote: | it can for sure "handle" it. the question is "how well"? | | a sparkline with 100 datapoints is very realistic. and having | a couple columns in a table with 100 rows filled with these | svg sparklines will have ui lag that you'll definitely feel. | | sadly, svg is not a great performer in these 1k+ datapoints | cases and you gotta switch to canvas. | yawnxyz wrote: | This is cool! | | For those who don't know, there's a font called Sparks that uses | glyphs to create sparklines: | https://github.com/aftertheflood/sparks | watersb wrote: | Recent HN thread on another "graphing data" font, although this | one doesn't simply map numbers to graphic, prompting a | discussion on accessibility issues to consider: | | Datalegreya Font https://news.ycombinator.com/item?id=25832196 | pmarreck wrote: | all their examples and URLs (save for the code itself on | github) _but even the font files themselves_ are dead because | that company closed in 2020 : / | | Very neat idea, though! I did find this example: | https://observablehq.com/@tomgp/sparks-with-live-data | | For those examples to work (which they still do), the URL | references to the font data in the stylesheet should ostensibly | still be valid: | https://tools.aftertheflood.com/sparks/styles/font-faces.css | watersb wrote: | Apparently, the host 'tools.aftertheflood.com' is still | mapped to GitHub Pages. | | Backing out from the CSS file (many thanks!), turns out the | top-level web page is still up -- BUT the links to download | the zip file font collections DONT WORK. | | So you still need to scrape the CSS file to get working links | to the individual fonts... _(I was going to post those URLs | here, but there are 84 of them. Use a command like this to | scrape the CSS file:)_ grep -o "http[^']*" < | sparks.css | | However, this GitHub Pages site still hosts web pages that | show some great examples and links to ObservableHQ notebooks | (which also still work, hosted at observablehq.com). | | https://tools.aftertheflood.com/ | dreadlordbone wrote: | Javascript version here: https://jsfiddle.net/buk3dsqv/ | entropie wrote: | It would be nice if you consider to put it in a jsfiddle, or | something. | dreadlordbone wrote: | Good point, updated that to a jsfiddle. | entropie wrote: | Thank you | stevekrouse wrote: | I ported your jsfiddle to run on val town! | | Main function: | https://www.val.town/v/stevekrouse.sparklineSVG | | Rendered example: | https://www.val.town/v/stevekrouse.sparklineEx2 | [deleted] | jwr wrote: | I'm going to be the Smug Lisp Weenie here (I wonder who gets the | reference), and comment on this: | | > One of my favourite things about creating sparklines like this | is that I can create the SVGs entirely on the backend. I don't | need to worry about using a JavaScript charting library, or | sending the "points" data to the frontend. The browser requests | an SVG. The server returns it. Simple! | | Me, I don't care where I create the SVGs. Most of my Clojure code | is shared between backend and frontend (compiled and running on | the JVM in the backend and compiled to JavaScript in the | frontend). So I can generate SVGs wherever, it doesn't matter, | the code is only written once. Or rather, it might matter, | because my website uses server-side rendering, so the same thing | must be generated on both sides. | | I'll see myself out now. | mighmi wrote: | What's Clojure's WASM story like? That would be much more | exciting than having to transpile to JS. | lucideer wrote: | I mean... isomorphic code isn't unique to Clojure & is how many | JS/NodeJS apps work... | javajosh wrote: | I like it! But instead of modifying your data to suit SVG's | default coordinate system, I suggest using a top-level "g" tag | with a "transform/scale" attribute. Like this: | <svg class="natural-units" width="200px" height="200px" | viewBox="-1 -1 2 2" > <desc>A static svg unit | circle</desc> <g transform="scale(1,-1)"> | <circle class='unit-circle' r="1" fill="none" stroke-width=".001 | "/> </g> | | </svg> | | Example adapted from: https://simpatico.io/svg.md#naturalunits | | In this way you can use the intuition about the coordinate system | that you built in school. | bla3 wrote: | Doesn't this flip all text in the SVG upside down? | javajosh wrote: | Alas, yes. And you have to reflip it with another g/scale. | But such is life! | ComputerGuru wrote: | A bigger problem is that it breaks text rendering. | Transforms turn off pixel snapping in the hinting engine so | you'll get blurry text or lines. | | (At least if you applied it as a css transform you would. | Maybe if you did it natively in svg you wouldn't?) | chefandy wrote: | Maybe it's just because I have so much experience with design and | visual art, but I think SVG is one of the most, if not the most | underutilized web format. It's great for the self-contained | static vector graphics that it's most commonly used for, but it | can do so much more. SMIL animations can be a little clunky, but | having an alternative to gif and video that doesn't require JS is | pretty rad-- especially for throbbers and things like that. That | you can work with SVGs so easily using JS and CSS is awesome. You | can even build your own filter stacks using its built-in | effects... though last time I did that with a detailed full- | screen art piece, performance was rough. | wbobeirne wrote: | Totally agree. I bookmarked this guide that hit the top of HN a | few weeks back, a good primer on how to get started manually | programming paths, which unlocks a lot of cool dynamic SVG and | animation opportunities: https://www.nan.fyi/svg-paths. | watersb wrote: | I try to keep my SVGs simple, and often tweak them by editing | the XML data in a text editor. (Linus Torvalds relaxes with | assembly language, I make image files smaller...) | https://www.phoronix.com/news/Linus-Torvalds-Relax-Inline- | AS... | | This simple iOS app helps me play with path changes, sort of | a unit-test use case for me: | | http://genhelp.com/apps/svgpaths.html | psygn89 wrote: | I wish <img> would accept `fill` property through css. There's | a neat trick to colorize SVG's: https://angel-rs.github.io/css- | color-filter-generator/ | chefandy wrote: | There's definitely some super clunky stuff, there. "This is | an image! no... wait... this is an embedded document! no... | hold on... it's an ima... hmm...." | | It all makes sense from a technical perspective when you dig | into it, but it's totally counterintuitive in surprising | ways, sometimes. | javajosh wrote: | _> SVG is one of the most, if not the most underutilized web | format_ | | Yes. I think the problem is that you have to learn to author | with it before you program with it, and the learning curve is | actually fairly steep. OTOH the feedback is immediate and | satisfying. | | Personally, I've ignored SVG's built-in animation capabilities | in favor of pumping DOM modifications into the scenegraph with | a (requestAnimationFrame) timer. This gives you exquisite | control requiring very little code. | | https://simpatico.io/svg.md#clocksvg | chefandy wrote: | Yeah it's great with JS, and I use it for most dynamic things | I do with SVG. I'd still stick with SMIL for little animated | icons that would be deployed multiple places and other little | problems like that. | | > Yes. I think the problem is that you have to learn to | author with it before you program with it, and the learning | curve is actually fairly steep. | | Good point. | gabereiser wrote: | +1 for requestAnimationFrame. SMIL animations are cool until | you try doing 1,000 of them. Still, I do agree that SVG is | underutilized. Not only can it do so much more but it has | effects that can be used _in conjunction with_ DOM elements. | Things like dropshadow, glow, blur, greyscale, duotone, etc. | Check out this SVG glitch effect [0] | | [0] https://codepen.io/DirkWeber/pen/YzBYWY | jjcm wrote: | I ended up hand crafting my svg graphs for non.io for many of the | same reasons. I originally was looking around at 3rd party | libraries, but one of my goals with the site was to use as few | external libraries as possible. I made an attempt at dynamically | generating the svg points myself, and found it incredibly easy. | | For context, here's the 22 lines of code it took to create a | simple svg graph: https://github.com/jjcm/soci- | frontend/blob/master/components... | | And here's the final output: https://non.io/Animation-example | nnf wrote: | Simple, data-driven graphics like this is one area where SVG | really shines, I think. No need to load a JavaScript charting | library if you just want some simple line charts like this. I | create SVG images fairly often, and maybe half the time I find | myself hand-coding them, or at least hand-tweaking them, since I | enjoy the magic of seeing code turn into something visual. | kongprofit wrote: | do you have a blog | unmole wrote: | SVGs are amazing for interactive visualisation too. Like | Flamegraphs: https://www.brendangregg.com/flamegraphs.html | antonhag wrote: | An alternative if you want a bit more help with charting, | without client side JS, is to use d3-shape | (https://github.com/d3/d3-shape) to server-side render SVGs. | drewcoo wrote: | The "unfinished" tiny line graph with no fill is actually closer | to what Tufte meant by sparklines. He meant those to be placed in | text, word-sized, along with words to help communicate better. | | https://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=... | | I feel like many people use "sparkline" to mean "pretty graph." | Those, frankly, lack the punch of a sparkline. | pictur wrote: | pretty good. can user interactive charts be prepared in this way? | mindok wrote: | Yes, but depending on the interactions it can get complex | quickly. D3.js handles all the interactions in JS on the | client. ContEx (elixir server-side charting) handles certain | events (e.g. data point click) server side (see https://contex- | charts.org/barcharts - turn on "show clicked bar" option). | Showing data point detail, e.g. "On hover" would require client | side code. | | (Disc: ContEx author) | nkozyra wrote: | Sure, but you'll need JS for anything complex. You could use | SVG+CSS to show/hide specific things like data values on | mouseover but it would be a global on/off for the whole chart. | renewiltord wrote: | Cool idea! ChatGPT-4 was able to generate something for me pretty | quick | https://chat.openai.com/share/d0e8102c-9ea5-4709-8898-b278ca... | that looks pretty similar https://jsfiddle.net/13awmx8y/ | spoiler wrote: | I've used a similar technique to implement one of the graphs for | small "header dashboard" for a trading tool at my previous job. | It was replacing an old decrepit tool and I wanted to add some | pizzaz to the tool, and had an obsession with SVG and micro | interactions at the time, so I've basically implemented most of | the little graphics using hand-emitted SVG that was manipulatied | through React. The updates happened in one batch too, so the | performance was always great | umtksa wrote: | this looks like a subject I like to read on a blog | stevekrouse wrote: | I thought it'd be fun to play with sparklines on Val Town, which | is a server-side platform for running JavaScript. | | First I did the opposite of this post and used all the libraries | (react, htm, and react-sparkline): | https://www.val.town/v/stevekrouse.sparklineEx | | Then I found a comment below that does it in vanilla js, so I | ported that over to Val Town as well: | https://www.val.town/v/stevekrouse.sparklineEx2 | [deleted] | nologic01 wrote: | SVG feels like the neglected stepchild of the web universe for | reasons that are not entirely clear. | | While its obviously not the solution to any and all | visualizations in the browser its a remarkable addition to html | and the dom. It should not really be considered a foreign format | but the natural native one. | | SVG can go a long way on its own or together with server side | templates (as this post nicely demonstrates) but imho its pairing | with js libraries such as d3 or vega is (still) out of this world | in terms of the user experience they create. | bob1029 wrote: | This is fantastic. I'm already using string interpolation & | builders for my HTML/JS/CSS source, so why not the same for SVG? | | I didn't realize the syntax was so straightforward. It looks like | you could even build the final SVG with some clever SQL queries | if all you need to do is produce a time series visual (i.e. | string aggregation over Path). | mindok wrote: | Cool explanation! I use quite a lot of SVG visualisations | generated server-side. Some basic charts (including sparkline) | are bundled up into ContEx (an elixir library) - see | https://contex-charts.org/ (disclosure - author). | alexpls wrote: | Thanks! And thanks also for your work on ContEx, its Sparkline | module [1] was a big inspiration for what I ended up | implementing. | | [1] | https://github.com/mindok/contex/blob/master/lib/chart/spark... ___________________________________________________________________ (page generated 2023-07-10 23:00 UTC)