-
Notifications
You must be signed in to change notification settings - Fork 16
/
AreaChartImpls.js
122 lines (92 loc) · 2.78 KB
/
AreaChartImpls.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import D3Component from '../charts/D3Component';
import d3 from 'd3';
import Axis from '../charts/common/Axis';
export default class AreaChartImpls extends D3Component {
willMount() {
let {xAccessor, yAccessor, xScale, yScale, interpolate} = this.props;
if (this.props.xaxis) {
this.setAxis(new Axis(this.props.xaxis, this.props.xScale));
}
if (this.props.yaxis) {
this.setAxis(new Axis(this.props.yaxis, this.props.yScale));
}
this.points = [];
this.areaGenerator = d3.svg.area()
.interpolate(interpolate)
.x(d => xScale(xAccessor(d)))
.y0(d => yScale(0))
.y1(d => yScale(yAccessor(d)));
}
onMount() {
super.onMount();
this.baseLayer = this.base.append('g').classed('area-layer', true);
this._render();
}
getClosestDataIndex(pt) {
if (!this.points.length) return null;
let {data, xAccessor} = this.props;
this.points.forEach((d) => {
d.d = Math.abs(d.x - pt);
});
this.points.sort((a,b) => {return d3.ascending(a.d, b.d);});
return this.points[0].i;
}
onMouseMoveHandler() {
if (!this.hover || !this.tooltip) return;
const mx = d3.mouse(this.baseLayer.node());
const inverted = this.props.xScale.invert(mx[0]);
const itemIdx = this.getClosestDataIndex(mx[0]);
this.tooltip.setPosition(d3.event);
if (itemIdx !== null) this.tooltip.setContent(this.props.data[0][itemIdx]);
}
preRender() {
let {data, xScale, yScale, interpolate, xAccessor, yAccessor} = this.props;
xScale.range([0, this.width]);
yScale.range([this.height, 0]);
this.updateAxis(0, xScale, this.props.xaxis);
this.updateAxis(1, yScale, this.props.yaxis);
this.areaGenerator
.interpolate(interpolate)
.x(d => xScale(xAccessor(d)))
.y0(d => yScale(0))
.y1(d => yScale(yAccessor(d)));
this.points = [];
if (data.length) {
data[0].forEach((d,i) => {
const x = xScale(xAccessor(d));
this.points.push({x:x, i: i});
});
}
}
render() {
let {data, xAccessor, yAccessor, xScale, yScale, fillColor, fillOpacity} = this.props;
const area = this.baseLayer.selectAll('path.area').data(data);
area.exit().remove();
area.enter()
.append('path')
.attr('class', 'area');
area
.attr('d', d => this.areaGenerator(d))
.style('fill', fillColor)
.style('opacity', fillOpacity);
}
postRender() {
if (this.props.interactive) {
this.baseLayer.selectAll('path.area')
.on('mouseover', this.onOver.bind(this))
.on('mouseout', this.onOut.bind(this));
}
}
onOver() {
this.hover = true;
if (this.tooltip) {
this.tooltip.show();
}
}
onOut() {
this.hover = false;
if (this.tooltip) {
this.tooltip.hide();
}
}
}