blob: d99d6ada266844e7a8ee7b37ae0ddfc8657201db [file] [log] [blame]
/*
* 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.svg;
/**
* Implementations of line interpolators are given a list of
* points and they must return Svg path description to draw
* a line connecting these points
*/
typedef String LineInterpolator(List<math.Point> points);
/**
* [SvgLine] provides a data-driven way to create Svg path descriptions
* that can be used to draw lines. It internally has support for a few
* interpolations and can easily be extended to add support for more.
*/
class SvgLine implements SvgPathGenerator {
// TODO(prsd): Implement more interpolators
/** Linear interpolator */
static const String LINEAR = "linear";
/** Default interpolator */
static LineInterpolator DEFAULT_INTERPOLATOR = _linear;
/** Map of interpolator names to implementations */
static Map<String, LineInterpolator> interpolators = {};
/**
* [xAccessor] is used to access/convert datum to x coordinate value.
* If not specified, [defaultDataToX] is used.
*/
SelectionValueAccessor<num> xAccessor = defaultDataToX;
/**
* [yAccessor] is used to access/convert datum to y coordinate value.
* If not specified, [defaultDataToY] is used.
*/
SelectionValueAccessor<num> yAccessor = defaultDataToY;
/**
* [defined] is used to determine if a value is considered valid.
* If this function returns false for any value, that value isn't
* included in the line and the line gets split.
*/
SelectionCallback<bool> defined = (d, i, e) => true;
LineInterpolator _interpolate = DEFAULT_INTERPOLATOR;
/**
* Set line interpolation to one of the known/registered
* interpolation types. Defaults to [SvgLine.LINEAR]
*/
set interpolation(String value) {
if (!interpolators.containsKey(value)) {
throw new ArgumentError('Unregistered line interpolator.');
}
_interpolate = DEFAULT_INTERPOLATOR;
}
/** Set a constant value as the x-value on all points in the line */
set x(num value) => xAccessor = toValueAccessor(value);
/** Set a constant value as the x-value on all points in the line */
set y(num value) => yAccessor = toValueAccessor(value);
/**
* Get Svg path description for the given [data], element index [index]
* and element [e] to which the data is associated.
*/
String path(data, int index, Element e) {
var segments = [],
points = [];
assert(data is List);
data.asMap().forEach((int i, d) {
if (defined(d, i, e)) {
points.add(new math.Point(xAccessor(d, i), yAccessor(d, i)));
} else if (points.isNotEmpty) {
segments.add('M${_interpolate(points)}');
points = [];
}
});
if (points.isNotEmpty) segments.add('M${_interpolate(points)}');
return segments.join();
}
/**
* Default implementation of a callback to extract X coordinate
* value for a given datum. Assumes that datam is a non-empty
* array.
*/
static num defaultDataToX(d, i) => d[0];
/**
* Default implementation of a callback to extract Y coordinate
* value for a given datum. Assumes that datam is an array of
* atleast two elements.
*/
static num defaultDataToY(d, i) => d[1];
/* Implementation of the linear interpolator */
static String _linear(List points) =>
points.map((pt) => '${pt.x},${pt.y}').join('L');
}