| // |
| // Copyright 2014 Google Inc. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file or at |
| // https://developers.google.com/open-source/licenses/bsd |
| // |
| part of charted.core.scales; |
| |
| class _OrdinalScale implements OrdinalScale { |
| final _index = new Map<dynamic, int>(); |
| |
| List _domain = []; |
| List _range = []; |
| num _rangeBand = 0; |
| Extent _rangeExtent; |
| Function _reset; |
| |
| _OrdinalScale(); |
| |
| _OrdinalScale._clone(_OrdinalScale source) |
| : _domain = source._domain, |
| _range = source._range, |
| _reset = source._reset, |
| _rangeExtent = source._rangeExtent, |
| _rangeBand = source._rangeBand { |
| _index.addAll(source._index); |
| } |
| |
| @override |
| scale(dynamic value) { |
| if (!_index.containsKey(value)) { |
| _index[value] = domain.length; |
| _domain.add(value); |
| } |
| return _range.isNotEmpty |
| ? _range.elementAt(_index[value] % _range.length) |
| : 0; |
| } |
| |
| @override |
| dynamic invert(num value) { |
| int position = _range.indexOf(value); |
| return position > -1 && position < _domain.length |
| ? _domain[position] |
| : null; |
| } |
| |
| @override |
| set domain(Iterable values) { |
| _domain = []; |
| _index.clear(); |
| |
| for (var i = 0; i < values.length; i++) { |
| var value = values.elementAt(i); |
| if (_index[value] == null) { |
| _index[value] = _domain.length; |
| _domain.add(value); |
| } |
| } |
| |
| if (_reset != null) _reset(this); |
| } |
| |
| @override |
| Iterable get domain => _domain; |
| |
| @override |
| set range(Iterable values) => _setRange(this, values); |
| |
| @override |
| Iterable get range => _range; |
| |
| @override |
| Extent get rangeExtent => _rangeExtent; |
| |
| @override |
| void rangePoints(Iterable range, [double padding = 0.0]) => |
| _setRangePoints(this, range, padding); |
| |
| @override |
| void rangeBands(Iterable range, |
| [double padding = 0.0, double outerPadding]) => |
| _setRangeBands( |
| this, range, padding, outerPadding == null ? padding : outerPadding); |
| |
| @override |
| void rangeRoundBands(Iterable range, |
| [double padding = 0.0, double outerPadding]) => |
| _setRangeRoundBands( |
| this, range, padding, outerPadding == null ? padding : outerPadding); |
| |
| @override |
| num get rangeBand => _rangeBand; |
| |
| @override |
| FormatFunction createTickFormatter([String format]) => identityFunction; |
| |
| @override |
| Iterable get ticks => _domain; |
| |
| @override |
| OrdinalScale clone() => new _OrdinalScale._clone(this); |
| |
| List _steps(start, step) => |
| new Range(domain.length).map((num i) => start + step * i).toList(); |
| |
| static void _setRange(_OrdinalScale scale, Iterable values) { |
| scale._reset = (_OrdinalScale s) { |
| s._range = values; |
| s._rangeBand = 0; |
| s._rangeExtent = null; |
| }; |
| scale._reset(scale); |
| } |
| |
| static void _setRangePoints( |
| _OrdinalScale scale, Iterable range, double padding) { |
| scale._reset = (_OrdinalScale s) { |
| var start = range.first, |
| stop = range.last, |
| step = (stop - start) / (s.domain.length - 1 + padding); |
| |
| s._range = s._steps( |
| s.domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, |
| step); |
| s._rangeBand = 0; |
| s._rangeExtent = new Extent(start, stop); |
| }; |
| if (scale.domain.isNotEmpty) { |
| scale._reset(scale); |
| } |
| } |
| |
| static void _setRangeBands(_OrdinalScale scale, Iterable range, |
| double padding, double outerPadding) { |
| scale._reset = (_OrdinalScale s) { |
| var start = range.first, |
| stop = range.last, |
| step = (stop - start) / s.domain.length - padding + 2 * outerPadding; |
| |
| s._range = s._steps(start + step * outerPadding, step); |
| s._rangeBand = step * (1 - padding); |
| s._rangeExtent = new Extent(start, stop); |
| }; |
| if (scale.domain.isNotEmpty) { |
| scale._reset(scale); |
| } |
| } |
| |
| static void _setRangeRoundBands(_OrdinalScale scale, Iterable range, |
| double padding, double outerPadding) { |
| scale._reset = (_OrdinalScale s) { |
| var start = range.first, |
| stop = range.last, |
| step = ((stop - start) / |
| (s.domain.length - padding + 2 * outerPadding)).floor(), |
| error = stop - start - (s.domain.length - padding) * step; |
| |
| s._range = s._steps(start + (error / 2).round(), step); |
| s._rangeBand = (step * (1 - padding)).round(); |
| s._rangeExtent = new Extent(start, stop); |
| }; |
| if (scale.domain.isNotEmpty) { |
| scale._reset(scale); |
| } |
| } |
| |
| // |
| // Properties that are valid only on quantitative scales. |
| // |
| |
| bool clamp; |
| bool nice; |
| bool rounded; |
| int ticksCount; |
| } |