Open bubblechartsordeath opened 7 years ago
@bubblechartsordeath - I know this is over a year old, but did you ever figure out a solution for this?
I think I'll need to directly use d3 for my force graph if I can't modify the tick listener.
Hi @simon-lang, I ended up going with the custom d3.timer (the 3rd approach I listed in my original post). It works fine until your chart is completely filled with nodes. At that point, the resistance between the nodes mixed with the "auto correction" of the custom d3 timer causes the nodes around the border to do a very jittery dance that's tough to look at.
I have the following code within my "on-ready" callback that I registered with the nvd3 directive. The "chartData" and "options" objects are the values that I set in the "data" and "options" nvd3 directive attributes. I believe "radius" is a value that I had manually set on each node. In my case the nodes had a dynamic size but you may be able to get away with a constant if that's not the case for you.
//create d3 timer for keeping nodes within visible chart
d3.timer(function() {
if (this.options.chart.width && this.options.chart.height) {
_.forEach(this.chartData.nodes, (d) => {
d.x = Math.max(d.radius, Math.min(this.options.chart.width - d.radius, d.x));
d.y = Math.max(d.radius, Math.min(this.options.chart.height - d.radius, d.y));
d.px = Math.max(d.radius, Math.min(this.options.chart.width - d.radius, d.px));
d.py = Math.max(d.radius, Math.min(this.options.chart.height - d.radius, d.py));
});
}
}.bind(this));
This is great @bubblechartsordeath , thanks for taking the time!
I'd like to create a force directed graph in which the nodes can't move out of the viewport. I understand that this can be achieved by modifying the tick listener function to keep the x and y values within a certain range like in this example. However, I'd like to do this without modifying the nvd3 source code in my workspace. Does anyone know of a way to provide our own tick listener for this chart type?
I've tried the following:
Add a "tick" listener to the angular-nvd3 chart dispatch options. It appears that "renderEnd" is the only exposed listener for the forceDirectedGraph type so this did not work (although I may be missing something as I do not completely understand the dispatch event mechanism).
I dug through the values exposed by the chart api attribute (getElement(), getScope(), etc) hoping to find the d3.layout.force object created by the nvd3 code. I thought if I could find that force object then I could provide my "on tick" function. It doesn't appear that a reference to the force object is available.
I noticed that d3.timer is used to call the force chart's tick function repeatedly. I passed my own callback to d3.timer which iterates through my dataset and makes the necessary modifications to x and y (using min/max as in the example linked above). This means my callback is running alongside the nvd3 tick listener. This WORKS but I have concerns about the performance of running this logic on every interval. I think it would be cleaner to do this in one customized tick listener.
Thanks for any help/suggestions you can give!