D3 with Vue Reactivity
by samonela
HTML
<script src="https://cdn.rawgit.com/chrisvfritz/459a93673c5f2e362464125381e51515/raw/9e07d5bda30203dc788894cba18749a3bb44e79d/get-players.js"></script>
<script src="https://unpkg.com/d3"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app"></div>
JavaScript
var chart = new Vue({
data: {
players: getPlayers()
},
computed: {
scores: function () {
return this.players.map(function (player) {
return player.score
})
},
highestScore: function () {
return d3.max(this.scores)
},
scale: function () {
return d3.scaleLinear()
.domain(d3.extent(this.scores))
.range([100, 300])
}
}
})
var app = d3.select('#app')
function updateBars (players) {
var bars = app.selectAll('.bar')
.data(players, function (player) {
return player.name
})
// When bars enter...
bars.enter().append('div')
.attr('class', 'bar')
// Permanent styles
.style('padding-left', '10px')
.style('line-height', '30px')
.style('transition', 'width 1s')
// Styles before entering
.style('opacity', 0)
.style('transform', 'translateX(-100px)')
.transition().duration(1000)
// Styles after entering
.style('height', '30px')
.style('opacity', 1)
.style('transform', 'none')
// When bars enter and update...
bars
.text(function (player) {
return player.name
})
.style('width', function (player) {
return vm.scale(player.score) + 'px'
})
.style('background', function (player) {
return player.score === vm.highestScore
? 'orange'
: 'lightblue'
})
// When bars exit...
bars.exit()
// Have to remove the 'bar' class on exit or
// else d3 will freak out on the next tick
.attr('class', '')
.transition().duration(1000)
// Had to use '0px' here because unlike CSS,
// d3's interpolation is not smart enough
// to tween 30px to 0 (even has a string)
.style('height', '0px')
.style('opacity', 0)
.style('transform', 'translateX(-100px)')
.remove()
}
updateBars(vm.players)
vm.$watch('players', updateBars, { deep: true })