| 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 part of charted.core.scales; | 8 part of charted.core.scales; |
| 9 | 9 |
| 10 class LinearScale implements Scale { | 10 class LinearScale implements Scale { |
| 11 static const defaultDomain = const [0, 1]; | 11 static const defaultDomain = const [0, 1]; |
| 12 static const defaultRange = const [0, 1]; | 12 static const defaultRange = const [0, 1]; |
| 13 | 13 |
| 14 bool _rounded = false; | 14 bool _rounded = false; |
| 15 Iterable _domain = defaultDomain; | 15 Iterable _domain = defaultDomain; |
| 16 Iterable _range = defaultRange; | 16 Iterable _range = defaultRange; |
| 17 | 17 |
| 18 int _ticksCount = 5; | 18 int _ticksCount = 5; |
| 19 int _forcedTicksCount = -1; |
| 20 |
| 19 bool _clamp = false; | 21 bool _clamp = false; |
| 20 bool _nice = false; | 22 bool _nice = false; |
| 21 | |
| 22 Function _invert; | 23 Function _invert; |
| 23 Function _scale; | 24 Function _scale; |
| 24 | 25 |
| 25 LinearScale(); | 26 LinearScale(); |
| 26 | 27 |
| 27 LinearScale._clone(LinearScale source) | 28 LinearScale._clone(LinearScale source) |
| 28 : _domain = source._domain.toList(), | 29 : _domain = source._domain.toList(), |
| 29 _range = source._range.toList(), | 30 _range = source._range.toList(), |
| 30 _ticksCount = source._ticksCount, | 31 _ticksCount = source._ticksCount, |
| 31 _clamp = source._clamp, | 32 _clamp = source._clamp, |
| 32 _nice = source._nice, | 33 _nice = source._nice, |
| 33 _rounded = source._rounded { | 34 _rounded = source._rounded { |
| 34 _reset(); | 35 _reset(); |
| 35 } | 36 } |
| 36 | 37 |
| 37 void _reset({bool nice: false}) { | 38 void _reset({bool nice: false}) { |
| 38 if (nice) { | 39 if (nice) { |
| 39 _domain = ScaleUtils.nice( | 40 _domain = ScaleUtils.nice( |
| 40 _domain, ScaleUtils.niceStep(_linearTickRange().step)); | 41 _domain, ScaleUtils.niceStep(_linearTickRange().step)); |
| 42 } else { |
| 43 if (_forcedTicksCount > 0) { |
| 44 var tickRange = _linearTickRange(); |
| 45 _domain = [tickRange.first, tickRange.last]; |
| 46 } |
| 41 } | 47 } |
| 42 | 48 |
| 43 Function linear = math.min(_domain.length, _range.length) > 2 | 49 Function linear = math.min(_domain.length, _range.length) > 2 |
| 44 ? ScaleUtils.polylinearScale | 50 ? ScaleUtils.polylinearScale |
| 45 : ScaleUtils.bilinearScale; | 51 : ScaleUtils.bilinearScale; |
| 46 | 52 |
| 47 Function uninterpolator = clamp ? uninterpolateClamp : uninterpolateNumber; | 53 Function uninterpolator = clamp ? uninterpolateClamp : uninterpolateNumber; |
| 48 InterpolatorGenerator interpolator; | 54 InterpolatorGenerator interpolator; |
| 49 if (rounded) { | 55 if (rounded) { |
| 50 interpolator = createRoundedNumberInterpolator; | 56 interpolator = createRoundedNumberInterpolator; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 assert(value != null); | 98 assert(value != null); |
| 93 if (value != null && _ticksCount != value) { | 99 if (value != null && _ticksCount != value) { |
| 94 _ticksCount = value; | 100 _ticksCount = value; |
| 95 _reset(); | 101 _reset(); |
| 96 } | 102 } |
| 97 } | 103 } |
| 98 | 104 |
| 99 @override | 105 @override |
| 100 int get ticksCount => _ticksCount; | 106 int get ticksCount => _ticksCount; |
| 101 | 107 |
| 108 set forcedTicksCount(int value) { |
| 109 _forcedTicksCount = value; |
| 110 _reset(nice: false); |
| 111 } |
| 112 |
| 113 get forcedTicksCount => _forcedTicksCount; |
| 114 |
| 102 @override | 115 @override |
| 103 Iterable get ticks => _linearTickRange(); | 116 Iterable get ticks => _linearTickRange(); |
| 104 | 117 |
| 105 @override | 118 @override |
| 106 set clamp(bool value) { | 119 set clamp(bool value) { |
| 107 assert(value != null); | 120 assert(value != null); |
| 108 if (value != null && _clamp != value) { | 121 if (value != null && _clamp != value) { |
| 109 _clamp = value; | 122 _clamp = value; |
| 110 _reset(); | 123 _reset(); |
| 111 } | 124 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 136 invert(value) => _invert(value); | 149 invert(value) => _invert(value); |
| 137 | 150 |
| 138 Range _linearTickRange([Extent extent]) { | 151 Range _linearTickRange([Extent extent]) { |
| 139 if (extent == null) { | 152 if (extent == null) { |
| 140 extent = ScaleUtils.extent(_domain); | 153 extent = ScaleUtils.extent(_domain); |
| 141 } | 154 } |
| 142 var span = extent.max - extent.min; | 155 var span = extent.max - extent.min; |
| 143 if (span == 0) { | 156 if (span == 0) { |
| 144 span = 1.0; // [span / _ticksCount] should never be equal zero. | 157 span = 1.0; // [span / _ticksCount] should never be equal zero. |
| 145 } | 158 } |
| 146 var step = math.pow(10, (math.log(span / _ticksCount) / math.LN10).floor()); | |
| 147 var err = _ticksCount / span * step; | |
| 148 | 159 |
| 149 // Filter ticks to get closer to the desired count. | 160 var step; |
| 150 if (err <= .15) { | 161 if (_forcedTicksCount > 0) { |
| 151 step *= 10; | 162 // Find the factor (in power of 10) for the max and min of the extent and |
| 152 } else if (err <= .35) { | 163 // round the max up and min down to make sure the domain of the scale is |
| 153 step *= 5; | 164 // of nicely rounded number and it contains the original domain. This way |
| 154 } else if (err <= .75) { | 165 // when forcing the ticks count at least the two ends of the scale would |
| 155 step *= 2; | 166 // look nice and has a high chance of having the intermediate tick values |
| 167 // to be nice. |
| 168 var maxFactor = extent.max == 0 ? 1 |
| 169 : math.pow(10, (math.log((extent.max as num).abs() / forcedTicksCount) |
| 170 / math.LN10).floor()); |
| 171 var max = (extent.max / maxFactor).ceil() * maxFactor; |
| 172 var minFactor = extent.min == 0 ? 1 |
| 173 : math.pow(10, (math.log((extent.min as num).abs() / forcedTicksCount) |
| 174 / math.LN10).floor()); |
| 175 var min = (extent.min / minFactor).floor() * minFactor; |
| 176 step = (max - min) / forcedTicksCount; |
| 177 return new Range(min, max + step * 0.5, step); |
| 178 } else { |
| 179 |
| 180 step = math.pow(10, (math.log(span / _ticksCount) / math.LN10).floor()); |
| 181 var err = _ticksCount / span * step; |
| 182 |
| 183 // Filter ticks to get closer to the desired count. |
| 184 if (err <= .15) { |
| 185 step *= 10; |
| 186 } else if (err <= .35) { |
| 187 step *= 5; |
| 188 } else if (err <= .75) { |
| 189 step *= 2; |
| 190 } |
| 156 } | 191 } |
| 157 | 192 |
| 158 return new Range((extent.min / step).ceil() * step, | 193 return new Range((extent.min / step).ceil() * step, |
| 159 (extent.max / step).floor() * step + step * 0.5, step); | 194 (extent.max / step).floor() * step + step * 0.5, step); |
| 160 } | 195 } |
| 161 | 196 |
| 162 @override | 197 @override |
| 163 FormatFunction createTickFormatter([String formatStr]) { | 198 FormatFunction createTickFormatter([String formatStr]) { |
| 164 int precision(value) { | 199 int precision(value) { |
| 165 return -(math.log(value) / math.LN10 + .01).floor(); | 200 return -(math.log(value) / math.LN10 + .01).floor(); |
| 166 } | 201 } |
| 167 Range tickRange = _linearTickRange(); | 202 Range tickRange = _linearTickRange(); |
| 168 if (formatStr == null) { | 203 if (formatStr == null) { |
| 169 formatStr = ".${precision(tickRange.step)}f"; | 204 formatStr = ".${precision(tickRange.step)}f"; |
| 170 } | 205 } |
| 171 NumberFormat formatter = new NumberFormat(new EnUsLocale()); | 206 NumberFormat formatter = new NumberFormat(new EnUsLocale()); |
| 172 return formatter.format(formatStr); | 207 return formatter.format(formatStr); |
| 173 } | 208 } |
| 174 | 209 |
| 175 @override | 210 @override |
| 176 LinearScale clone() => new LinearScale._clone(this); | 211 LinearScale clone() => new LinearScale._clone(this); |
| 177 } | 212 } |
| OLD | NEW |