2020-02-19 07:36:11 +00:00
|
|
|
const _ = require('lodash');
|
2020-02-18 11:29:51 +00:00
|
|
|
const d3 = require('d3');
|
|
|
|
const moment = require('moment');
|
|
|
|
|
2020-02-19 07:36:11 +00:00
|
|
|
export class CdfChartD3 {
|
2020-02-18 11:29:51 +00:00
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.attrs = {
|
|
|
|
svgWidth: 400,
|
|
|
|
svgHeight: 400,
|
|
|
|
|
|
|
|
marginTop: 5,
|
|
|
|
marginBottom: 5,
|
|
|
|
marginRight: 50,
|
|
|
|
marginLeft: 5,
|
|
|
|
|
2020-02-19 07:36:11 +00:00
|
|
|
container: null,
|
2020-02-18 11:29:51 +00:00
|
|
|
minX: false,
|
|
|
|
maxX: false,
|
|
|
|
scale: 'linear',
|
2020-02-19 07:36:11 +00:00
|
|
|
timeScale: null,
|
2020-02-18 11:29:51 +00:00
|
|
|
showDistributionLines: true,
|
2020-02-20 11:08:51 +00:00
|
|
|
showDistributionYAxis: false,
|
2020-02-18 11:29:51 +00:00
|
|
|
areaColors: ['#E1E5EC', '#E1E5EC'],
|
|
|
|
logBase: 10,
|
|
|
|
verticalLine: 110,
|
|
|
|
showVerticalLine: true,
|
2020-02-20 11:08:51 +00:00
|
|
|
data: {
|
2020-02-20 13:59:29 +00:00
|
|
|
continuous: null,
|
2020-02-20 11:08:51 +00:00
|
|
|
discrete: null,
|
|
|
|
},
|
2020-02-26 07:39:57 +00:00
|
|
|
yMaxContinuousDomainFactor: 1,
|
|
|
|
yMaxDiscreteDomainFactor: 1,
|
|
|
|
options: {},
|
2020-02-18 11:29:51 +00:00
|
|
|
onHover: (e) => {
|
|
|
|
},
|
|
|
|
};
|
2020-02-20 10:15:48 +00:00
|
|
|
|
2020-02-20 07:02:39 +00:00
|
|
|
this.calc = {
|
|
|
|
chartLeftMargin: null,
|
|
|
|
chartTopMargin: null,
|
|
|
|
chartWidth: null,
|
|
|
|
chartHeight: null,
|
|
|
|
};
|
2020-02-20 06:11:01 +00:00
|
|
|
|
|
|
|
this.chart = null;
|
|
|
|
this.svg = null;
|
|
|
|
this._container = null;
|
|
|
|
|
2020-02-18 11:58:34 +00:00
|
|
|
this.formatDates = this.formatDates.bind(this);
|
2020-02-18 11:29:51 +00:00
|
|
|
}
|
|
|
|
|
2020-02-26 07:39:57 +00:00
|
|
|
set(name, value) {
|
|
|
|
_.set(this.attrs, [name], value);
|
2020-02-18 11:29:51 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
data(data) {
|
|
|
|
this.attrs.data = data;
|
2020-02-26 07:12:13 +00:00
|
|
|
this.attrs.data.continuous = data.continuous || {
|
|
|
|
xs: [],
|
|
|
|
ys: [],
|
|
|
|
};
|
|
|
|
this.attrs.data.discrete = data.discrete || {
|
|
|
|
xs: [],
|
|
|
|
ys: [],
|
|
|
|
};
|
2020-02-18 11:29:51 +00:00
|
|
|
return this;
|
|
|
|
}
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-18 11:29:51 +00:00
|
|
|
render() {
|
2020-02-20 06:11:01 +00:00
|
|
|
this._container = d3.select(this.attrs.container);
|
|
|
|
if (this._container.node() === null) {
|
2020-02-19 08:42:54 +00:00
|
|
|
console.error('Container for D3 is not defined.');
|
|
|
|
return;
|
|
|
|
}
|
2020-02-19 07:36:11 +00:00
|
|
|
// Sets the width from the DOM element.
|
2020-02-20 06:11:01 +00:00
|
|
|
const containerRect = this._container.node().getBoundingClientRect();
|
2020-02-17 21:52:21 +00:00
|
|
|
if (containerRect.width > 0) {
|
2020-02-20 06:11:01 +00:00
|
|
|
this.attrs.svgWidth = containerRect.width;
|
2020-02-17 21:52:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Calculated properties.
|
2020-02-20 06:11:01 +00:00
|
|
|
this.calc.chartLeftMargin = this.attrs.marginLeft;
|
|
|
|
this.calc.chartTopMargin = this.attrs.marginTop;
|
2020-02-26 07:12:13 +00:00
|
|
|
this.calc.chartWidth = this.attrs.svgWidth
|
|
|
|
- this.attrs.marginRight
|
|
|
|
- this.attrs.marginLeft;
|
|
|
|
this.calc.chartHeight = this.attrs.svgHeight
|
|
|
|
- this.attrs.marginBottom
|
|
|
|
- this.attrs.marginTop;
|
2020-02-20 06:11:01 +00:00
|
|
|
|
|
|
|
// Add svg.
|
|
|
|
this.svg = this._container
|
|
|
|
.createObject({ tag: 'svg', selector: 'svg-chart-container' })
|
|
|
|
.attr('width', "100%")
|
|
|
|
.attr('height', this.attrs.svgHeight)
|
|
|
|
.attr('pointer-events', 'none');
|
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// Add container "g" (empty) element.
|
2020-02-20 06:11:01 +00:00
|
|
|
this.chart = this.svg
|
|
|
|
.createObject({ tag: 'g', selector: 'chart' })
|
|
|
|
.attr(
|
|
|
|
'transform',
|
2020-02-26 07:12:13 +00:00
|
|
|
`translate(${this.calc.chartLeftMargin}, ${this.calc.chartTopMargin})`,
|
2020-02-20 06:11:01 +00:00
|
|
|
);
|
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
if (this.hasDate('continuous')) {
|
2020-02-20 10:43:39 +00:00
|
|
|
const distributionChart = this.addDistributionChart();
|
2020-02-26 07:12:13 +00:00
|
|
|
if (this.hasDate('discrete')) {
|
2020-02-20 10:43:39 +00:00
|
|
|
this.addLollipopsChart(distributionChart);
|
|
|
|
}
|
|
|
|
}
|
2020-02-20 09:34:34 +00:00
|
|
|
return this;
|
|
|
|
}
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-20 09:34:34 +00:00
|
|
|
addDistributionChart() {
|
2020-02-20 06:11:01 +00:00
|
|
|
const areaColorRange = d3.scaleOrdinal().range(this.attrs.areaColors);
|
2020-02-20 13:59:29 +00:00
|
|
|
const dataPoints = [this.getDataPoints('continuous')];
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-20 10:15:48 +00:00
|
|
|
// Boundaries.
|
2020-02-21 05:05:41 +00:00
|
|
|
const xMin = this.attrs.minX || d3.min(this.attrs.data.continuous.xs) || d3.min(this.attrs.data.discrete.xs);
|
|
|
|
const xMax = this.attrs.maxX || d3.max(this.attrs.data.continuous.xs) || d3.max(this.attrs.data.discrete.xs);
|
2020-02-20 13:59:29 +00:00
|
|
|
const yMin = d3.min(this.attrs.data.continuous.ys);
|
|
|
|
const yMax = d3.max(this.attrs.data.continuous.ys);
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// X-domains.
|
2020-02-26 07:39:57 +00:00
|
|
|
const yMaxDomainFactor = _.get(this.attrs, 'yMaxContinuousDomainFactor', 1);
|
2020-02-26 07:12:13 +00:00
|
|
|
const xMinDomain = xMin;
|
|
|
|
const xMaxDomain = xMax;
|
2020-02-26 07:39:57 +00:00
|
|
|
const yMinDomain = yMin;
|
|
|
|
const yMaxDomain = yMax * yMaxDomainFactor;
|
2020-02-26 07:12:13 +00:00
|
|
|
|
|
|
|
// X-scale.
|
|
|
|
let xScale = this.attrs.scale === 'linear'
|
|
|
|
? d3.scaleLinear()
|
|
|
|
.domain([xMinDomain, xMaxDomain])
|
|
|
|
.range([0, this.calc.chartWidth])
|
|
|
|
: d3.scaleLog()
|
2020-02-20 06:11:01 +00:00
|
|
|
.base(this.attrs.logBase)
|
2020-02-26 07:12:13 +00:00
|
|
|
.domain([xMinDomain, xMaxDomain])
|
2020-02-20 06:11:01 +00:00
|
|
|
.range([0, this.calc.chartWidth]);
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// Y-scale.
|
2020-02-20 10:33:21 +00:00
|
|
|
const yScale = d3.scaleLinear()
|
2020-02-26 07:39:57 +00:00
|
|
|
.domain([yMinDomain, yMaxDomain])
|
2020-02-20 06:11:01 +00:00
|
|
|
.range([this.calc.chartHeight, 0]);
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// X-axis.
|
2020-02-20 10:15:48 +00:00
|
|
|
let xAxis = null;
|
2020-02-19 07:36:11 +00:00
|
|
|
if (!!this.attrs.timeScale) {
|
2020-02-26 07:12:13 +00:00
|
|
|
// Calculates the projection on X-axis.
|
|
|
|
const zero = _.get(this.attrs, 'timeScale.zero', moment());
|
|
|
|
const unit = _.get(this.attrs, 'timeScale.unit', 'years');
|
2020-02-19 12:06:41 +00:00
|
|
|
const diff = Math.abs(xMax - xMin);
|
|
|
|
const left = zero.clone().add(xMin, unit);
|
|
|
|
const right = left.clone().add(diff, unit);
|
2020-02-19 07:36:11 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// X-time-scale.
|
2020-02-19 08:33:50 +00:00
|
|
|
const xScaleTime = d3.scaleTime()
|
2020-02-19 12:06:41 +00:00
|
|
|
.domain([left.toDate(), right.toDate()])
|
2020-02-19 08:33:50 +00:00
|
|
|
.nice()
|
2020-02-20 06:11:01 +00:00
|
|
|
.range([0, this.calc.chartWidth]);
|
2020-02-19 07:36:11 +00:00
|
|
|
|
2020-02-20 10:15:48 +00:00
|
|
|
xAxis = d3.axisBottom()
|
2020-02-19 08:33:50 +00:00
|
|
|
.scale(xScaleTime)
|
2020-02-19 12:06:41 +00:00
|
|
|
.ticks(this.getTimeTicksByStr(unit))
|
2020-02-18 11:58:34 +00:00
|
|
|
.tickFormat(this.formatDates);
|
|
|
|
} else {
|
2020-02-20 10:33:21 +00:00
|
|
|
xAxis = d3.axisBottom(xScale)
|
2020-02-18 11:58:34 +00:00
|
|
|
.ticks(3)
|
|
|
|
.tickFormat(d => {
|
|
|
|
if (Math.abs(d) < 1) {
|
|
|
|
return d3.format(".2")(d);
|
|
|
|
} else if (xMin > 1000 && xMax < 3000) {
|
|
|
|
// Condition which identifies years; 2019, 2020, 2021.
|
|
|
|
return d3.format(".0")(d);
|
|
|
|
} else {
|
|
|
|
const prefix = d3.formatPrefix(".0", d);
|
|
|
|
return prefix(d).replace("G", "B");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// Y-axis.
|
2020-02-20 10:33:21 +00:00
|
|
|
const yAxis = d3.axisRight(yScale);
|
2020-02-20 09:31:10 +00:00
|
|
|
|
2020-02-19 08:39:57 +00:00
|
|
|
// Objects.
|
2020-02-18 09:31:47 +00:00
|
|
|
const line = d3.line()
|
2020-02-20 10:33:21 +00:00
|
|
|
.x(d => xScale(d.x))
|
|
|
|
.y(d => yScale(d.y));
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-18 09:31:47 +00:00
|
|
|
const area = d3.area()
|
2020-02-20 10:33:21 +00:00
|
|
|
.x(d => xScale(d.x))
|
|
|
|
.y1(d => yScale(d.y))
|
2020-02-20 06:11:01 +00:00
|
|
|
.y0(this.calc.chartHeight);
|
2020-02-17 21:52:21 +00:00
|
|
|
|
|
|
|
// Add axis.
|
2020-02-26 07:12:13 +00:00
|
|
|
this.chart
|
|
|
|
.createObject({ tag: 'g', selector: 'x-axis' })
|
|
|
|
.attr('transform', `translate(0, ${this.calc.chartHeight})`)
|
2020-02-20 10:15:48 +00:00
|
|
|
.call(xAxis);
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-20 11:08:51 +00:00
|
|
|
if (this.attrs.showDistributionYAxis) {
|
2020-02-26 07:12:13 +00:00
|
|
|
this.chart
|
|
|
|
.createObject({ tag: 'g', selector: 'y-axis' })
|
2020-02-20 11:08:51 +00:00
|
|
|
.call(yAxis);
|
|
|
|
}
|
2020-02-20 09:31:10 +00:00
|
|
|
|
2020-02-17 21:52:21 +00:00
|
|
|
// Draw area.
|
2020-02-18 11:29:51 +00:00
|
|
|
this.chart
|
2020-02-19 09:53:43 +00:00
|
|
|
.createObjectsWithData({
|
2020-02-17 21:52:21 +00:00
|
|
|
tag: 'path',
|
|
|
|
selector: 'area-path',
|
2020-02-20 10:15:48 +00:00
|
|
|
data: dataPoints,
|
2020-02-17 21:52:21 +00:00
|
|
|
})
|
|
|
|
.attr('d', area)
|
2020-02-19 08:39:57 +00:00
|
|
|
.attr('fill', (d, i) => areaColorRange(i))
|
2020-02-18 09:31:47 +00:00
|
|
|
.attr('opacity', (d, i) => i === 0 ? 0.7 : 0.5);
|
2020-02-17 21:52:21 +00:00
|
|
|
|
|
|
|
// Draw line.
|
2020-02-20 06:11:01 +00:00
|
|
|
if (this.attrs.showDistributionLines) {
|
2020-02-18 11:29:51 +00:00
|
|
|
this.chart
|
2020-02-19 09:53:43 +00:00
|
|
|
.createObjectsWithData({
|
2020-02-17 21:52:21 +00:00
|
|
|
tag: 'path',
|
|
|
|
selector: 'line-path',
|
2020-02-20 10:15:48 +00:00
|
|
|
data: dataPoints,
|
2020-02-17 21:52:21 +00:00
|
|
|
})
|
|
|
|
.attr('d', line)
|
|
|
|
.attr('id', (d, i) => 'line-' + (i + 1))
|
2020-02-18 11:58:34 +00:00
|
|
|
.attr('opacity', (d, i) => i === 0 ? 0.7 : 1)
|
2020-02-17 21:52:21 +00:00
|
|
|
.attr('fill', 'none');
|
|
|
|
}
|
|
|
|
|
2020-02-20 06:11:01 +00:00
|
|
|
if (this.attrs.showVerticalLine) {
|
2020-02-18 11:29:51 +00:00
|
|
|
this.chart
|
2020-02-19 09:24:38 +00:00
|
|
|
.createObject({ tag: 'line', selector: 'v-line' })
|
2020-02-20 10:33:21 +00:00
|
|
|
.attr('x1', xScale(this.attrs.verticalLine))
|
|
|
|
.attr('x2', xScale(this.attrs.verticalLine))
|
2020-02-17 21:52:21 +00:00
|
|
|
.attr('y1', 0)
|
2020-02-20 06:11:01 +00:00
|
|
|
.attr('y2', this.calc.chartHeight)
|
2020-02-17 21:52:21 +00:00
|
|
|
.attr('stroke-width', 1.5)
|
|
|
|
.attr('stroke-dasharray', '6 6')
|
|
|
|
.attr('stroke', 'steelblue');
|
|
|
|
}
|
|
|
|
|
2020-02-20 10:15:48 +00:00
|
|
|
const hoverLine = this.chart
|
2020-02-19 09:24:38 +00:00
|
|
|
.createObject({ tag: 'line', selector: 'hover-line' })
|
2020-02-17 21:52:21 +00:00
|
|
|
.attr('x1', 0)
|
|
|
|
.attr('x2', 0)
|
|
|
|
.attr('y1', 0)
|
2020-02-20 06:11:01 +00:00
|
|
|
.attr('y2', this.calc.chartHeight)
|
2020-02-17 21:52:21 +00:00
|
|
|
.attr('opacity', 0)
|
|
|
|
.attr('stroke-width', 1.5)
|
|
|
|
.attr('stroke-dasharray', '6 6')
|
|
|
|
.attr('stroke', '#22313F');
|
|
|
|
|
|
|
|
// Add drawing rectangle.
|
2020-02-20 10:15:48 +00:00
|
|
|
{
|
|
|
|
const context = this;
|
|
|
|
|
|
|
|
function mouseover() {
|
|
|
|
const mouse = d3.mouse(this);
|
2020-02-26 07:12:13 +00:00
|
|
|
hoverLine
|
|
|
|
.attr('opacity', 1)
|
|
|
|
.attr('x1', mouse[0])
|
|
|
|
.attr('x2', mouse[0]);
|
2020-02-24 21:01:29 +00:00
|
|
|
const xValue = xScale.invert(mouse[0]);
|
2020-02-20 10:15:48 +00:00
|
|
|
context.attrs.onHover(xValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
function mouseout() {
|
2020-02-26 07:12:13 +00:00
|
|
|
hoverLine.attr('opacity', 0);
|
2020-02-20 10:15:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.chart
|
|
|
|
.createObject({ tag: 'rect', selector: 'mouse-rect' })
|
|
|
|
.attr('width', this.calc.chartWidth)
|
|
|
|
.attr('height', this.calc.chartHeight)
|
|
|
|
.attr('fill', 'transparent')
|
|
|
|
.attr('pointer-events', 'all')
|
|
|
|
.on('mouseover', mouseover)
|
|
|
|
.on('mousemove', mouseover)
|
|
|
|
.on('mouseout', mouseout);
|
|
|
|
}
|
2020-02-20 10:33:21 +00:00
|
|
|
|
|
|
|
return { xScale, yScale };
|
2020-02-20 09:34:34 +00:00
|
|
|
}
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
/**
|
|
|
|
* @param {object} distributionChart
|
|
|
|
* @param {object} distributionChart.xScale
|
|
|
|
* @param {object} distributionChart.yScale
|
|
|
|
*/
|
2020-02-20 10:33:21 +00:00
|
|
|
addLollipopsChart(distributionChart) {
|
|
|
|
const data = this.getDataPoints('discrete');
|
2020-02-20 09:34:34 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
const _yMin = d3.min(this.attrs.data.discrete.ys);
|
|
|
|
const yMax = d3.max(this.attrs.data.discrete.ys);
|
|
|
|
|
|
|
|
// X axis.
|
|
|
|
this.chart.append('g')
|
|
|
|
.attr('class', 'lollipops-x-axis')
|
|
|
|
.attr('transform', `translate(0, ${this.calc.chartHeight})`)
|
2020-02-20 10:33:21 +00:00
|
|
|
.call(d3.axisBottom(distributionChart.xScale));
|
2020-02-20 09:34:34 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// Y-domain.
|
2020-02-26 07:39:57 +00:00
|
|
|
const yMaxDomainFactor = _.get(this.attrs, 'yMaxDiscreteDomainFactor', 1);
|
2020-02-26 07:12:13 +00:00
|
|
|
const yMinDomain = 0;
|
2020-02-26 07:39:57 +00:00
|
|
|
const yMaxDomain = yMax * yMaxDomainFactor;
|
2020-02-26 07:12:13 +00:00
|
|
|
|
|
|
|
// Y-scale.
|
2020-02-20 10:33:43 +00:00
|
|
|
const yScale = d3.scaleLinear()
|
2020-02-26 07:12:13 +00:00
|
|
|
.domain([yMinDomain, yMaxDomain])
|
2020-02-20 09:34:34 +00:00
|
|
|
.range([this.calc.chartHeight, 0]);
|
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// Adds "g" for an y-axis.
|
|
|
|
this.chart.append('g')
|
|
|
|
.attr('class', 'lollipops-y-axis')
|
|
|
|
.attr('transform', `translate(${this.calc.chartWidth}, 0)`)
|
2020-02-20 10:33:43 +00:00
|
|
|
.call(d3.axisLeft(yScale));
|
2020-02-20 09:34:34 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
// Lines.
|
|
|
|
this.chart.selectAll('lollipops-line')
|
2020-02-20 09:34:34 +00:00
|
|
|
.data(data)
|
|
|
|
.enter()
|
2020-02-26 07:12:13 +00:00
|
|
|
.append('line')
|
|
|
|
.attr('class', 'lollipops-line')
|
|
|
|
.attr('x1', d => distributionChart.xScale(d.x))
|
|
|
|
.attr('x2', d => distributionChart.xScale(d.x))
|
|
|
|
.attr('y1', d => yScale(d.y))
|
|
|
|
.attr('y2', yScale(0));
|
|
|
|
|
|
|
|
// Circles.
|
|
|
|
this.chart.selectAll('lollipops-circle')
|
2020-02-20 09:34:34 +00:00
|
|
|
.data(data)
|
|
|
|
.enter()
|
2020-02-26 07:12:13 +00:00
|
|
|
.append('circle')
|
|
|
|
.attr('class', 'lollipops-circle')
|
|
|
|
.attr('cx', d => distributionChart.xScale(d.x))
|
|
|
|
.attr('cy', d => yScale(d.y))
|
|
|
|
.attr('r', '4');
|
2020-02-18 11:29:51 +00:00
|
|
|
}
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-26 07:12:13 +00:00
|
|
|
/**
|
|
|
|
* @param ts
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
2020-02-18 11:58:34 +00:00
|
|
|
formatDates(ts) {
|
2020-02-19 08:33:50 +00:00
|
|
|
return moment(ts).format("MMMM Do YYYY");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-02-19 12:06:41 +00:00
|
|
|
* @param {string} unit
|
2020-02-19 08:33:50 +00:00
|
|
|
* @returns {*}
|
|
|
|
*/
|
2020-02-19 12:06:41 +00:00
|
|
|
getTimeTicksByStr(unit) {
|
|
|
|
switch (unit) {
|
2020-02-19 08:33:50 +00:00
|
|
|
case "months":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeMonth.every(4);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "quarters":
|
|
|
|
return d3.timeMonth.every(3);
|
|
|
|
case "hours":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeHour.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "days":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeDay.every(7);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "seconds":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeSecond.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "years":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeYear.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "minutes":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeMinute.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "weeks":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeWeek.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
case "milliseconds":
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeMillisecond.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
default:
|
2020-02-20 10:57:01 +00:00
|
|
|
return d3.timeYear.every(10);
|
2020-02-19 08:33:50 +00:00
|
|
|
}
|
2020-02-18 11:58:34 +00:00
|
|
|
}
|
2020-02-20 06:11:01 +00:00
|
|
|
|
|
|
|
/**
|
2020-02-20 10:43:39 +00:00
|
|
|
* @param {name} key
|
|
|
|
* @returns {{x: number[], y: number[]}}
|
2020-02-20 06:11:01 +00:00
|
|
|
*/
|
|
|
|
getDataPoints(key) {
|
|
|
|
const dt = [];
|
2020-02-20 10:33:21 +00:00
|
|
|
const emptyShape = { xs: [], ys: [] };
|
|
|
|
const data = _.get(this.attrs.data, key, emptyShape);
|
2020-02-20 06:11:01 +00:00
|
|
|
const len = data.xs.length;
|
|
|
|
|
|
|
|
for (let i = 0; i < len; i++) {
|
|
|
|
dt.push({ x: data.xs[i], y: data.ys[i] });
|
|
|
|
}
|
|
|
|
|
|
|
|
return dt;
|
|
|
|
}
|
2020-02-20 10:43:39 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {string} key
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
hasDate(key) {
|
2020-02-26 07:12:13 +00:00
|
|
|
const xs = _.get(this.attrs, ['data', key, 'xs']);
|
|
|
|
return !!_.size(xs);
|
2020-02-20 10:43:39 +00:00
|
|
|
}
|
2020-02-18 11:29:51 +00:00
|
|
|
}
|
2020-02-17 21:52:21 +00:00
|
|
|
|
2020-02-19 08:39:57 +00:00
|
|
|
/**
|
2020-02-19 09:24:38 +00:00
|
|
|
* @docs: https://github.com/d3/d3-selection
|
2020-02-20 10:43:39 +00:00
|
|
|
* @param {object} params
|
|
|
|
* @param {string} params.selector
|
|
|
|
* @param {string} params.tag
|
2020-02-19 08:39:57 +00:00
|
|
|
* @returns {*}
|
|
|
|
*/
|
2020-02-19 09:24:38 +00:00
|
|
|
d3.selection.prototype.createObject = function createObject(params) {
|
2020-02-19 05:20:54 +00:00
|
|
|
const selector = params.selector;
|
2020-02-19 09:53:43 +00:00
|
|
|
const tag = params.tag;
|
|
|
|
return this.insert(tag).attr('class', selector);
|
2020-02-19 09:24:38 +00:00
|
|
|
};
|
2020-02-19 05:20:54 +00:00
|
|
|
|
2020-02-19 09:24:38 +00:00
|
|
|
/**
|
|
|
|
* @docs: https://github.com/d3/d3-selection
|
2020-02-20 10:43:39 +00:00
|
|
|
* @param {object} params
|
|
|
|
* @param {string} params.selector
|
|
|
|
* @param {string} params.tag
|
|
|
|
* @param {*[]} params.data
|
2020-02-19 09:24:38 +00:00
|
|
|
* @returns {*}
|
|
|
|
*/
|
2020-02-19 09:53:43 +00:00
|
|
|
d3.selection.prototype.createObjectsWithData = function createObjectsWithData(params) {
|
2020-02-19 09:24:38 +00:00
|
|
|
const selector = params.selector;
|
2020-02-19 09:53:43 +00:00
|
|
|
const tag = params.tag;
|
2020-02-19 09:24:38 +00:00
|
|
|
const data = params.data;
|
2020-02-19 05:20:54 +00:00
|
|
|
|
2020-02-19 09:24:38 +00:00
|
|
|
return this.selectAll('.' + selector)
|
|
|
|
.data(data)
|
2020-02-19 05:20:54 +00:00
|
|
|
.enter()
|
2020-02-19 09:53:43 +00:00
|
|
|
.insert(tag)
|
2020-02-19 05:20:54 +00:00
|
|
|
.attr('class', selector);
|
|
|
|
};
|