a ES2015 fork of @micahstubbs‘ bl.ock X-Value Mouseover with Droplines
this example also converts all CSS styles previously inside of the <style></style>
HTML tags into inline styles applied in Javascript to d3 selections.
this CSS that styles the droplines:
.focus line {
fill: none;
stroke: black;
stroke-width: 1.5px;
stroke-dasharray: 3 3;
}
becomes this Javascript that does the same thing:
d3.selectAll('.focus line')
.style({
fill: 'none',
'stroke': 'black',
'stroke-width': '1.5px',
'stroke-dasharray': '3 3'
})
inline styles can make it easier to quickly include d3js examples like this into a larger Javascript project that is automatically built from many source files into one bundle file.
<!DOCTYPE html>
<meta charset='utf-8'>
<body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js'></script>
<script src='https://npmcdn.com/babel-core@5.8.34/browser.min.js'></script>
<script lang='babel' type='text/babel'>
const margin = { top: 20, right: 50, bottom: 30, left: 50 };
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
const parseDate = d3.time.format('%d-%b-%y').parse;
const bisectDate = d3.bisector(d => d.date).left;
const formatValue = d3.format(',.2f');
const formatCurrency = d => `$${formatValue(d)}`;
d3.select('body')
.style('font', '10px sans-serif')
const x = d3.time.scale()
.range([0, width]);
const y = d3.scale.linear()
.range([height, 0]);
const xAxis = d3.svg.axis()
.scale(x)
.orient('bottom');
const yAxis = d3.svg.axis()
.scale(y)
.orient('left');
const line = d3.svg.line()
.x(d => x(d.date))
.y(d => y(d.close));
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})`);
d3.tsv('data.tsv', (error, data) => {
if (error) throw error;
data.forEach(d => {
d.date = parseDate(d.date);
d.close = +d.close;
});
data.sort((a, b) => a.date - b.date);
x.domain([data[0].date, data[data.length - 1].date]);
y.domain(d3.extent(data, d => d.close));
svg.append('g')
.attr('class', 'x axis')
.attr('transform', `translate(0, ${height})`)
.call(xAxis);
svg.append('g')
.attr('class', 'y axis')
.call(yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Price ($)');
// style the axes
d3.selectAll('.axis path')
.style({
fill: 'none',
stroke: '#000',
'shape-rendering': 'crispEdges'
})
d3.selectAll('.axis line')
.style({
fill: 'none',
stroke: '#000',
'shape-rendering': 'crispEdges'
})
d3.selectAll('.x.axis path')
.style('display', 'none');
svg.append('path')
.datum(data)
.attr('class', 'line')
.attr('d', line);
const focus = svg.append('g')
.attr('class', 'focus')
.style('display', 'none');
focus.append('circle')
.attr('r', 4.5);
focus.append('line')
.classed('x', true);
focus.append('line')
.classed('y', true);
focus.append('text')
.attr('x', 9)
.attr('dy', '.35em');
svg.append('rect')
.attr('class', 'overlay')
.attr('width', width)
.attr('height', height)
.on('mouseover', () => focus.style('display', null))
.on('mouseout', () => focus.style('display', 'none'))
.on('mousemove', mousemove);
d3.selectAll('.line')
.style({
fill: 'none',
stroke: 'steelblue',
'stroke-width': '1.5px'
});
d3.selectAll('.overlay')
.style({
fill: 'none',
'pointer-events': 'all'
});
d3.selectAll('.focus')
.style('opacity', 0.7);
d3.selectAll('.focus circle')
.style({
fill: 'none',
stroke: 'black'
})
d3.selectAll('.focus line')
.style({
fill: 'none',
'stroke': 'black',
'stroke-width': '1.5px',
'stroke-dasharray': '3 3'
})
function mousemove() {
const x0 = x.invert(d3.mouse(this)[0]);
const i = bisectDate(data, x0, 1);
const d0 = data[i - 1];
const d1 = data[i];
const d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr('transform', `translate(${x(d.date)}, ${y(d.close)})`);
focus.select('line.x')
.attr('x1', 0)
.attr('x2', -x(d.date))
.attr('y1', 0)
.attr('y2', 0);
focus.select('line.y')
.attr('x1', 0)
.attr('x2', 0)
.attr('y1', 0)
.attr('y2', height - y(d.close));
focus.select('text').text(formatCurrency(d.close));
}
});
</script>