OLD | NEW |
1 // | 1 // |
2 // Copyright 2014 Google Inc. All rights reserved. | 2 // Copyright 2014 Google Inc. All rights reserved. |
3 // | 3 // |
4 // Use of this source code is governed by a BSD-style | 4 // Use of this source code is governed by a BSD-style |
5 // license that can be found in the LICENSE file or at | 5 // license that can be found in the LICENSE file or at |
6 // https://developers.google.com/open-source/licenses/bsd | 6 // https://developers.google.com/open-source/licenses/bsd |
7 // | 7 // |
8 | 8 |
9 part of charted.charts; | 9 part of charted.charts; |
10 | 10 |
11 class DefaultChartAxisImpl { | 11 class DefaultChartAxisImpl { |
| 12 static const int _AXIS_TITLE_HEIGHT = 20; |
| 13 |
12 CartesianArea _area; | 14 CartesianArea _area; |
13 ChartAxisConfig _config; | 15 ChartAxisConfig config; |
14 ChartAxisTheme _theme; | 16 ChartAxisTheme _theme; |
15 SvgAxisTicks _axisTicksPlacement; | 17 SvgAxisTicks _axisTicksPlacement; |
16 | 18 |
17 int _column; | 19 int _column; |
18 bool _isDimension; | 20 bool _isDimension; |
19 ChartColumnSpec _columnSpec; | 21 ChartColumnSpec _columnSpec; |
20 | 22 |
21 bool _isVertical; | 23 bool _isVertical; |
22 String _orientation; | 24 String _orientation; |
23 Scale _scale; | 25 Scale _scale; |
24 SelectionScope _scope; | 26 SelectionScope _scope; |
| 27 String _title; |
25 | 28 |
26 MutableRect size; | 29 MutableRect size; |
27 | 30 |
28 DefaultChartAxisImpl.withAxisConfig(this._area, this._config); | 31 DefaultChartAxisImpl.withAxisConfig(this._area, this.config); |
29 DefaultChartAxisImpl(this._area); | 32 DefaultChartAxisImpl(this._area); |
30 | 33 |
31 void initAxisDomain(int column, bool isDimension, Iterable domain) { | 34 void initAxisDomain(int column, bool isDimension, Iterable domain) { |
32 _columnSpec = _area.data.columns.elementAt(column); | 35 _columnSpec = _area.data.columns.elementAt(column); |
33 _column = column; | 36 _column = column; |
34 _isDimension = isDimension; | 37 _isDimension = isDimension; |
35 | 38 |
36 // If we don't have a scale yet, create one. | 39 // If we don't have a scale yet, create one. |
37 if (scale == null) { | 40 if (scale == null) { |
38 _scale = _columnSpec.createDefaultScale(); | 41 _scale = _columnSpec.createDefaultScale(); |
39 } | 42 } |
40 | 43 |
41 // We have the scale, get theme. | 44 // We have the scale, get theme. |
42 _theme = isDimension | 45 _theme = isDimension |
43 ? _area.theme.getDimensionAxisTheme(scale) | 46 ? _area.theme.getDimensionAxisTheme(scale) |
44 : _area.theme.getMeasureAxisTheme(scale); | 47 : _area.theme.getMeasureAxisTheme(scale); |
45 | 48 |
46 // Sets the domain if not using a custom scale. | 49 // Sets the domain if not using a custom scale. |
47 if (_config == null || (_config != null && _config.scale == null)) { | 50 if (config == null || (config != null && config.scale == null)) { |
48 scale.domain = domain; | 51 scale.domain = domain; |
49 scale.nice = !_isDimension; | 52 scale.nice = !_isDimension && |
| 53 !(config?.forcedTicksCount != null && config.forcedTicksCount > 0); |
50 } | 54 } |
| 55 |
| 56 _title = config?.title; |
51 } | 57 } |
52 | 58 |
53 void initAxisScale(Iterable range) { | 59 void initAxisScale(Iterable range) { |
54 assert(scale != null); | 60 assert(scale != null); |
55 if (scale is OrdinalScale) { | 61 if (scale is OrdinalScale) { |
56 var usingBands = _area.dimensionsUsingBands.contains(_column), | 62 var usingBands = _area.dimensionsUsingBands.contains(_column), |
57 innerPadding = usingBands ? _theme.axisBandInnerPadding : 1.0, | 63 innerPadding = usingBands ? _theme.axisBandInnerPadding : 1.0, |
58 outerPadding = | 64 outerPadding = |
59 usingBands ? _theme.axisBandOuterPadding : _theme.axisOuterPadding; | 65 usingBands ? _theme.axisBandOuterPadding : _theme.axisOuterPadding; |
60 | 66 |
61 // This is because when left axis is primary the first data row should | 67 // This is because when left axis is primary the first data row should |
62 // appear on top of the y-axis instead of on bottom. | 68 // appear on top of the y-axis instead of on bottom. |
63 if (_area.config.isLeftAxisPrimary) { | 69 if (_area.config.isLeftAxisPrimary) { |
64 range = range.toList().reversed; | 70 range = range.toList().reversed; |
65 } | 71 } |
66 (scale as OrdinalScale) | 72 if (usingBands) { |
67 .rangeRoundBands(range, innerPadding, outerPadding); | 73 (scale as OrdinalScale) |
| 74 .rangeRoundBands(range, innerPadding, outerPadding); |
| 75 } else { |
| 76 (scale as OrdinalScale).rangePoints(range, outerPadding); |
| 77 } |
68 } else { | 78 } else { |
69 scale.range = range; | 79 if (_title != null) { |
| 80 var modifiedRange = range.take(range.length - 1).toList(); |
| 81 modifiedRange.add(range.last + _AXIS_TITLE_HEIGHT); |
| 82 scale.range = modifiedRange; |
| 83 } else { |
| 84 scale.range = range; |
| 85 } |
70 scale.ticksCount = _theme.axisTickCount; | 86 scale.ticksCount = _theme.axisTickCount; |
71 } | 87 } |
72 } | 88 } |
73 | 89 |
74 void prepareToDraw(String orientation) { | 90 void prepareToDraw(String orientation) { |
75 if (orientation == null) orientation = ORIENTATION_BOTTOM; | 91 if (orientation == null) orientation = ORIENTATION_BOTTOM; |
76 _orientation = orientation; | 92 _orientation = orientation; |
77 _isVertical = | 93 _isVertical = |
78 _orientation == ORIENTATION_LEFT || _orientation == ORIENTATION_RIGHT; | 94 _orientation == ORIENTATION_LEFT || _orientation == ORIENTATION_RIGHT; |
79 | 95 |
80 var layout = _area.layout.chartArea; | 96 var layout = _area.layout.chartArea; |
81 size = _isVertical | 97 size = _isVertical |
82 ? new MutableRect.size(_theme.verticalAxisWidth, layout.width) | 98 ? new MutableRect.size(_theme.verticalAxisWidth, layout.width) |
83 : new MutableRect.size(layout.height, _theme.horizontalAxisHeight); | 99 : new MutableRect.size(layout.height, _theme.horizontalAxisHeight); |
84 | 100 |
| 101 if (config?.forcedTicksCount != null && config.forcedTicksCount > 0) { |
| 102 scale.forcedTicksCount = config.forcedTicksCount; |
| 103 } |
| 104 |
85 // Handle auto re-sizing of horizontal axis. | 105 // Handle auto re-sizing of horizontal axis. |
86 var ticks = (_config != null && !isNullOrEmpty(_config.tickValues)) | 106 var ticks = (config != null && !isNullOrEmpty(config.tickValues)) |
87 ? _config.tickValues | 107 ? config.tickValues |
88 : scale.ticks, | 108 : scale.ticks, |
| 109 |
89 formatter = _columnSpec.formatter == null | 110 formatter = _columnSpec.formatter == null |
90 ? scale.createTickFormatter() | 111 ? scale.createTickFormatter() |
91 : _columnSpec.formatter, | 112 : _columnSpec.formatter, |
92 textMetrics = new TextMetrics(fontStyle: _theme.ticksFont), | 113 textMetrics = new TextMetrics(fontStyle: _theme.ticksFont), |
93 formattedTicks = ticks.map((x) => formatter(x)).toList(), | 114 formattedTicks = ticks.map((x) => formatter(x)).toList(), |
94 shortenedTicks = formattedTicks; | 115 shortenedTicks = formattedTicks; |
95 if (_isVertical) { | 116 if (_isVertical) { |
96 var width = textMetrics.getLongestTextWidth(formattedTicks).ceil(); | 117 var width = textMetrics.getLongestTextWidth(formattedTicks).ceil(); |
97 if (width > _theme.verticalAxisWidth) { | 118 if (width > _theme.verticalAxisWidth) { |
98 width = _theme.verticalAxisWidth; | 119 width = _theme.verticalAxisWidth; |
(...skipping 25 matching lines...) Expand all Loading... |
124 void draw(Element element, SelectionScope scope, {bool preRender: false}) { | 145 void draw(Element element, SelectionScope scope, {bool preRender: false}) { |
125 assert(element != null && element is GElement); | 146 assert(element != null && element is GElement); |
126 assert(scale != null); | 147 assert(scale != null); |
127 | 148 |
128 var rect = _area.layout.axes[_orientation], | 149 var rect = _area.layout.axes[_orientation], |
129 renderAreaRect = _area.layout.renderArea, | 150 renderAreaRect = _area.layout.renderArea, |
130 range = _isVertical ? [rect.height, 0] : [0, rect.width], | 151 range = _isVertical ? [rect.height, 0] : [0, rect.width], |
131 innerTickSize = _theme.axisTickSize <= ChartAxisTheme.FILL_RENDER_AREA | 152 innerTickSize = _theme.axisTickSize <= ChartAxisTheme.FILL_RENDER_AREA |
132 ? 0 - (_isVertical ? renderAreaRect.width : renderAreaRect.height) | 153 ? 0 - (_isVertical ? renderAreaRect.width : renderAreaRect.height) |
133 : _theme.axisTickSize, | 154 : _theme.axisTickSize, |
134 tickValues = _config != null && !isNullOrEmpty(_config.tickValues) | 155 tickValues = config != null && !isNullOrEmpty(config.tickValues) |
135 ? _config.tickValues | 156 ? config.tickValues |
136 : null; | 157 : null; |
137 | 158 |
138 element.attributes['transform'] = 'translate(${rect.x}, ${rect.y})'; | 159 element.attributes['transform'] = 'translate(${rect.x}, ${rect.y})'; |
139 | 160 |
140 if (!_isVertical) { | 161 if (!_isVertical) { |
141 _axisTicksPlacement = new RotateHorizontalAxisTicks( | 162 _axisTicksPlacement = new RotateHorizontalAxisTicks( |
142 rect, _theme.ticksFont, _theme.axisTickSize + _theme.axisTickPadding); | 163 rect, _theme.ticksFont, _theme.axisTickSize + _theme.axisTickPadding); |
143 } | 164 } |
| 165 initAxisScale(range); |
144 | 166 |
145 initAxisScale(range); | 167 if (_title != null) { |
| 168 var label = element.querySelector('.chart-axis-label'); |
| 169 if (label != null) { |
| 170 label.text = _title; |
| 171 } else { |
| 172 var title = Namespace.createChildElement('text', element); |
| 173 title.attributes['text-anchor'] = 'middle'; |
| 174 title.text = _title; |
| 175 title.classes.add('chart-axis-label'); |
| 176 element.append(title); |
| 177 } |
| 178 } |
| 179 |
146 var axis = new SvgAxis( | 180 var axis = new SvgAxis( |
147 orientation: _orientation, | 181 orientation: _orientation, |
148 innerTickSize: innerTickSize, | 182 innerTickSize: innerTickSize, |
149 outerTickSize: 0, | 183 outerTickSize: 0, |
150 tickPadding: _theme.axisTickPadding, | 184 tickPadding: _theme.axisTickPadding, |
151 tickFormat: _columnSpec.formatter, | 185 tickFormat: _columnSpec.formatter, |
152 tickValues: tickValues, | 186 tickValues: tickValues, |
153 scale: scale); | 187 scale: scale); |
154 | 188 |
155 axis.create(element, scope, | 189 axis.create(element, scope, |
156 axisTicksBuilder: _axisTicksPlacement, isRTL: _area.config.isRTL); | 190 axisTicksBuilder: _axisTicksPlacement, isRTL: _area.config.isRTL); |
157 } | 191 } |
158 | 192 |
159 void clear() {} | 193 void clear() {} |
160 | 194 |
161 // Scale passed through configuration takes precedence | 195 // Scale passed through configuration takes precedence |
162 Scale get scale => | 196 Scale get scale => |
163 (_config != null && _config.scale != null) ? _config.scale : _scale; | 197 (config != null && config.scale != null) ? config.scale : _scale; |
164 | 198 |
165 set scale(Scale value) { | 199 set scale(Scale value) { |
166 _scale = value; | 200 _scale = value; |
167 } | 201 } |
| 202 |
168 } | 203 } |
169 | 204 |
170 class PrecomputedAxisTicks implements SvgAxisTicks { | 205 class PrecomputedAxisTicks implements SvgAxisTicks { |
171 final int rotation = 0; | 206 final int rotation = 0; |
172 final Iterable ticks; | 207 final Iterable ticks; |
173 final Iterable formattedTicks; | 208 final Iterable formattedTicks; |
174 final Iterable shortenedTicks; | 209 final Iterable shortenedTicks; |
175 const PrecomputedAxisTicks( | 210 const PrecomputedAxisTicks( |
176 this.ticks, this.formattedTicks, this.shortenedTicks); | 211 this.ticks, this.formattedTicks, this.shortenedTicks); |
177 void init(SvgAxis axis) {} | 212 void init(SvgAxis axis) {} |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 // Check if we have enough space to render full chart | 249 // Check if we have enough space to render full chart |
215 allowedWidth = (1.4142 * (rectHeight)) - (textMetrics.fontSize / 1.4142); | 250 allowedWidth = (1.4142 * (rectHeight)) - (textMetrics.fontSize / 1.4142); |
216 if (maxLabelWidth > allowedWidth) { | 251 if (maxLabelWidth > allowedWidth) { |
217 shortenedTicks = formattedTicks | 252 shortenedTicks = formattedTicks |
218 .map((x) => textMetrics.ellipsizeText(x, allowedWidth)) | 253 .map((x) => textMetrics.ellipsizeText(x, allowedWidth)) |
219 .toList(); | 254 .toList(); |
220 } | 255 } |
221 } | 256 } |
222 } | 257 } |
223 } | 258 } |
OLD | NEW |