|
1 /* |
|
2 YUI 3.10.3 (build 2fb5187) |
|
3 Copyright 2013 Yahoo! Inc. All rights reserved. |
|
4 Licensed under the BSD License. |
|
5 http://yuilibrary.com/license/ |
|
6 */ |
|
7 |
|
8 YUI.add('series-line-util', function (Y, NAME) { |
|
9 |
|
10 /** |
|
11 * Provides functionality for drawing lines in a series. |
|
12 * |
|
13 * @module charts |
|
14 * @submodule series-line-util |
|
15 */ |
|
16 /** |
|
17 * Utility class used for drawing lines. |
|
18 * |
|
19 * @class Lines |
|
20 * @constructor |
|
21 * @submodule series-line-util |
|
22 */ |
|
23 var Y_Lang = Y.Lang; |
|
24 function Lines(){} |
|
25 |
|
26 Lines.prototype = { |
|
27 /** |
|
28 * @property _lineDefaults |
|
29 * @type Object |
|
30 * @private |
|
31 */ |
|
32 _lineDefaults: null, |
|
33 |
|
34 /** |
|
35 * Creates a graphic in which to draw a series. |
|
36 * |
|
37 * @method _getGraphic |
|
38 * @return Graphic |
|
39 * @private |
|
40 */ |
|
41 _getGraphic: function() |
|
42 { |
|
43 var graphic = this.get("graphic") || this.get("graph").get("graphic"); |
|
44 if(!this._lineGraphic) |
|
45 { |
|
46 this._lineGraphic = graphic.addShape({type: "path"}); |
|
47 } |
|
48 this._lineGraphic.clear(); |
|
49 return this._lineGraphic; |
|
50 }, |
|
51 |
|
52 /** |
|
53 * Toggles visibility |
|
54 * |
|
55 * @method _toggleVisible |
|
56 * @param {Boolean} visible indicates visibilitye |
|
57 * @private |
|
58 */ |
|
59 _toggleVisible: function(visible) |
|
60 { |
|
61 if(this._lineGraphic) |
|
62 { |
|
63 this._lineGraphic.set("visible", visible); |
|
64 } |
|
65 }, |
|
66 |
|
67 /** |
|
68 * Draws lines for the series. |
|
69 * |
|
70 * @method drawLines |
|
71 * @protected |
|
72 */ |
|
73 drawLines: function() |
|
74 { |
|
75 if(this.get("xcoords").length < 1) |
|
76 { |
|
77 return; |
|
78 } |
|
79 var isNumber = Y_Lang.isNumber, |
|
80 xcoords, |
|
81 ycoords, |
|
82 direction = this.get("direction"), |
|
83 len, |
|
84 lastPointValid, |
|
85 pointValid, |
|
86 noPointsRendered = true, |
|
87 lastValidX, |
|
88 lastValidY, |
|
89 nextX, |
|
90 nextY, |
|
91 i, |
|
92 styles = this.get("styles").line, |
|
93 lineType = styles.lineType, |
|
94 lc = styles.color || this._getDefaultColor(this.get("graphOrder"), "line"), |
|
95 lineAlpha = styles.alpha, |
|
96 dashLength = styles.dashLength, |
|
97 gapSpace = styles.gapSpace, |
|
98 connectDiscontinuousPoints = styles.connectDiscontinuousPoints, |
|
99 discontinuousType = styles.discontinuousType, |
|
100 discontinuousDashLength = styles.discontinuousDashLength, |
|
101 discontinuousGapSpace = styles.discontinuousGapSpace, |
|
102 path = this._getGraphic(); |
|
103 if(this._stacked) |
|
104 { |
|
105 xcoords = this.get("stackedXCoords"); |
|
106 ycoords = this.get("stackedYCoords"); |
|
107 } |
|
108 else |
|
109 { |
|
110 xcoords = this.get("xcoords"); |
|
111 ycoords = this.get("ycoords"); |
|
112 } |
|
113 len = direction === "vertical" ? ycoords.length : xcoords.length; |
|
114 path.set("stroke", { |
|
115 weight: styles.weight, |
|
116 color: lc, |
|
117 opacity: lineAlpha |
|
118 }); |
|
119 for(i = 0; i < len; i = ++i) |
|
120 { |
|
121 nextX = xcoords[i]; |
|
122 nextY = ycoords[i]; |
|
123 pointValid = isNumber(nextX) && isNumber(nextY); |
|
124 if(!pointValid) |
|
125 { |
|
126 lastPointValid = pointValid; |
|
127 continue; |
|
128 } |
|
129 if(noPointsRendered) |
|
130 { |
|
131 noPointsRendered = false; |
|
132 path.moveTo(nextX, nextY); |
|
133 } |
|
134 else if(lastPointValid) |
|
135 { |
|
136 if(lineType !== "dashed") |
|
137 { |
|
138 path.lineTo(nextX, nextY); |
|
139 } |
|
140 else |
|
141 { |
|
142 this.drawDashedLine(path, lastValidX, lastValidY, nextX, nextY, |
|
143 dashLength, |
|
144 gapSpace); |
|
145 } |
|
146 } |
|
147 else if(!connectDiscontinuousPoints) |
|
148 { |
|
149 path.moveTo(nextX, nextY); |
|
150 } |
|
151 else |
|
152 { |
|
153 if(discontinuousType !== "solid") |
|
154 { |
|
155 this.drawDashedLine(path, lastValidX, lastValidY, nextX, nextY, |
|
156 discontinuousDashLength, |
|
157 discontinuousGapSpace); |
|
158 } |
|
159 else |
|
160 { |
|
161 path.lineTo(nextX, nextY); |
|
162 } |
|
163 } |
|
164 lastValidX = nextX; |
|
165 lastValidY = nextY; |
|
166 lastPointValid = true; |
|
167 } |
|
168 path.end(); |
|
169 }, |
|
170 |
|
171 /** |
|
172 * Connects data points with a consistent curve for a series. |
|
173 * |
|
174 * @method drawSpline |
|
175 * @protected |
|
176 */ |
|
177 drawSpline: function() |
|
178 { |
|
179 if(this.get("xcoords").length < 1) |
|
180 { |
|
181 return; |
|
182 } |
|
183 var xcoords = this.get("xcoords"), |
|
184 ycoords = this.get("ycoords"), |
|
185 curvecoords = this.getCurveControlPoints(xcoords, ycoords), |
|
186 len = curvecoords.length, |
|
187 cx1, |
|
188 cx2, |
|
189 cy1, |
|
190 cy2, |
|
191 x, |
|
192 y, |
|
193 i = 0, |
|
194 styles = this.get("styles").line, |
|
195 path = this._getGraphic(), |
|
196 lineAlpha = styles.alpha, |
|
197 color = styles.color || this._getDefaultColor(this.get("graphOrder"), "line"); |
|
198 path.set("stroke", { |
|
199 weight: styles.weight, |
|
200 color: color, |
|
201 opacity: lineAlpha |
|
202 }); |
|
203 path.moveTo(xcoords[0], ycoords[0]); |
|
204 for(; i < len; i = ++i) |
|
205 { |
|
206 x = curvecoords[i].endx; |
|
207 y = curvecoords[i].endy; |
|
208 cx1 = curvecoords[i].ctrlx1; |
|
209 cx2 = curvecoords[i].ctrlx2; |
|
210 cy1 = curvecoords[i].ctrly1; |
|
211 cy2 = curvecoords[i].ctrly2; |
|
212 path.curveTo(cx1, cy1, cx2, cy2, x, y); |
|
213 } |
|
214 path.end(); |
|
215 }, |
|
216 |
|
217 /** |
|
218 * Draws a dashed line between two points. |
|
219 * |
|
220 * @method drawDashedLine |
|
221 * @param {Number} xStart The x position of the start of the line |
|
222 * @param {Number} yStart The y position of the start of the line |
|
223 * @param {Number} xEnd The x position of the end of the line |
|
224 * @param {Number} yEnd The y position of the end of the line |
|
225 * @param {Number} dashSize the size of dashes, in pixels |
|
226 * @param {Number} gapSize the size of gaps between dashes, in pixels |
|
227 * @private |
|
228 */ |
|
229 drawDashedLine: function(path, xStart, yStart, xEnd, yEnd, dashSize, gapSize) |
|
230 { |
|
231 dashSize = dashSize || 10; |
|
232 gapSize = gapSize || 10; |
|
233 var segmentLength = dashSize + gapSize, |
|
234 xDelta = xEnd - xStart, |
|
235 yDelta = yEnd - yStart, |
|
236 delta = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2)), |
|
237 segmentCount = Math.floor(Math.abs(delta / segmentLength)), |
|
238 radians = Math.atan2(yDelta, xDelta), |
|
239 xCurrent = xStart, |
|
240 yCurrent = yStart, |
|
241 i; |
|
242 xDelta = Math.cos(radians) * segmentLength; |
|
243 yDelta = Math.sin(radians) * segmentLength; |
|
244 |
|
245 for(i = 0; i < segmentCount; ++i) |
|
246 { |
|
247 path.moveTo(xCurrent, yCurrent); |
|
248 path.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize); |
|
249 xCurrent += xDelta; |
|
250 yCurrent += yDelta; |
|
251 } |
|
252 |
|
253 path.moveTo(xCurrent, yCurrent); |
|
254 delta = Math.sqrt((xEnd - xCurrent) * (xEnd - xCurrent) + (yEnd - yCurrent) * (yEnd - yCurrent)); |
|
255 |
|
256 if(delta > dashSize) |
|
257 { |
|
258 path.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize); |
|
259 } |
|
260 else if(delta > 0) |
|
261 { |
|
262 path.lineTo(xCurrent + Math.cos(radians) * delta, yCurrent + Math.sin(radians) * delta); |
|
263 } |
|
264 |
|
265 path.moveTo(xEnd, yEnd); |
|
266 }, |
|
267 |
|
268 /** |
|
269 * Default values for `styles` attribute. |
|
270 * |
|
271 * @method _getLineDefaults |
|
272 * @return Object |
|
273 * @protected |
|
274 */ |
|
275 _getLineDefaults: function() |
|
276 { |
|
277 return { |
|
278 alpha: 1, |
|
279 weight: 6, |
|
280 lineType:"solid", |
|
281 dashLength:10, |
|
282 gapSpace:10, |
|
283 connectDiscontinuousPoints:true, |
|
284 discontinuousType:"solid", |
|
285 discontinuousDashLength:10, |
|
286 discontinuousGapSpace:10 |
|
287 }; |
|
288 } |
|
289 }; |
|
290 Y.augment(Lines, Y.Attribute); |
|
291 Y.Lines = Lines; |
|
292 |
|
293 |
|
294 }, '3.10.3'); |