A couple of days ago we were looking for the datasheets for the various sensors installed in the MX3D bridge: as you’ve probably already read, there are nearly a hundred sensors in and on the bridge, although of only about eight different model types. My colleague Josh Cameron said, in passing, “it would be really handy to have these datasheets integrated into Dasher!”.
As usual, this sent me down a rather fun rabbit-hole for a day or so, to see how we might reasonably integrate these PDFs into Dasher. Firstly it’s worth pointing out that these days the Forge viewer is itself a really capable PDF view and markup tool. But I didn’t want the overhead of going through Forge, as the needs for the datasheets are pretty simple: we want to be able to show a simple preview of the datasheet when (for instance) hovering over a sensor, and to open the PDF inside the browser – in a new tab or window, depending on the user preference – when it’s clicked. The latter piece is super-simple to implement: it’s really a matter of deciding how to specify the datasheets for sensors, and were to place links in the UI that can download and open the PDF(s).
The definition piece ended up being reasonably straightforward: in our JSON settings it’s now possible to specify a default datasheet for a particular sensor type, but also override this for individual sensors. For example, as there are three types of strain gauge on the bridge, it made sense to set the default strain gauge datasheet to be the most commonly used one, and then have sensors of the two less common models be over-ridden on a sensor-by-sensor basis. Fair enough.
For the UX, initially I imagined having this driven somehow by the sensor dots, but Josh made the suggestion to add an information button into the Sensor List UI for each sensor with a datasheet available. This definitely made life easier from a development perspective, but also seems to be a reasonable UX, as far as things go.
In terms of how this was implemented, I decided to go client-side for the PDF rendering. There’s a handy library from Mozilla called PDF.js (not to be confused with this one), which can download and render a PDF’s pages asynchronously. My original approach was to download and render the PDF every time a sensor’s '”i” was hovered over in the list, but realised this was sub-optimal. You can see the delay – and some strange visual artefacts – here:
I decided to add a cache, so that previously rendered PDFs would get reused. I did this by taking a hash of the URL and using a simple list of hashes to know which index into my DOM-based cache of canvases to take. When a known PDF is needed for rendering, we copy their contents from the rendered canvas into the one belonging to the tooltip, which then gets displayed using Tooltipster.
This worked well enough, but there was still an initial delay when a new PDF was downloaded and rendered, which sometimes caused issues with the tooltip display. As we only have eight different datasheets for the bridge, I then decided to download and render them as the model is loading, so that the cache is always pre-populated “just in case” rather than “just in time”. This leads to the experience being super-smooth as you hover over the various sensors:
Depending on your needs you might want to do this differently: we only want the first page of a PDF as a thumbnail, so you might prefer to pre-render these thumbnails and store the images on the server, or to have a service that generates thumbnails for a given PDF… the client-side approach probably only makes sense if dealing with a relatively small set of (small) PDFs. But anyway – as a first pass I thought it worth pointing out the techniques that I used to implement it.