Index: charted/lib/svg/axis.dart |
diff --git a/charted/lib/svg/axis.dart b/charted/lib/svg/axis.dart |
deleted file mode 100644 |
index 81fc756f74f59a517b6d142d47a5a540ab7c57cc..0000000000000000000000000000000000000000 |
--- a/charted/lib/svg/axis.dart |
+++ /dev/null |
@@ -1,233 +0,0 @@ |
-// |
-// 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 |
-// |
- |
-library charted.svg.axis; |
- |
-import 'dart:html' show Element; |
-import 'dart:math' as math; |
- |
-import 'package:charted/core/scales.dart'; |
-import 'package:charted/core/utils.dart'; |
-import 'package:charted/selection/selection.dart'; |
- |
-/// |
-/// [SvgAxis] helps draw chart axes based on a given scale. |
-/// |
-class SvgAxis { |
- /// Store of axis roots mapped to currently used scales |
- static final _scales = new Expando<Scale>(); |
- |
- /// Orientation of the axis. Defaults to [ORIENTATION_BOTTOM]. |
- final String orientation; |
- |
- /// Scale used on this axis |
- final Scale scale; |
- |
- /// Size of all inner ticks |
- final num innerTickSize; |
- |
- /// Size of the outer two ticks |
- final num outerTickSize; |
- |
- /// Padding on the ticks |
- final num tickPadding; |
- |
- /// List of values to be used on the ticks |
- List _tickValues; |
- |
- /// Formatter for the tick labels |
- FormatFunction _tickFormat; |
- |
- SvgAxis({ |
- this.orientation: ORIENTATION_BOTTOM, |
- this.innerTickSize: 6, |
- this.outerTickSize: 6, |
- this.tickPadding: 3, |
- Iterable tickValues, |
- FormatFunction tickFormat, |
- Scale scale }) : scale = scale == null ? new LinearScale() : scale { |
- _tickFormat = tickFormat == null |
- ? this.scale.createTickFormatter() |
- : tickFormat; |
- _tickValues = isNullOrEmpty(tickValues) ? this.scale.ticks : tickValues; |
- } |
- |
- Iterable get tickValues => _tickValues; |
- |
- FormatFunction get tickFormat => _tickFormat; |
- |
- /// Draw an axis on each non-null element in selection |
- draw(Selection g, {SvgAxisTicks axisTicksBuilder, bool isRTL: false}) => |
- g.each((d, i, e) => create( |
- e, g.scope, axisTicksBuilder: axisTicksBuilder, isRTL: isRTL)); |
- |
- /// Create an axis on [element]. |
- create(Element element, SelectionScope scope, { |
- SvgAxisTicks axisTicksBuilder, bool isRTL: false}) { |
- |
- var group = scope.selectElements([element]), |
- older = _scales[element], |
- current = _scales[element] = scale.clone(), |
- isInitialRender = older == null; |
- |
- var isLeft = orientation == ORIENTATION_LEFT, |
- isRight = !isLeft && orientation == ORIENTATION_RIGHT, |
- isVertical = isLeft || isRight, |
- isBottom = !isVertical && orientation == ORIENTATION_BOTTOM, |
- isTop = !(isVertical || isBottom) && orientation == ORIENTATION_TOP, |
- isHorizontal = !isVertical; |
- |
- if (older == null) older = current; |
- if (axisTicksBuilder == null) { |
- axisTicksBuilder = new SvgAxisTicks(); |
- } |
- axisTicksBuilder.init(this); |
- |
- var values = axisTicksBuilder.ticks, |
- formatted = axisTicksBuilder.formattedTicks, |
- ellipsized = axisTicksBuilder.shortenedTicks; |
- |
- var ticks = group.selectAll('.tick').data(values, current.scale), |
- exit = ticks.exit, |
- transform = isVertical ? _yAxisTransform : _xAxisTransform, |
- sign = isTop || isLeft ? -1 : 1, |
- isEllipsized = ellipsized != formatted; |
- |
- var enter = ticks.enter.appendWithCallback((d, i, e) { |
- var group = Namespace.createChildElement('g', e) |
- ..attributes['class'] = 'tick' |
- ..append(Namespace.createChildElement('line', e)) |
- ..append(Namespace.createChildElement('text', e) |
- ..attributes['dy'] = |
- isVertical ? '0.32em' : (isBottom ? '0.71em' : '0')); |
- if (!isInitialRender) { |
- group.style.setProperty('opacity', EPSILON.toString()); |
- } |
- return group; |
- }); |
- |
- // All attributes/styles/classes that may change due to theme and scale. |
- // TODO(prsd): Order elements before updating ticks. |
- ticks.each((d, i, e) { |
- Element line = e.firstChild; |
- Element text = e.lastChild; |
- bool isRTLText = false; // FIXME(prsd) |
- |
- if (isHorizontal) { |
- line.attributes['y2'] = '${sign * innerTickSize}'; |
- text.attributes['y'] = |
- '${sign * (math.max(innerTickSize, 0) + tickPadding)}'; |
- |
- if (axisTicksBuilder.rotation != 0) { |
- text.attributes |
- ..['transform'] = |
- 'rotate(${(isRTL ? -1 : 1) * axisTicksBuilder.rotation})' |
- ..['text-anchor'] = isRTL ? 'end' : 'start'; |
- } else { |
- text.attributes |
- ..remove('transform') |
- ..['text-anchor'] = 'middle'; |
- } |
- } else { |
- line.attributes['x2'] = '${sign * innerTickSize}'; |
- text.attributes |
- ..['x'] = '${sign * (math.max(innerTickSize, 0) + tickPadding)}' |
- ..['text-anchor'] = isLeft |
- ? (isRTLText ? 'start' : 'end') |
- : (isRTLText ? 'end' : 'start'); |
- } |
- |
- text.text = fixSimpleTextDirection(ellipsized.elementAt(i)); |
- if (isEllipsized) { |
- text.attributes['data-detail'] = formatted.elementAt(i); |
- } else { |
- text.attributes.remove('data-detail'); |
- } |
- |
- if (isInitialRender) { |
- var dx = current is OrdinalScale ? current.rangeBand / 2 : 0; |
- e.attributes['transform'] = isHorizontal |
- ? 'translate(${current.scale(d) + dx},0)' |
- : 'translate(0,${current.scale(d) + dx})'; |
- } else { |
- e.style.setProperty('opacity', '1.0'); |
- } |
- }); |
- |
- // Transition existing ticks to right positions |
- if (!isInitialRender) { |
- var transformFn; |
- if (current is OrdinalScale && current.rangeBand != 0) { |
- var dx = current.rangeBand / 2; |
- transformFn = (d) => current.scale(d) + dx; |
- } else if (older is OrdinalScale && older.rangeBand != 0) { |
- older = current; |
- } else { |
- transform(ticks, current.scale); |
- } |
- |
- transform(enter, transformFn != null ? transformFn : older.scale); |
- transform(ticks, transformFn != null ? transformFn : current.scale); |
- } |
- |
- exit.remove(); |
- |
- // Append the outer domain. |
- var path = element.querySelector('.domain'), |
- tickSize = sign * outerTickSize, |
- range = current.rangeExtent; |
- if (path == null) { |
- path = Namespace.createChildElement('path', element) |
- ..setAttribute('class', 'domain'); |
- } |
- path.attributes['d'] = isLeft || isRight |
- ? 'M${tickSize},${range.min}H0V${range.max}H${tickSize}' |
- : 'M${range.min},${tickSize}V0H${range.max}V${tickSize}'; |
- element.append(path); |
- } |
- |
- _xAxisTransform(Selection selection, transformFn) { |
- selection.transition() |
- ..attrWithCallback( |
- 'transform', (d, i, e) => 'translate(${transformFn(d)},0)'); |
- } |
- |
- _yAxisTransform(Selection selection, transformFn) { |
- selection.transition() |
- ..attrWithCallback( |
- 'transform', (d, i, e) => 'translate(0,${transformFn(d)})'); |
- } |
-} |
- |
-/// Interface and the default implementation of [SvgAxisTicks]. |
-/// SvgAxisTicks provides strategy to handle overlapping ticks on an |
-/// axis. Default implementation assumes that the ticks don't overlap. |
-class SvgAxisTicks { |
- int _rotation = 0; |
- Iterable _ticks; |
- Iterable _formattedTicks; |
- |
- void init(SvgAxis axis) { |
- _ticks = axis.tickValues; |
- _formattedTicks = _ticks.map((x) => axis.tickFormat(x)); |
- } |
- |
- /// When non-zero, indicates the angle by which each tick value must be |
- /// rotated to avoid the overlap. |
- int get rotation => _rotation; |
- |
- /// List of ticks that will be displayed on the axis. |
- Iterable get ticks => _ticks; |
- |
- /// List of formatted ticks values. |
- Iterable get formattedTicks => _formattedTicks; |
- |
- /// List of clipped tick values, if they had to be clipped. Must be same |
- /// as the [formattedTicks] if none of the ticks were ellipsized. |
- Iterable get shortenedTicks => _formattedTicks; |
-} |