I noticed the Control Flow section in the D3 API and tried to apply those on my code. My final goal is to avoid any "mouseenter", "mouseleave", "click".. etc. interaction as long as the transition() is still ongoing.
The snippet displays 3 nodes which are swapping the color after an "mouseenter" event. The problem is, if I interrupt a ongoing transition with in "mouseenter" event the color changes back to white. How can I avoid such behaviour?
After my applying attempts I receive await is only valid in async functions and async generators as an error.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>D3v6 Transition Example</title>
<!-- call external d3.js framework -->
<script src="https://d3js.org/d3.v6.js"></script>
</head>
<style>
body {
background-color: rgb(220, 220, 220);
overflow: hidden;
margin: 0px;
}
.node {
stroke: white;
stroke-width: 2px;
cursor: pointer;
}
.node:hover {
stroke: red
}
.link {
fill: none;
cursor: default;
stroke: rgb(0, 0, 0);
stroke-width: 3px;
}
</style>
<body>
<svg id="svg"> </svg>
<script>
var graph = {
"nodes": [
{
"id": 0,
},
{
"id": 1,
},
{
"id": 2,
}
],
"links": [
{
"source": 0,
"target": 1,
},
{
"source": 1,
"target": 2,
},
{
"source": 2,
"target": 0,
}
]
}
var width = window.innerWidth
var height = window.innerHeight
var svg = d3.select("svg")
.attr("class", "canvas")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.append("g")
// remove zoom on dblclick listener
d3.select("svg").on("dblclick.zoom", null)
var linkContainer = svg.append("g").attr("class", "linkContainer")
var nodeContainer = svg.append("g").attr("class", "nodeContainer")
var isRed = false;
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}).distance(100))
.force("charge", d3.forceManyBody().strength(-500))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(50))
initialize()
function initialize() {
link = linkContainer.selectAll(".link")
.data(graph.links)
.join("line")
.attr("class", "link")
node = nodeContainer.selectAll(".node")
.data(graph.nodes, d => d.id)
.join("g")
.attr("class", "node")
node.selectAll("circle")
.data(d => [d])
.join("circle")
.attr("r", 30)
.style("fill", "whitesmoke")
.on("mouseenter", mouseEnter)
node.selectAll("text")
.data(d=> [d])
.join("text")
.style("class", "icon")
.attr("font-family", "FontAwesome")
.attr("dominant-baseline", "central")
.attr("text-anchor", "middle")
.attr("font-size", 30)
.attr("fill", "black")
.attr("stroke-width", "0px")
.attr("pointer-events", "none")
.text((d) => {
return d.id
})
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation
.force("link")
.links(graph.links)
}
function mouseEnter(d) {
if (!isRed) {
d3.select(this)
.transition()
.duration(1500)
.style("fill", "red")
isRed = true
} else {
d3.select(this)
.transition()
.duration(1500)
.style("fill", "whitesmoke")
isRed = false
}
}
function ticked() {
// update link positions
link
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
// update node positions
node
.attr("transform", function (d) {
return "translate(" + d.x + ", " + d.y + ")";
});
}
</script>
</body>
</html>