Skip to content

Instantly share code, notes, and snippets.

@jwickens
Created March 18, 2017 16:56
Show Gist options
  • Save jwickens/0c4082c9724c552efef86a45b4f6d087 to your computer and use it in GitHub Desktop.
Save jwickens/0c4082c9724c552efef86a45b4f6d087 to your computer and use it in GitHub Desktop.
Vue.js + D3 Force

An example of force-directed D3 with Vue.js, based on two gists @JMStewart for comparability:

Vue.js is by far a lot slower than its counterparts. There are probably techniques that could be used to speed things up. In fact this is what I tried with using force.stop() on the beforeUpdate hook and its companion on the updated hook. However, this did not noticably speed up the simulation compared to just running force.start() at the beginning.

Even though Vue.js batch applies updates through an asycnronous queue and I am stopping and starting simulation updates between Vue.js updates, the Vue.js updates still slow down the simulation.

With more work the two could probably be brought more in sync, but with so much work what's the point?

For me this means that there is no point mixing D3 with another library in the same component.

However if you want to see an example that works you can see an article @johnnynotsolucky wrote: Composing D3 Visualizations With Vue.js

Open the console to see performance logs.

<!DOCTYPE html>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.11.0/react.min.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="container">
<svg v-bind:width="width" v-bind:height="height">
<g>
<circle v-for="point in points"
:cx="point.x"
:cy="point.y"
:r="point.r"
fill="steelblue">
</circle>
</g>
</svg>
</div>
<script>
var size = 1000;
var height = 500;
var width = 960;
var charge = -0.3;
var points = d3.range(size).map(function(){
return {
r: Math.floor(Math.random() * 8 + 2),
};
});
var start = new Date();
var time = 0;
var ticks = 0;
var force = d3.layout.force()
.size([width, height])
.nodes(points)
.charge(function(d){
return d.r * d.r * charge;
})
var renderStart = new Date();
force.start();
var app = new Vue({
el: '#container',
data: {
height: height,
width: width,
points
},
beforeUpdate: function() {
renderStart = new Date();
force.stop();
},
updated: function() {
time += (new Date() - renderStart);
if (ticks > 298) {
var totalTime = new Date() - start;
console.log('Total Time:', totalTime);
console.log('Render Time:', time);
console.log('Ticks:', ticks);
console.log('Average Time:', totalTime / ticks);
} else {
force.start();
}
}
});
force.on('tick', function () {
ticks++;
})
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment