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 /// | |
12 /// [SvgArc] provides a data-driven way to create path descriptions | |
13 /// that can be used to draw arcs - like those used in pie-charts. | |
14 /// | |
15 class SvgArc implements SvgShape { | |
16 static const _OFFSET = -HALF_PI; | |
17 static const _MAX = TAU - EPSILON; | |
18 | |
19 /// [innerRadiusCallback] is called to get inner radius of the arc. | |
20 /// As with other callbacks, [innerRadiusCallback] is passed data, index | |
21 /// and element in the context. | |
22 final SelectionCallback<num> innerRadiusCallback; | |
23 | |
24 /// [outerRadiusCallback] is called to get outer radius of the arc. | |
25 /// As with other callbacks, [outerRadiusCallback] is passed data, index | |
26 /// and element in the context. | |
27 final SelectionCallback<num> outerRadiusCallback; | |
28 | |
29 /// [startAngleCallback] is called to get the start angle of the arc. | |
30 /// As with other callbacks, [startAngleCallback] is passed data, index | |
31 /// and element in the context. | |
32 final SelectionCallback<num> startAngleCallback; | |
33 | |
34 /// [endAngleCallback] is called to get the start angle of the arc. | |
35 /// As with other callbacks, [endAngleCallback] is passed data, index | |
36 /// and element in the context. | |
37 final SelectionCallback<num> endAngleCallback; | |
38 | |
39 SvgArc({ | |
40 this.innerRadiusCallback : defaultInnerRadiusCallback, | |
41 this.outerRadiusCallback: defaultOuterRadiusCallback, | |
42 this.startAngleCallback: defaultStartAngleCallback, | |
43 this.endAngleCallback: defaultEndAngleCallback | |
44 }); | |
45 | |
46 String path(d, int i, Element e) { | |
47 var ir = innerRadiusCallback(d, i, e), | |
48 or = outerRadiusCallback(d, i, e), | |
49 start = startAngleCallback(d, i, e) + _OFFSET, | |
50 end = endAngleCallback(d, i, e) + _OFFSET, | |
51 sa = math.min(start, end), | |
52 ea = math.max(start, end), | |
53 delta = ea - sa; | |
54 | |
55 if (delta > _MAX) { | |
56 return ir > 0 | |
57 ? "M0,$or" "A$or,$or 0 1,1 0,-$or" "A$or,$or 0 1,1 0,$or" | |
58 "M0,$ir" "A$ir,$ir 0 1,0 0,-$ir" "A$ir,$ir 0 1,0 0,$ir" "Z" | |
59 : "M0,$or" "A$or,$or 0 1,1 0,-$or" "A$or,$or 0 1,1 0,$or" "Z"; | |
60 } | |
61 | |
62 var ss = math.sin(sa), | |
63 se = math.sin(ea), | |
64 cs = math.cos(sa), | |
65 ce = math.cos(ea), | |
66 df = delta < PI ? 0 : 1; | |
67 | |
68 return ir > 0 | |
69 ? "M${or * cs},${or * ss}" "A$or,$or 0 $df,1 ${or * ce},${or * se}" | |
70 "L${ir * ce},${ir * se}" "A$ir,$ir 0 $df,0 ${ir * cs},${ir * ss}" | |
71 "Z" | |
72 : "M${or * cs},${or * ss}" "A$or,$or 0 $df,1 ${or * ce},${or * se}" | |
73 "L0,0" "Z"; | |
74 } | |
75 | |
76 List centroid(d, int i, Element e) { | |
77 var r = (innerRadiusCallback(d, i, e) + outerRadiusCallback(d, i, e)) / 2, | |
78 a = (startAngleCallback(d, i, e) + endAngleCallback(d, i, e)) / 2 - | |
79 math.PI / 2; | |
80 return [math.cos(a) * r, math.sin(a) * r]; | |
81 } | |
82 | |
83 /// Default [innerRadiusCallback] returns data.innerRadius | |
84 static num defaultInnerRadiusCallback(d, i, e) => | |
85 d is! SvgArcData || d.innerRadius == null ? 0 : d.innerRadius; | |
86 | |
87 /// Default [outerRadiusCallback] returns data.outerRadius | |
88 static num defaultOuterRadiusCallback(d, i, e) => | |
89 d is! SvgArcData || d.outerRadius == null ? 0 : d.outerRadius; | |
90 | |
91 /// Default [startAngleCallback] returns data.startAngle | |
92 static num defaultStartAngleCallback(d, i, e) => | |
93 d is! SvgArcData || d.startAngle == null ? 0 : d.startAngle; | |
94 | |
95 /// Default [endAngleCallback] that returns data.endAngle | |
96 static num defaultEndAngleCallback(d, i, e) => | |
97 d is! SvgArcData || d.endAngle == null ? 0 : d.endAngle; | |
98 } | |
99 | |
100 /// Value type for SvgArc as used by default property accessors in SvgArc | |
101 class SvgArcData { | |
102 dynamic data; | |
103 num value; | |
104 num innerRadius; | |
105 num outerRadius; | |
106 num startAngle; | |
107 num endAngle; | |
108 | |
109 SvgArcData(this.data, this.value, | |
110 this.startAngle, this.endAngle, [ | |
111 this.innerRadius = 0, this.outerRadius = 100 ]); | |
112 } | |
113 | |
114 | |
115 /// Returns the interpolator between two [SvgArcData] [a] and [b]. | |
116 /// | |
117 /// The interpolator will interpolate the older innerRadius and outerRadius with | |
118 /// newer ones, as well as older startAngle and endAngle with newer ones. | |
119 Interpolator interpolateSvgArcData(SvgArcData a, SvgArcData b) { | |
120 var ast = a.startAngle, | |
121 aen = a.endAngle, | |
122 ai = a.innerRadius, | |
123 ao = a.outerRadius, | |
124 bst = b.startAngle - ast, | |
125 ben = b.endAngle - aen, | |
126 bi = b.innerRadius - ai, | |
127 bo = b.outerRadius - ao; | |
128 | |
129 return (t) => new SvgArcData(b.data, b.value, | |
130 (ast + bst * t), (aen + ben * t), (ai + bi * t), (ao + bo * t)); | |
131 } | |
OLD | NEW |