interpolated-charts
Version:
Configurable d3 v4 charts with interpolation and missing data range
199 lines (163 loc) • 4.57 kB
JavaScript
import * as d3 from 'd3';
function tooltip({
chartHeight = 440, chartWidth = 700, tooltipWidth = 220,
horizontalMouseMargin = 40, verticalBorderMargin = 10,
headerFormatter = selectedDate => d3.timeFormat('%Y-%d-%m %H:%M:%S')(selectedDate),
topicFormatter = data => data.name,
valueFormatter = data => d3.format('.1f')(data.interpolatedValue),
sort = () => 0
} = {}) {
let svg;
function exports(selection) {
selection.each(function() {
buildSvg(this);
});
}
function buildSvg(container) {
if (!svg) {
svg = d3.select(container)
.append('g')
.classed('tooltip-container', true);
}
}
exports.remove = function() {
svg
.select('.tooltip')
.remove();
return this;
};
exports.show = function({ x, y, selectedDate, data }) {
exports.remove();
svg
.append('g')
.classed('tooltip', true)
.append('rect')
.attr('width', tooltipWidth);
const foreignObject = svg
.select('.tooltip')
.append('foreignObject')
.classed('foreign-object', true)
.attr('width', tooltipWidth);
const { divHeight } = createToltipDiv(foreignObject, selectedDate, data);
svg
.select('.tooltip foreignObject')
.attr('height', divHeight);
svg
.select('.tooltip rect')
.attr('height', divHeight);
const xPosition = x > chartWidth / 2 ?
x - tooltipWidth - horizontalMouseMargin :
x + horizontalMouseMargin;
const yPosition = y + divHeight > chartHeight - verticalBorderMargin ?
chartHeight - divHeight - verticalBorderMargin :
y;
svg
.select('.tooltip')
.attr('transform', `translate(${xPosition}, ${yPosition})`);
return this;
};
function createToltipDiv(container, selectedDate, data) {
const div = container
.append('xhtml:div')
.append('div')
.classed('tooltip-container', true);
div
.append('div')
.classed('tooltip-header', true)
.append('p')
.html(headerFormatter(selectedDate, data));
div
.append('hr');
const topics = div
.selectAll('.topic')
.data(data.slice().sort(sort))
.enter()
.append('div')
.classed('topic', true);
topics
.append('div')
.classed('circle', true)
.style('background-color', d => d.color);
topics
.append('div')
.classed('topic-name', true)
.html(d => topicFormatter(d));
topics
.append('div')
.classed('topic-value', true)
.html(d => valueFormatter(d));
const divHeight = div
.node()
.getBoundingClientRect()
.height;
return {
div,
divHeight
};
}
exports.chartHeight = function(_chartHeight) {
if (!arguments.length) {
return chartHeight;
}
chartHeight = _chartHeight;
return this;
};
exports.chartWidth = function(_chartWidth) {
if (!arguments.length) {
return chartWidth;
}
chartWidth = _chartWidth;
return this;
};
exports.tooltipWidth = function(_tooltipWidth) {
if (!arguments.length) {
return tooltipWidth;
}
tooltipWidth = _tooltipWidth;
return this;
};
exports.horizontalMouseMargin = function(_horizontalMouseMargin) {
if (!arguments.length) {
return horizontalMouseMargin;
}
horizontalMouseMargin = _horizontalMouseMargin;
return this;
};
exports.verticalBorderMargin = function(_verticalBorderMargin) {
if (!arguments.length) {
return verticalBorderMargin;
}
verticalBorderMargin = _verticalBorderMargin;
return this;
};
exports.headerFormatter = function(_headerFormatter) {
if (!arguments.length) {
return headerFormatter;
}
headerFormatter = _headerFormatter;
return this;
};
exports.topicFormatter = function(_topicFormatter) {
if (!arguments.length) {
return topicFormatter;
}
topicFormatter = _topicFormatter;
return this;
};
exports.valueFormatter = function(_valueFormatter) {
if (!arguments.length) {
return valueFormatter;
}
valueFormatter = _valueFormatter;
return this;
};
exports.sort = function(_sort) {
if (!arguments.length) {
return sort;
}
sort = _sort;
return this;
};
return exports;
}
export default tooltip;