Skip to content

Instantly share code, notes, and snippets.

@zemirco
Created June 6, 2018 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zemirco/ef5dc3ae80b538e1034442c17c44237f to your computer and use it in GitHub Desktop.
Save zemirco/ef5dc3ae80b538e1034442c17c44237f to your computer and use it in GitHub Desktop.
d3 update
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>
<svg id="svg"></svg>
<button id="update">update</button>
<button id="reset">reset</button>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
const defaults = {
target: '#chart',
width: 640,
height: 480,
margin: {
top: 20,
right: 20,
bottom: 30,
left: 40
}
}
class LineChart {
constructor(config) {
Object.assign(this, defaults, config)
this.init()
}
init() {
const {target, width, height, margin} = this
const w = width - margin.left - margin.right
const h = height - margin.top - margin.bottom
this.svg = d3.select(target)
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
this.xScale = d3.scalePoint()
.range([0, w])
this.yScale = d3.scaleLinear()
.range([h, 0])
this.xAxis = d3.axisBottom(this.xScale)
this.svg
.append('g')
.attr('class', 'x axis')
.attr('transform', `translate(0, ${h})`)
.call(this.xAxis)
this.yAxis = d3.axisLeft(this.yScale)
this.svg
.append('g')
.attr('class', 'y axis')
.call(this.yAxis)
}
render(data) {
const {xScale, yScale, xAxis, yAxis, svg} = this
xScale.domain(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'])
svg.select('.x.axis')
.call(xAxis)
yScale.domain([0, 10])
svg.select('.y.axis')
.call(yAxis)
svg
.selectAll('.dot')
.data(data, d => d.key)
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', d => xScale(d.key))
.attr('cy', d => yScale(d.value))
.attr('r', 10)
}
update(data) {
const {svg, xScale, yScale} = this
// join new data with old elements
const selection = svg
.selectAll('.dot')
.data(data, d => d.key)
// update old elements
selection
.transition()
.attr('cx', d => xScale(d.key))
.attr('cy', d => yScale(d.value))
// add new elements
selection.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', d => xScale(d.key))
.attr('cy', d => yScale(d.value))
.attr('r', 0)
.transition()
.attr('r', 10)
.attr('fill', 'orange')
// remove old elements
selection.exit()
.transition()
.attr('r', 0)
.attr('fill', 'red')
.remove()
}
}
// draw chart
let chart
const draw = () => {
const config = {
target: 'svg',
width: document.body.clientWidth
}
chart = new LineChart(config)
const data = [
{key: 'a', value: 1},
{key: 'b', value: 0},
{key: 'c', value: 3},
{key: 'd', value: 2},
{key: 'e', value: 5},
{key: 'f', value: 4},
{key: 'g', value: 7},
{key: 'h', value: 6},
{key: 'i', value: 9},
{key: 'j', value: 8}
]
chart.render(data)
}
draw()
// update button
const button = document.getElementById('update')
button.addEventListener('click', () => {
const data = [
// remove a
// {key: 'a', value: 1},
// update b, c, d, e, f, g, h, i, j
{key: 'b', value: 1},
{key: 'c', value: 4},
{key: 'd', value: 3},
{key: 'e', value: 6},
{key: 'f', value: 3},
{key: 'g', value: 6},
{key: 'h', value: 7},
{key: 'i', value: 3},
{key: 'j', value: 4},
// add k
{key: 'k', value: 9}
]
chart.update(data)
})
// reset button
const reset = document.getElementById('reset')
reset.addEventListener('click', () => {
document.getElementById('svg').firstChild.remove()
draw()
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment