OLD | NEW |
| (Empty) |
1 // | |
2 // Copyright 2014 Google Inc. All rights reserved. | |
3 // | |
4 // Use of this source code is governed by a BSD-style | |
5 // license that can be found in the LICENSE file or at | |
6 // https://developers.google.com/open-source/licenses/bsd | |
7 // | |
8 | |
9 part of charted.svg.shapes; | |
10 | |
11 /// Function to convert a list of points to path. | |
12 typedef String LineInterpolator(Iterable<math.Point> points, int tension); | |
13 | |
14 /// | |
15 /// [SvgLine] provides a data-driven way to create path descriptions | |
16 /// that can be used to draw lines. | |
17 /// | |
18 class SvgLine implements SvgShape { | |
19 static const LINE_INTERPOLATOR_LINEAR = 'linear'; | |
20 | |
21 static final LINE_INTERPOLATORS = { | |
22 LINE_INTERPOLATOR_LINEAR: _linear | |
23 }; | |
24 | |
25 /// Callback to access/convert datum to x coordinate value. | |
26 final SelectionValueAccessor<num> xValueAccessor; | |
27 | |
28 /// Callback to access/convert datum to y coordinate value. | |
29 final SelectionValueAccessor<num> yValueAccessor; | |
30 | |
31 /// Callback that is used to determine if a value is considered valid. | |
32 /// If [isDefined] returns false at any time, the value isn't part | |
33 /// of the line - the line would be split. | |
34 final SelectionCallback<bool> isDefined; | |
35 | |
36 /// Interpolator that is used for creating the path. | |
37 final LineInterpolator interpolator; | |
38 | |
39 /// Tension of the line, as used by a few interpolators. | |
40 final int tension; | |
41 | |
42 SvgLine({ | |
43 this.xValueAccessor: defaultDataToX, | |
44 this.yValueAccessor: defaultDataToY, | |
45 this.isDefined: defaultIsDefined, | |
46 this.tension: 0, | |
47 String interpolate: LINE_INTERPOLATOR_LINEAR }) | |
48 : interpolator = LINE_INTERPOLATORS[interpolate] { | |
49 assert(interpolator != null); | |
50 } | |
51 | |
52 /// Generates path for drawing a line based in the selected [interpolator] | |
53 @override | |
54 String path(data, int index, Element e) { | |
55 assert(data is Iterable); | |
56 var segments = new StringBuffer(), | |
57 points = []; | |
58 for (int i = 0, len = data.length; i < len; ++i) { | |
59 final d = data.elementAt(i); | |
60 if (isDefined(d, i, e)) { | |
61 points.add(new math.Point(xValueAccessor(d, i), yValueAccessor(d, i))); | |
62 } else if (points.isNotEmpty){ | |
63 segments.write('M${interpolator(points, tension)}'); | |
64 points.clear(); | |
65 } | |
66 } | |
67 if (points.isNotEmpty) { | |
68 segments.write('M${interpolator(points, tension)}'); | |
69 } | |
70 return segments.toString(); | |
71 } | |
72 | |
73 /// Default implementation of [xValueAccessor]. | |
74 /// Returns the first element if [d] is an iterable, otherwise returns [d]. | |
75 static num defaultDataToX(d, i) => d is Iterable ? d.first : d; | |
76 | |
77 /// Default implementation of [yValueAccessor]. | |
78 /// Returns the second element if [d] is an iterable, otherwise returns [d]. | |
79 static num defaultDataToY(d, i) => d is Iterable ? d.elementAt(1) : d; | |
80 | |
81 /// Default implementation of [isDefined]. | |
82 /// Returns true for all non-null values of [d]. | |
83 static bool defaultIsDefined(d, i, e) => d != null; | |
84 | |
85 /// Linear interpolator. | |
86 static String _linear(Iterable points, _) => | |
87 points.map((pt) => '${pt.x},${pt.y}').join('L'); | |
88 } | |
OLD | NEW |