OLD | NEW |
| (Empty) |
1 // | |
2 // Copyright 2014 Google Inc. All rights reserved. | |
3 // | |
4 // Use of this source code is governed by a BSD-style | |
5 // license that can be found in the LICENSE file or at | |
6 // https://developers.google.com/open-source/licenses/bsd | |
7 // | |
8 | |
9 part of charted.charts; | |
10 | |
11 /// A behavior that draws marking lines on the chart. | |
12 class LineMarker implements ChartBehavior { | |
13 /// Position of the line markers. | |
14 final Map<int,dynamic> positions; | |
15 | |
16 /// If true, the markers are drawn above the series | |
17 final bool drawAboveSeries; | |
18 | |
19 /// If true, animates (grows from the axis into the chart) | |
20 final bool animate; | |
21 | |
22 CartesianArea _area; | |
23 bool _isLeftAxisPrimary = false; | |
24 Rect _rect; | |
25 | |
26 bool _showing; | |
27 Selection _parent; | |
28 DataSelection _markers; | |
29 | |
30 StreamSubscription _axesChangeSubscription; | |
31 | |
32 LineMarker(this.positions, | |
33 {this.drawAboveSeries: false, this.animate: false}); | |
34 | |
35 void init(ChartArea area, Selection upper, Selection lower) { | |
36 if (area is! CartesianArea) return; | |
37 _area = area; | |
38 _parent = drawAboveSeries ? upper : lower; | |
39 _isLeftAxisPrimary = _area.config.isLeftAxisPrimary; | |
40 _axesChangeSubscription = | |
41 _area.onChartAxesUpdated.listen((_) => _update()); | |
42 _update(); | |
43 } | |
44 | |
45 void dispose() { | |
46 if (_axesChangeSubscription != null) _axesChangeSubscription.cancel(); | |
47 if (_markers != null) _markers.remove(); | |
48 } | |
49 | |
50 bool _isDimension(int column) => _area.config.dimensions.contains(column); | |
51 | |
52 String _pathForDimension(int column, bool initial) { | |
53 assert(_isDimension(column)); | |
54 | |
55 int index; | |
56 for(index = 0; | |
57 _area.config.dimensions.elementAt(index) != column; ++index); | |
58 | |
59 assert(index == 0 || index == 1 && _area.useTwoDimensionAxes); | |
60 | |
61 var dimensionAtBottom = | |
62 index == 1 && _isLeftAxisPrimary || | |
63 index == 0 && !_isLeftAxisPrimary, | |
64 scale = _area.dimensionScales.elementAt(index), | |
65 scaled = scale.scale(positions[column]), | |
66 theme = _area.theme.getDimensionAxisTheme(), | |
67 renderAreaRect = _area.layout.renderArea, | |
68 left = renderAreaRect.x, | |
69 right = initial ? left : (left + renderAreaRect.width), | |
70 bottom = renderAreaRect.y + renderAreaRect.height, | |
71 top = initial ? bottom : renderAreaRect.y; | |
72 | |
73 if (scale is OrdinalScale) { | |
74 var band = scale.rangeBand, | |
75 bandPadding = theme.axisBandInnerPadding; | |
76 scaled = scaled - band * bandPadding + _area.theme.defaultStrokeWidth; | |
77 band = band + 2 * (band * bandPadding - _area.theme.defaultStrokeWidth); | |
78 return dimensionAtBottom | |
79 ? 'M ${left + scaled} ${bottom} V ${top} H ${left + scaled + band} V $
{bottom} Z' | |
80 : 'M ${left} ${scaled + band} H ${right} V ${scaled - band} H ${left}
Z'; | |
81 } else { | |
82 return dimensionAtBottom | |
83 ? 'M ${left + scaled} ${bottom} V ${top}' | |
84 : 'M ${left} ${scaled} H ${right}'; | |
85 } | |
86 } | |
87 | |
88 String _pathForMeasure(int column, bool initial) { | |
89 throw new UnimplementedError('Measure axis markers'); | |
90 } | |
91 | |
92 String _getMarkerPath(int column, bool initial) => | |
93 _isDimension(column) | |
94 ? _pathForDimension(column, initial) | |
95 : _pathForMeasure(column, initial); | |
96 | |
97 void _update() { | |
98 if (!_area.isReady) return; | |
99 _markers = _parent.selectAll('.line-marker').data(positions.keys); | |
100 | |
101 _markers.enter.append('path').each((d, i, e) { | |
102 e.classes.add('line-marker'); | |
103 e.attributes['d'] = _getMarkerPath(d, animate); | |
104 }); | |
105 | |
106 if (animate) { | |
107 _markers.transition() | |
108 .attrWithCallback('d', (d, i, e) => _getMarkerPath(d, false)); | |
109 } | |
110 | |
111 _markers.exit.remove(); | |
112 } | |
113 } | |
114 | |
OLD | NEW |