[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)