/*
This is required for d3 to load.
*/
/* global d3 */
import utils from '../utils/utils';
const internalArea = {
/*
This is required for d3 to load.
*/
/* global d3 */
import utils from '../utils/utils';
const internalArea = {
Builds the actual chart components with data, including the tooltips
/*
@private
@function buildChartComponents
@description Builds the actual chart components with data, including the tooltips
@returns {Object} context Chart object
*/
buildChartComponents(context) {
const tooltip = context.tooltip;
const d0 = context.area(context.data.map(() => { return { [context.xColumnName]: context.xScale.domain()[0], [context.yColumnName]: context.yScale.domain()[0] }; }));
const d1 = context.area(context.data);
const transition = (path) => {
path.transition()
.duration(1000)
.attrTween('d', internalArea.pathTween(d1, 1));
};
context.svg.append('path')
.datum(context.data)
.attr('class', 'area')
.style({
fill: context.getColors[0],
stroke: context.getColors[0],
'stroke-width': 'crispEdges',
})
.attr('d', d0)
.transition()
.call(transition, d0, d1);
const area = d3.select('.area');
area.on('mousemove', () => {
tooltip.show();
tooltip.setContent(`${context.xColumnName}: ${context.xScale.invert(d3.event.pageX - context.getMargins.left - context.getMargins.right).toLocaleString()}\
${context.yColumnName}: ${context.yScale.invert(d3.event.pageY - context.getMargins.top - context.getMargins.bottom).toFixed(3)}`);
});
area.on('mouseout', () => {
tooltip.hide();
});
return context;
},
Does the path tweening for the area chart transitions
/*
@private
@function pathTween
@description Does the path tweening for the area chart transitions
@param {String} d1 the path to be transitioned to
@param {Number} precision the precision needed for the graph
@returns {Function} function
*/
pathTween(d1, precision) {
return function worker() {
const path0 = this;
const path1 = path0.cloneNode();
const n0 = path0.getTotalLength();
const n1 = (path1.setAttribute('d', d1), path1).getTotalLength();
Uniform sampling of distance based on specified precision.
const distances = [0];
let i = 0;
const dt = precision / Math.max(n0, n1);
while (i < 1) {
distances.push(i);
i += dt;
}
distances.push(1);
Compute point-interpolators at each distance.
const points = distances.map((t) => {
const p0 = path0.getPointAtLength(t * n0);
const p1 = path1.getPointAtLength(t * n1);
return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]);
});
return (t) => {
return t < 1 ? 'M' + points.map((p) => { return p(t); }).join('L') : d1;
};
};
},
Updates the data area on chart
/*
@private
@function updateChartComponents
@description Updates the data area on chart
@param {Object} context Chart object
@returns {Object} context Chart object
*/
updateChartComponents(context) {
context.svg.select('.area')
.datum(context.data)
.attr('d', context.area);
return context;
},
Sets the columnNames for the graph
/*
@private
@function setColumnNames
@description Sets the columnNames for the graph
@param {Object} context Chart object
@returns {Object} context Chart object
*/
setColumnNames(context) {
context.xColumnName = utils.getFirstTimeColumn(context.data);
context.yColumnName = utils.getFirstLinearColumn(context.data);
return this;
},
Sets the x scale
/*
@private
@function setXScale
@description Sets the x scale
@param {Object} context Chart object
@returns {Object} context Chart object
*/
setXScale(context) {
context.setxAxisLabel = context.xColumnName;
context.xScale = d3.time.scale()
.range([0, context.getChartWidth])
.domain(d3.extent(context.data, (d) => { return d[context.xColumnName]; }));
return context;
},
Sets the y scale
/*
@private
@function setYScale
@description Sets the y scale
@param {Object} context Chart object
@returns {Object} context Chart object
*/
setYScale(context) {
context.setyAxisLabel = context.yColumnName;
context.yScale = d3.scale.linear()
.range([context.getChartHeight, 0])
.domain([0, d3.max(context.data, (d) => { return d[context.yColumnName]; })]);
return context;
},
Update chart area colors
/*
@private
@function updateColors
@description Update chart colors
@param {Object} context Chart object
@returns {Object} context Chart object
*/
updateColors(context) {
context.element.select('svg')
.select('.area')
.style({
fill: context.getColors[0],
stroke: context.getColors[0],
'stroke-width': 'crispEdges',
});
return context;
},
Create the area drawing function
/*
@private
@function buildArea
@description Create the area drawing function
@param {Object} context Chart object
@returns {Object} context Chart object
*/
buildArea(context) {
context.area = d3.svg.area()
.x((d) => { return context.xScale(d[context.getxAxisLabel]); })
.y0(context.getChartHeight)
.y1((d) => { return context.yScale(d[context.getyAxisLabel]); });
return context;
},
Adds the y axis to the chart
/*
@private
@function buildYAxis
@description Adds the y axis to the chart
@param {Object} context Chart object
@returns {Object} context Chart object
*/
buildYAxis(context) {
context.svg.append('g')
.attr('class', 'y axis')
.call(context.yAxis)
.append('text')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text(context.getyAxisLabel);
return context;
},
Convert chart data
/*
@private
@function convertData
@description Convert chart data
@param {Object} context Chart object
@returns {Object} context Chart object
*/
convertData(context) {
context.data = utils.parseTimeData(context.data, context.xColumnName, context.dateFormat);
context.data = utils.parseNumberData(context.data, context.yColumnName);
return context;
},
Updates the style on the chart
/*
@private
@function styleChart
@description Updates the style on the chart
@param {Object} context Chart object
@returns {Object} context Chart object
*/
styleChart(context) {
context.element.select('svg')
.style('font-family', context.getFontStyle)
.attr('font-size', context.getFontSize)
.append('text')
.attr('class', 'title')
.attr('x', context.getChartWidth * 0.5)
.attr('y', 20)
.text(context.getTitle);
},
};
export default internalArea;