Skip to content

Instantly share code, notes, and snippets.

@TBD
Last active February 10, 2020 17:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save TBD/600b23e56545026ae6fda2905efa42ce to your computer and use it in GitHub Desktop.
Save TBD/600b23e56545026ae6fda2905efa42ce to your computer and use it in GitHub Desktop.
timeline chart with zoom
license: mit

timeline chart with zoom

require:

  • D3.js v4
  • coffeescript

by TBD | @tbdr

(function() {
var i, j;
window.VEHICLES = [];
for (i = j = 1; j <= 15; i = ++j) {
VEHICLES.push({
tir: i,
start: new Date(+(new Date()) - Math.floor(Math.random() * 1000000000)),
end: new Date()
});
}
}).call(this);
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="http://coffeescript.org/v1/browser-compiler/coffee-script.js"></script>
<style>
.chart {
margin: 0 auto;
width: 960px;
min-height: 8px;
height: 100%;
box-shadow: 0 0 3px 1px #eee;
}
svg {
vertical-align: top;
width: 100%;
height: 100%;
}
.tooltip {
position: absolute;
}
.axis {
height: 20px;
}
.zoom {
cursor: move;
position: absolute;
top: 0;
left: 0;
fill: none;
pointer-events: all;
}
</style>
</head>
<body>
<div class="chart"></div>
<script src="data.js"></script>
<script type="text/coffeescript">
wrapper = document.querySelector '.chart'
width = wrapper.clientWidth;
parser = d3.isoParse
minX = d3.min(VEHICLES, (d) -> parser d.start)
maxX = d3.max(VEHICLES, (d) -> parser d.end)
# --- X scale
x = d3.scaleTime()
.domain([minX, maxX])
.rangeRound([0, width])
# --- nest all the data
symbols = d3.nest()
.key (d) -> d.tir
.entries(VEHICLES)
height = wrapper.getBoundingClientRect().bottom
spanX = (d) -> x(parser(d.start))
spanW = (d) -> x(parser(d.end)) - x(parser(d.start))
chart = (symbol) ->
svg = d3.select this
svg.selectAll 'rect'
.data(symbol.values)
.enter()
.append 'rect'
.attr 'x', (d) -> spanX d
.attr 'y', 0
.attr 'width', (d) -> spanW d
.attr 'height', height
.attr 'fill', (d) -> d.color or '#ddf'
.on 'mouseover', (d) ->
tooltip.html [d.tir, d.start, d.end].join('<br>')
.on 'mouseout', () ->
tooltip.html ''
# --- add all charts
allCharts = d3.select(wrapper).selectAll('svg')
.data(symbols)
.enter()
.append('svg')
.attr('height', height)
.each(chart)
# --- add X axis
xAxis = d3.axisBottom(x)
.ticks(width / 100)
globalX = d3.select(wrapper)
.append('svg')
.attr('class', 'axis')
.call(xAxis)
# --- catch all zoom svg rect
catchAll = d3.select('body')
.append 'svg'
.attr 'class', 'zoom'
.append 'rect'
.attr 'fill', 'none'
.attr 'width', width
.attr 'height', wrapper.getBoundingClientRect().bottom
# --- add tooltip
tooltip = d3.select(wrapper).append('div')
.attr 'class', 'tooltip'
catchAll.call(d3.zoom()
.scaleExtent([0.1, 10])
.on "zoom", ->
transform = d3.event.transform
globalX.call xAxis.scale(transform.rescaleX(x))
allCharts.selectAll('rect')
.attr 'x', (d) -> transform.applyX spanX d
.attr 'width', (d) -> transform.k * spanW d
)
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment