I would recommend to make the transition directly controllable, so that a user can set it to any intermediate offset. Happy to take a stab at it, if you're interested in this change.
Thanks for your suggestion. I did something like that for my 'The Hague Morphing Transit Map' notebook. There I've defined one global `t` and all the intermediate values are calculated everytime the slider input is dragged but I was wondering if there's a better way to control a d3 transition with an input in Observable
Here's what I'm thinking: While we could use d3.interpolate directly, we'd miss out on the nice abstraction / wrapping of start and end value that d3.transition offers us. On the other hand, we cannot (easily) replace its internal timer. What we *can* do however, is to set an infinite duration and custom easing:
// make sure to stop any running transitions - untested
invalidation.then(() => selection.interrupt());
// Given an input t, return its value without triggering a rerender.
// Elements are updated on each frame via transition anyway.
selection.transition().duration(Infinity).ease(() => viewof t.value)
If instead we wanted to create a static render based on t, we'd be better off to use d3.interpolate directly, e.g.:
selection.attr("fill", d3.interpolate("transparent", "yellow")(t))
There are also some very ugly ways to access the internal attribute tweens via __transition, but the way they need to be applied requires replicating some internal d3-transition code (although not much). At that point a generic interpolation helper, called e.g. via .call or .each, will likely be the cleaner choice.
Thanks for your detailed response, I think I'll look into using d3-interpolate directly for a static render, the other options seem too hard for me but feel free to make a suggestion if you'd like.