Reputation: 70
I am trying to modify the color of some nodes in the force layout using a color picker.
I haven't found any examples of how to modify the elements within the force layout without the events being triggered within/by those elements.
This example is updating the layout with buttons, but is only changing the data that is passed, and then updating the graph. The data I am using contains a "group" which determines the color, which is defined in the JS. Therefore updating the data is not an option, however updating the variable doesn't work either.
This question asks about updating forces/attributes of the simulation itself rather than its elements and the solution here did not work for me as reheating the simulation does not pick up the changed colors.
var cp = document.getElementById("useCasePicker");
cp.value = useCaseColor;
cp.addEventListener("change", updateColor, false);
function updateColor(event)
{
useCaseColor = event.target.value;
update();
}
This is what I've tried to do (with update() function redrawing the graph with any new inputs) but the nodes that already exist, which I want to change, are skipped over as they already exist.
I also tried doing it this way (where node is the <g>
element containing all circles) -
node.selectAll("circle").style("fill", useCaseColor);
This also did not work for changing the color -
node.selectAll("circle").remove();
label.selectAll("text").remove();
update();
I'm guessing I could do something like a newColor
flag that the event sets, and when that is true, trigger an event off the nodes themselves somehow, but I assume there is a better way to do it.
This is how the nodes are defined in the update()
function.
node = node.data(config.nodes, d => d.id);
node.exit().remove();
node = node.enter().append("circle")
.attr("class", "node")
.attr("r", function (d) {
switch(d.group)
{
case "use case":
return useCaseRad;
case "data service":
return dataServRad;
case "source":
return sourceRad;
}
})
.attr("fill", function (d) {
switch(d.group)
{
case "use case":
return useCaseColor;
case "data service":
return dataServColor;
case "source":
return sourceColor;
}
})
.attr("stroke", "black")
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended))
.on("mouseover", mouseOver)
.on("mouseout", mouseOut)
.merge(node);
I can provide more of the code if need be but I know everything with the graph works fine, I just want to be able to update the color without having to destroy the whole graph and re-draw it.
Upvotes: 0
Views: 112
Reputation: 219
You don't have to destroy the graph - simply put your fill method call after merge.
.merge(data)
.attr("fill", function (d) {
switch(d.group) {
case "use case":
return useCaseColor;
case "data service":
return dataServColor;
case "source":
return sourceColor;
}
})
merge allows you to work with both initial & enter selections, so you can update it correctly.
Upvotes: 1