I'm currently trying to consume an Restful-Api call and use the infromation, to make an d3.js force-simulation. The problem is that if I use the data from an API, call the simulation handles it if there was nothing. If I wait for the next tick this.$nextTick(simu)
all positions end up as an NaN
. Is there a reason for this behaviour?
const URL = 'https://jsonplaceholder.typicode.com/posts';
new Vue({
el: '#app',
data() {
return {
webGraph: {
nodes: [],
edges: []
},
graph1: {
nodes:[
{url:2},
{url:3},
],
edges:[
{source:2, target:3},
]
}
}
},
created() {
axios.get(URL).then((response) => {
let node1 = {
url: response.data[1].id
}
let node2 = {
url: response.data[2].id
}
let edge = {
source: {url:response.data[1].id},
target: {url:response.data[2].id}
}
this.webGraph.nodes.push(node1)
this.webGraph.nodes.push(node2)
this.webGraph.edges.push(edge)
})
d3.forceSimulation(this.webGraph.nodes)
.force("charge", d3.forceManyBody().strength(-25))
.force("link", d3.forceLink().id(d => d.url).links(this.webGraph.edges))
.on('end', function() {
console.log("done")
});
d3.forceSimulation(this.graph1.nodes)
.force("charge", d3.forceManyBody().strength(-25))
.force("link", d3.forceLink().id(d => d.url).links(this.graph1.edges))
.on('end', function() {
console.log("done")
});
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h6>{{webGraph}}</h6>
<br>
<h6>{{graph1}}</h6>
</div>
CodePudding user response:
The reason why webGraph
and graphData1
have different outcomes, is that the simulation of webGraph
is started before it has data. If you move the simulation
code inside inside the axios.get().then
, then you'll see it works as you'd expect.
const URL = 'https://jsonplaceholder.typicode.com/posts';
new Vue({
el: '#app',
data() {
return {
webGraph: {
nodes: [],
edges: []
},
graph1: {
nodes:[
{url:2},
{url:3},
],
edges:[
{source:2, target:3},
]
}
}
},
created() {
axios.get(URL).then((response) => {
let node1 = {
url: response.data[1].id
}
let node2 = {
url: response.data[2].id
}
let edge = {
source: node1,
target: node2
}
this.webGraph = {
nodes: [node1, node2],
edges: [edge]
};
d3.forceSimulation(this.webGraph.nodes)
.force("charge", d3.forceManyBody().strength(-25))
.force("link", d3.forceLink().id(d => d.url).links(this.webGraph.edges))
.on('end', function() {
console.log("done")
});
})
d3.forceSimulation(this.graph1.nodes)
.force("charge", d3.forceManyBody().strength(-25))
.force("link", d3.forceLink().id(d => d.url).links(this.graph1.edges))
.on('end', function() {
console.log("done")
});
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h6>{{webGraph}}</h6>
<br>
<h6>{{graph1}}</h6>
</div>
In your code, I also changed the initialization of edge
. It showed that you need to look at the difference between variables and references.
With let edge = { source: {url:response.data[1].id}, target: {url:response.data[2].id} }
, if node1
changes, edge.source
does not. So edge.source
will not know where to point to. With let edge = { source: node1, target: node2 }
, the code is not only shorter, but if node1
changes, edge.source
is always up to date.