Skip to content

Instantly share code, notes, and snippets.

@abinashpanda
Last active April 14, 2019 13:41
Show Gist options
  • Save abinashpanda/ce5a3e933f538834ba0fbba40a79be4a to your computer and use it in GitHub Desktop.
Save abinashpanda/ce5a3e933f538834ba0fbba40a79be4a to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<link
href="https://fonts.googleapis.com/css?family=Roboto"
rel="stylesheet"
/>
<script src="node_modules/chart.js/dist/Chart.js"></script>
<script src="node_modules/lodash/lodash.js"></script>
<script src="node_modules/d3/dist/d3.js"></script>
<style>
* {
box-sizing: border-box;
}
body,
html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
svg {
display: block;
}
.line {
fill: none;
stroke: #636363;
stroke-width: 1.5;
}
.focus-circle {
fill: #fff;
fill-opacity: 0.5;
stroke: blue;
}
.x-focus-line,
.y-focus-line {
stroke: blue;
stroke-dasharray: 3, 3;
}
.label-container-rect {
fill: #fff;
fill-opacity: 0.8;
stroke: #636363;
stroke-width: 1;
}
.x-label,
.y-label {
fill: #000;
font-family: Roboto;
}
</style>
</head>
<body>
<script src="./app.js"></script>
</body>
</html>
const data = _.range(1000).map((val, index) => ({
x: index / 100,
y:
index > 600
? _.round(10 + 2 * _.random(true), 2)
: _.round(3 + _.random(true), 2)
}));
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = window.innerWidth - margin.left - margin.right;
const height = window.innerHeight / 2 - margin.top - margin.bottom;
const xScale = d3.scaleLinear().range([0, width]);
const yScale = d3.scaleLinear().range([height, 0]);
xScale.domain(d3.extent(data, d => d.x));
yScale.domain(d3.extent(data, d => d.y));
const svg = d3
.select('body')
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
// Append Axes
svg
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(d3.axisBottom(xScale));
svg.append('g').call(d3.axisLeft(yScale));
// Create Line Graph
const valueline = d3
.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y));
const lineSvg = svg.append('g');
lineSvg
.append('path')
.data([data])
.attr('class', 'line')
.attr('d', valueline);
// Create Tooltip
const focus = svg.append('g').style('display', 'none');
focus
.append('line')
.attr('class', 'x-focus-line')
.attr('y1', 0)
.attr('y2', height);
focus
.append('line')
.attr('class', 'y-focus-line')
.attr('x1', width)
.attr('x2', width);
focus
.append('circle')
.attr('class', 'focus-circle')
.attr('r', 4);
const labelContainer = focus.append('g').attr('class', 'label-container');
labelContainer
.append('rect')
.attr('class', 'label-container-rect')
.attr('width', 50)
.attr('height', 50);
labelContainer
.append('text')
.attr('class', 'y-label')
.attr('dx', 8)
.attr('dy', '-.3em');
labelContainer
.append('text')
.attr('class', 'x-label')
.attr('dx', 8)
.attr('dy', '1em');
// Move mouse on focus
const bisectDate = d3.bisector(d => d.x).left;
svg
.append('rect')
.attr('width', width)
.attr('height', height)
.style('fill', 'none')
.style('pointer-events', 'all')
.on('mouseover', () => {
focus.style('display', null);
})
.on('mouseout', () => {
focus.style('display', 'none');
})
.on('mousemove', (datum, index, nodes) => {
const x0 = xScale.invert(d3.mouse(nodes[index])[0]);
const i = bisectDate(data, x0, 1);
const d0 = data[i - 1];
const d1 = data[i];
const d = x0 - d0.x > d1.x - x0 ? d1 : d0;
focus
.select('.focus-circle')
.attr('transform', `translate(${xScale(d.x)}, ${yScale(d.y)})`);
focus
.select('.label-container-rect')
.attr('transform', `translate(${xScale(d.x) + 10}, ${yScale(d.y) - 25})`);
focus
.select('text.y-label')
.attr('transform', `translate(${xScale(d.x) + 10}, ${yScale(d.y)})`)
.text(d.y);
focus
.select('text.x-label')
.attr('transform', `translate(${xScale(d.x) + 10}, ${yScale(d.y)})`)
.text(d.x);
focus
.select('.x-focus-line')
.attr('transform', `translate(${xScale(d.x)}, ${yScale(d.y)})`)
.attr('y2', height - yScale(d.y));
focus
.select('.y-focus-line')
.attr('transform', `translate(${width * -1}, ${yScale(d.y)})`)
.attr('x2', width + width);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment