Hi,
I’m currently experimenting with d3-graphviz, and have copied the demo at d3-graphviz/demo.html at master · magjac/d3-graphviz · GitHub using that transitions mechanism. The following is a simple example of what I’m doing:
let graphviz = d3.select("#graph").graphviz()
const dots = [
'digraph { a }',
'digraph { a->b }',
'digraph { a->b->c }',
]
let dotIndex = 0;
const render = function() {
var dot = dots[dotIndex];
graphviz
.renderDot(dot)
.on("end", function () {
dotIndex++
if (dotIndex < dots.length) {
render()
}
})
}
graphviz
.transition(function () {
return d3.transition("main")
.ease(d3.easeLinear)
.delay(5000)
.duration(500)
})
.on("initEnd", render)
The problem is that nothing happens for the first ‘delay’ seconds, whereas I would like the ‘a’ node to appear immediately, with the delay only affecting the later items. Is is possible to adjust the transition on a per-node basis?
As a bonus, is there a way to have aplay/pause button so that the user can start and stop the transition, and/or forward/back buttons to manually control things instead of automatic movement?
Thanks!
magjac
December 19, 2020, 4:22pm
2
This easiest way to do it perhaps to make the delay conditional based on the dotIndex
like so:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="../node_modules/d3/dist/d3.js"></script>
<script src="../node_modules/@hpcc-js/wasm/dist/index.js" type="javascript/worker"></script>
<script src="../build/d3-graphviz.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>
let graphviz = d3.select("#graph").graphviz();
const dots = [
'digraph { a }',
'digraph { a->b }',
'digraph { a->b->c }',
]
let dotIndex = 0;
const render = function() {
var dot = dots[dotIndex];
graphviz
.renderDot(dot)
.on("end", function () {
dotIndex++
if (dotIndex < dots.length) {
render()
}
})
}
graphviz
.transition(function () {
return d3.transition("main")
.ease(d3.easeLinear)
.delay(dotIndex == 0 ? 0 : 5000)
.duration(500)
})
.on("initEnd", render)
</script>
Ahh, that’s great - I hadn’t twigged that since the transition is returning a function that it could have different oparameters for each render! I’ll have a play around with this approach (I could also create a matching array that holds duration/delay values for each graph if needed).
I’ll have a play with also using this to toggle a play/pause state variable from a button, and then use that to affect transitions.
Many thanks!
1 Like
So for info, I realised that I was approaching this the ‘wrong way round’ by trying to work out how to ‘interrupt’ the automatic transitioning.
Instead I have refactored the code to move forward/back between graphs using buttons which call a function to increment or decrement ‘dotIndex’.
I then use a ‘play/pause’ button to set up or destroy a setInterval
function that calls the ‘move’ function every X seconds.
The relevant functions are as follows:
// Move forward/backward through graphs
// 0 = start, '' = end
const move = function(val) {
if (!val) {
// Empty val, move to end
dotIndex = dots.length - 1
} else if (val == 0) {
// 0 val - move to start
dotIndex = 0
} else {
let newIndex = dotIndex + val
if (newIndex >= 0 && newIndex < dots.length) {
dotIndex = newIndex
}
}
render()
}
let timer = false
const playPause = function() {
if (!timer) {
// Move immediately, then every 3 seconds
move(1)
timer = setInterval(() => move(1), 3000)
} else {
clearInterval(timer)
timer = false
}
}
1 Like
Jabeen
June 20, 2022, 12:48pm
5
Can you share a sample code please?