1 | define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/html", "dojo/_base/array", |
---|
2 | "dojo/dom-geometry", "dojo/_base/fx", "dojo/fx", "dojo/_base/sniff", |
---|
3 | "../Element", "./_PlotEvents", "dojo/_base/Color", "dojox/color/_base", "./common", "../axis2d/common", |
---|
4 | "../scaler/primitive", "dojox/gfx", "dojox/gfx/matrix", "dojox/gfx/fx", "dojox/lang/functional", |
---|
5 | "dojox/lang/utils", "dojo/fx/easing"], |
---|
6 | function(lang, declare, hub, html, arr, domGeom, baseFx, coreFx, has, |
---|
7 | Element, PlotEvents, Color, dxcolor, dc, da, primitive, |
---|
8 | g, m, gfxfx, df, du, easing){ |
---|
9 | /*===== |
---|
10 | var Element = dojox.charting.Element; |
---|
11 | var PlotEvents = dojox.charting.plot2d._PlotEvents; |
---|
12 | =====*/ |
---|
13 | var FUDGE_FACTOR = 0.2; // use to overlap fans |
---|
14 | |
---|
15 | var Spider = declare("dojox.charting.plot2d.Spider", [Element, PlotEvents], { |
---|
16 | // summary: |
---|
17 | // The plot that represents a typical Spider chart. |
---|
18 | defaultParams: { |
---|
19 | labels: true, |
---|
20 | ticks: false, |
---|
21 | fixed: true, |
---|
22 | precision: 1, |
---|
23 | labelOffset: -10, |
---|
24 | labelStyle: "default", // default/rows/auto |
---|
25 | htmlLabels: true, // use HTML to draw labels |
---|
26 | startAngle: -90, // start angle for slices in degrees |
---|
27 | divisions: 3, // radius tick count |
---|
28 | axisColor: "", // spider axis color |
---|
29 | axisWidth: 0, // spider axis stroke width |
---|
30 | spiderColor: "", // spider web color |
---|
31 | spiderWidth: 0, // spider web stroke width |
---|
32 | seriesWidth: 0, // plot border with |
---|
33 | seriesFillAlpha: 0.2, // plot fill alpha |
---|
34 | spiderOrigin: 0.16, |
---|
35 | markerSize: 3, // radius of plot vertex (px) |
---|
36 | spiderType: "polygon", //"circle" |
---|
37 | animationType: easing.backOut, |
---|
38 | axisTickFont: "", |
---|
39 | axisTickFontColor: "", |
---|
40 | axisFont: "", |
---|
41 | axisFontColor: "" |
---|
42 | }, |
---|
43 | optionalParams: { |
---|
44 | radius: 0, |
---|
45 | font: "", |
---|
46 | fontColor: "" |
---|
47 | }, |
---|
48 | |
---|
49 | constructor: function(chart, kwArgs){ |
---|
50 | // summary: |
---|
51 | // Create a Spider plot. |
---|
52 | this.opt = lang.clone(this.defaultParams); |
---|
53 | du.updateWithObject(this.opt, kwArgs); |
---|
54 | du.updateWithPattern(this.opt, kwArgs, this.optionalParams); |
---|
55 | this.series = []; |
---|
56 | this.dyn = []; |
---|
57 | this.datas = {}; |
---|
58 | this.labelKey = []; |
---|
59 | this.oldSeriePoints = {}; |
---|
60 | this.animations = {}; |
---|
61 | }, |
---|
62 | clear: function(){ |
---|
63 | // summary: |
---|
64 | // Clear out all of the information tied to this plot. |
---|
65 | // returns: dojox.charting.plot2d.Spider |
---|
66 | // A reference to this plot for functional chaining. |
---|
67 | this.dirty = true; |
---|
68 | this.dyn = []; |
---|
69 | this.series = []; |
---|
70 | this.datas = {}; |
---|
71 | this.labelKey = []; |
---|
72 | this.oldSeriePoints = {}; |
---|
73 | this.animations = {}; |
---|
74 | return this; // dojox.charting.plot2d.Spider |
---|
75 | }, |
---|
76 | setAxis: function(axis){ |
---|
77 | // summary: |
---|
78 | // Dummy method, since axes are irrelevant with a Spider chart. |
---|
79 | // returns: dojox.charting.plot2d.Spider |
---|
80 | // The reference to this plot for functional chaining. |
---|
81 | return this; // dojox.charting.plot2d.Spider |
---|
82 | }, |
---|
83 | addSeries: function(run){ |
---|
84 | // summary: |
---|
85 | // Add a data series to this plot. |
---|
86 | // run: dojox.charting.Series |
---|
87 | // The series to be added. |
---|
88 | // returns: dojox.charting.plot2d.Base |
---|
89 | // A reference to this plot for functional chaining. |
---|
90 | var matched = false; |
---|
91 | this.series.push(run); |
---|
92 | for(var key in run.data){ |
---|
93 | var val = run.data[key], |
---|
94 | data = this.datas[key]; |
---|
95 | if(data){ |
---|
96 | data.vlist.push(val); |
---|
97 | data.min = Math.min(data.min, val); |
---|
98 | data.max = Math.max(data.max, val); |
---|
99 | }else{ |
---|
100 | this.datas[key] = {min: val, max: val, vlist: [val]}; |
---|
101 | } |
---|
102 | } |
---|
103 | if (this.labelKey.length <= 0) { |
---|
104 | for (var key in run.data) { |
---|
105 | this.labelKey.push(key); |
---|
106 | } |
---|
107 | } |
---|
108 | return this; // dojox.charting.plot2d.Base |
---|
109 | }, |
---|
110 | getSeriesStats: function(){ |
---|
111 | // summary: |
---|
112 | // Calculate the min/max on all attached series in both directions. |
---|
113 | // returns: Object |
---|
114 | // {hmin, hmax, vmin, vmax} min/max in both directions. |
---|
115 | return dc.collectSimpleStats(this.series); |
---|
116 | }, |
---|
117 | calculateAxes: function(dim){ |
---|
118 | // summary: |
---|
119 | // Stub function for running the axis calculations (depricated). |
---|
120 | // dim: Object |
---|
121 | // An object of the form { width, height } |
---|
122 | // returns: dojox.charting.plot2d.Base |
---|
123 | // A reference to this plot for functional chaining. |
---|
124 | this.initializeScalers(dim, this.getSeriesStats()); |
---|
125 | return this; // dojox.charting.plot2d.Base |
---|
126 | }, |
---|
127 | getRequiredColors: function(){ |
---|
128 | // summary: |
---|
129 | // Get how many data series we have, so we know how many colors to use. |
---|
130 | // returns: Number |
---|
131 | // The number of colors needed. |
---|
132 | return this.series.length; // Number |
---|
133 | }, |
---|
134 | initializeScalers: function(dim, stats){ |
---|
135 | // summary: |
---|
136 | // Initializes scalers using attached axes. |
---|
137 | // dim: Object: |
---|
138 | // Size of a plot area in pixels as {width, height}. |
---|
139 | // stats: Object: |
---|
140 | // Min/max of data in both directions as {hmin, hmax, vmin, vmax}. |
---|
141 | // returns: dojox.charting.plot2d.Base |
---|
142 | // A reference to this plot for functional chaining. |
---|
143 | if(this._hAxis){ |
---|
144 | if(!this._hAxis.initialized()){ |
---|
145 | this._hAxis.calculate(stats.hmin, stats.hmax, dim.width); |
---|
146 | } |
---|
147 | this._hScaler = this._hAxis.getScaler(); |
---|
148 | }else{ |
---|
149 | this._hScaler = primitive.buildScaler(stats.hmin, stats.hmax, dim.width); |
---|
150 | } |
---|
151 | if(this._vAxis){ |
---|
152 | if(!this._vAxis.initialized()){ |
---|
153 | this._vAxis.calculate(stats.vmin, stats.vmax, dim.height); |
---|
154 | } |
---|
155 | this._vScaler = this._vAxis.getScaler(); |
---|
156 | }else{ |
---|
157 | this._vScaler = primitive.buildScaler(stats.vmin, stats.vmax, dim.height); |
---|
158 | } |
---|
159 | return this; // dojox.charting.plot2d.Base |
---|
160 | }, |
---|
161 | render: function(dim, offsets){ |
---|
162 | // summary: |
---|
163 | // Render the plot on the chart. |
---|
164 | // dim: Object |
---|
165 | // An object of the form { width, height }. |
---|
166 | // offsets: Object |
---|
167 | // An object of the form { l, r, t, b }. |
---|
168 | // returns: dojox.charting.plot2d.Spider |
---|
169 | // A reference to this plot for functional chaining. |
---|
170 | if(!this.dirty){ return this; } |
---|
171 | this.dirty = false; |
---|
172 | this.cleanGroup(); |
---|
173 | var s = this.group, t = this.chart.theme; |
---|
174 | this.resetEvents(); |
---|
175 | |
---|
176 | if(!this.series || !this.series.length){ |
---|
177 | return this; |
---|
178 | } |
---|
179 | |
---|
180 | // calculate the geometry |
---|
181 | var o = this.opt, ta = t.axis, |
---|
182 | rx = (dim.width - offsets.l - offsets.r) / 2, |
---|
183 | ry = (dim.height - offsets.t - offsets.b) / 2, |
---|
184 | r = Math.min(rx, ry), |
---|
185 | axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma", |
---|
186 | axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma", |
---|
187 | axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver", |
---|
188 | axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black", |
---|
189 | axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver", |
---|
190 | spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver", |
---|
191 | axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2, |
---|
192 | spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2, |
---|
193 | seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2, |
---|
194 | asize = g.normalizedLength(g.splitFontString(axisFont).size), |
---|
195 | startAngle = m._degToRad(o.startAngle), |
---|
196 | start = startAngle, step, filteredRun, slices, labels, shift, labelR, |
---|
197 | outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints, |
---|
198 | ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize, |
---|
199 | spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10, |
---|
200 | axisExtra = 0.2; |
---|
201 | |
---|
202 | if(o.labels){ |
---|
203 | labels = arr.map(this.series, function(s){ |
---|
204 | return s.name; |
---|
205 | }, this); |
---|
206 | shift = df.foldl1(df.map(labels, function(label, i){ |
---|
207 | var font = t.series.font; |
---|
208 | return g._base._getTextBox(label, { |
---|
209 | font: font |
---|
210 | }).w; |
---|
211 | }, this), "Math.max(a, b)") / 2; |
---|
212 | r = Math.min(rx - 2 * shift, ry - asize) + lboffset; |
---|
213 | labelR = r - lboffset; |
---|
214 | } |
---|
215 | if ("radius" in o) { |
---|
216 | r = o.radius; |
---|
217 | labelR = r - lboffset; |
---|
218 | } |
---|
219 | r /= (1+axisExtra); |
---|
220 | var circle = { |
---|
221 | cx: offsets.l + rx, |
---|
222 | cy: offsets.t + ry, |
---|
223 | r: r |
---|
224 | }; |
---|
225 | |
---|
226 | for (var i = this.series.length - 1; i >= 0; i--) { |
---|
227 | var serieEntry = this.series[i]; |
---|
228 | if (!this.dirty && !serieEntry.dirty) { |
---|
229 | t.skip(); |
---|
230 | continue; |
---|
231 | } |
---|
232 | serieEntry.cleanGroup(); |
---|
233 | var run = serieEntry.data; |
---|
234 | if (run !== null) { |
---|
235 | var len = this._getObjectLength(run); |
---|
236 | //construct connect points |
---|
237 | if (!outerPoints || outerPoints.length <= 0) { |
---|
238 | outerPoints = [], innerPoints = [], labelPoints = []; |
---|
239 | this._buildPoints(outerPoints, len, circle, r, start, true); |
---|
240 | this._buildPoints(innerPoints, len, circle, r*ro, start, true); |
---|
241 | this._buildPoints(labelPoints, len, circle, labelR, start); |
---|
242 | if(dv > 2){ |
---|
243 | divisionPoints = [], divisionRadius = []; |
---|
244 | for (var j = 0; j < dv - 2; j++) { |
---|
245 | divisionPoints[j] = []; |
---|
246 | this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true); |
---|
247 | divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1)); |
---|
248 | } |
---|
249 | } |
---|
250 | } |
---|
251 | } |
---|
252 | } |
---|
253 | |
---|
254 | //draw Spider |
---|
255 | //axis |
---|
256 | var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth}, |
---|
257 | spiderStroke = {color: spiderColor, width: spiderWidth}; |
---|
258 | for (var j = outerPoints.length - 1; j >= 0; --j) { |
---|
259 | var point = outerPoints[j], |
---|
260 | st = { |
---|
261 | x: point.x + (point.x - circle.cx) * axisExtra, |
---|
262 | y: point.y + (point.y - circle.cy) * axisExtra |
---|
263 | }, |
---|
264 | nd = { |
---|
265 | x: point.x + (point.x - circle.cx) * axisExtra / 2, |
---|
266 | y: point.y + (point.y - circle.cy) * axisExtra / 2 |
---|
267 | }; |
---|
268 | axisGroup.createLine({ |
---|
269 | x1: circle.cx, |
---|
270 | y1: circle.cy, |
---|
271 | x2: st.x, |
---|
272 | y2: st.y |
---|
273 | }).setStroke(axisStroke); |
---|
274 | //arrow |
---|
275 | this._drawArrow(axisGroup, st, nd, axisStroke); |
---|
276 | } |
---|
277 | |
---|
278 | // draw the label |
---|
279 | var labelGroup = s.createGroup(); |
---|
280 | for (var j = labelPoints.length - 1; j >= 0; --j) { |
---|
281 | var point = labelPoints[j], |
---|
282 | fontWidth = g._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0, |
---|
283 | render = this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx", |
---|
284 | elem = da.createText[render](this.chart, labelGroup, (!domGeom.isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y, |
---|
285 | "middle", this.labelKey[j], axisFont, axisFontColor); |
---|
286 | if (this.opt.htmlLabels) { |
---|
287 | this.htmlElements.push(elem); |
---|
288 | } |
---|
289 | } |
---|
290 | |
---|
291 | //spider web: polygon or circle |
---|
292 | var spiderGroup = s.createGroup(); |
---|
293 | if(spt == "polygon"){ |
---|
294 | spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke); |
---|
295 | spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke); |
---|
296 | if (divisionPoints.length > 0) { |
---|
297 | for (var j = divisionPoints.length - 1; j >= 0; --j) { |
---|
298 | spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke); |
---|
299 | } |
---|
300 | } |
---|
301 | }else{//circle |
---|
302 | var ccount = this._getObjectLength(this.datas); |
---|
303 | spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke); |
---|
304 | spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke); |
---|
305 | if (divisionRadius.length > 0) { |
---|
306 | for (var j = divisionRadius.length - 1; j >= 0; --j) { |
---|
307 | spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke); |
---|
308 | } |
---|
309 | } |
---|
310 | } |
---|
311 | //text |
---|
312 | var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0; |
---|
313 | for(var key in this.datas){ |
---|
314 | var data = this.datas[key], min = data.min, max = data.max, distance = max - min, |
---|
315 | end = start + 2 * Math.PI * k / len; |
---|
316 | for (var i = 0; i < dv; i++) { |
---|
317 | var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end); |
---|
318 | text = this._getLabel(text); |
---|
319 | var fontWidth = g._base._getTextBox(text, {font: axisTickFont}).w || 0, |
---|
320 | render = this.opt.htmlLabels && g.renderer != "vml" ? "html" : "gfx"; |
---|
321 | if (this.opt.htmlLabels) { |
---|
322 | this.htmlElements.push(da.createText[render] |
---|
323 | (this.chart, textGroup, (!domGeom.isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y, |
---|
324 | "start", text, axisTickFont, axisTickFontColor)); |
---|
325 | } |
---|
326 | } |
---|
327 | k++; |
---|
328 | } |
---|
329 | |
---|
330 | //draw series (animation) |
---|
331 | this.chart.seriesShapes = {}; |
---|
332 | var animationConnections = []; |
---|
333 | for (var i = this.series.length - 1; i >= 0; i--) { |
---|
334 | var serieEntry = this.series[i], run = serieEntry.data; |
---|
335 | if (run !== null) { |
---|
336 | //series polygon |
---|
337 | var seriePoints = [], k = 0, tipData = []; |
---|
338 | for(var key in run){ |
---|
339 | var data = this.datas[key], min = data.min, max = data.max, distance = max - min, |
---|
340 | entry = run[key], end = start + 2 * Math.PI * k / len, |
---|
341 | point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end); |
---|
342 | seriePoints.push(point); |
---|
343 | tipData.push({sname: serieEntry.name, key: key, data: entry}); |
---|
344 | k++; |
---|
345 | } |
---|
346 | seriePoints[seriePoints.length] = seriePoints[0]; |
---|
347 | tipData[tipData.length] = tipData[0]; |
---|
348 | var polygonBoundRect = this._getBoundary(seriePoints), |
---|
349 | theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group, |
---|
350 | f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth}; |
---|
351 | f.a = o.seriesFillAlpha; |
---|
352 | serieEntry.dyn = {fill: f, stroke: sk}; |
---|
353 | |
---|
354 | var osps = this.oldSeriePoints[serieEntry.name]; |
---|
355 | var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at); |
---|
356 | this.chart.seriesShapes[serieEntry.name] = cs; |
---|
357 | this.oldSeriePoints[serieEntry.name] = seriePoints; |
---|
358 | |
---|
359 | var po = { |
---|
360 | element: "spider_poly", |
---|
361 | index: i, |
---|
362 | id: "spider_poly_"+serieEntry.name, |
---|
363 | run: serieEntry, |
---|
364 | plot: this, |
---|
365 | shape: cs.poly, |
---|
366 | parent: ts, |
---|
367 | brect: polygonBoundRect, |
---|
368 | cx: circle.cx, |
---|
369 | cy: circle.cy, |
---|
370 | cr: r, |
---|
371 | f: f, |
---|
372 | s: s |
---|
373 | }; |
---|
374 | this._connectEvents(po); |
---|
375 | |
---|
376 | var so = { |
---|
377 | element: "spider_plot", |
---|
378 | index: i, |
---|
379 | id: "spider_plot_"+serieEntry.name, |
---|
380 | run: serieEntry, |
---|
381 | plot: this, |
---|
382 | shape: serieEntry.group |
---|
383 | }; |
---|
384 | this._connectEvents(so); |
---|
385 | |
---|
386 | arr.forEach(cs.circles, function(c, i){ |
---|
387 | var shape = c.getShape(), |
---|
388 | co = { |
---|
389 | element: "spider_circle", |
---|
390 | index: i, |
---|
391 | id: "spider_circle_"+serieEntry.name+i, |
---|
392 | run: serieEntry, |
---|
393 | plot: this, |
---|
394 | shape: c, |
---|
395 | parent: ts, |
---|
396 | tdata: tipData[i], |
---|
397 | cx: seriePoints[i].x, |
---|
398 | cy: seriePoints[i].y, |
---|
399 | f: f, |
---|
400 | s: s |
---|
401 | }; |
---|
402 | this._connectEvents(co); |
---|
403 | }, this); |
---|
404 | } |
---|
405 | } |
---|
406 | return this; // dojox.charting.plot2d.Spider |
---|
407 | }, |
---|
408 | _createSeriesEntry: function(ts, osps, sps, f, sk, r, ro, ms, at){ |
---|
409 | //polygon |
---|
410 | var spoly = ts.createPolyline(osps).setFill(f).setStroke(sk), scircle = []; |
---|
411 | for (var j = 0; j < osps.length; j++) { |
---|
412 | var point = osps[j], cr = ms; |
---|
413 | var circle = ts.createCircle({cx: point.x, cy: point.y, r: cr}).setFill(f).setStroke(sk); |
---|
414 | scircle.push(circle); |
---|
415 | } |
---|
416 | |
---|
417 | var anims = arr.map(sps, function(np, j){ |
---|
418 | // create animation |
---|
419 | var sp = osps[j], |
---|
420 | anim = new baseFx.Animation({ |
---|
421 | duration: 1000, |
---|
422 | easing: at, |
---|
423 | curve: [sp.y, np.y] |
---|
424 | }); |
---|
425 | var spl = spoly, sc = scircle[j]; |
---|
426 | hub.connect(anim, "onAnimate", function(y){ |
---|
427 | //apply poly |
---|
428 | var pshape = spl.getShape(); |
---|
429 | pshape.points[j].y = y; |
---|
430 | spl.setShape(pshape); |
---|
431 | //apply circle |
---|
432 | var cshape = sc.getShape(); |
---|
433 | cshape.cy = y; |
---|
434 | sc.setShape(cshape); |
---|
435 | }); |
---|
436 | return anim; |
---|
437 | }); |
---|
438 | |
---|
439 | var anims1 = arr.map(sps, function(np, j){ |
---|
440 | // create animation |
---|
441 | var sp = osps[j], |
---|
442 | anim = new baseFx.Animation({ |
---|
443 | duration: 1000, |
---|
444 | easing: at, |
---|
445 | curve: [sp.x, np.x] |
---|
446 | }); |
---|
447 | var spl = spoly, sc = scircle[j]; |
---|
448 | hub.connect(anim, "onAnimate", function(x){ |
---|
449 | //apply poly |
---|
450 | var pshape = spl.getShape(); |
---|
451 | pshape.points[j].x = x; |
---|
452 | spl.setShape(pshape); |
---|
453 | //apply circle |
---|
454 | var cshape = sc.getShape(); |
---|
455 | cshape.cx = x; |
---|
456 | sc.setShape(cshape); |
---|
457 | }); |
---|
458 | return anim; |
---|
459 | }); |
---|
460 | var masterAnimation = coreFx.combine(anims.concat(anims1)); //dojo.fx.chain(anims); |
---|
461 | masterAnimation.play(); |
---|
462 | return {group :ts, poly: spoly, circles: scircle}; |
---|
463 | }, |
---|
464 | plotEvent: function(o){ |
---|
465 | // summary: |
---|
466 | // Stub function for use by specific plots. |
---|
467 | // o: Object |
---|
468 | // An object intended to represent event parameters. |
---|
469 | var runName = o.id ? o.id : "default", a; |
---|
470 | if (runName in this.animations) { |
---|
471 | a = this.animations[runName]; |
---|
472 | a.anim && a.anim.stop(true); |
---|
473 | } else { |
---|
474 | a = this.animations[runName] = {}; |
---|
475 | } |
---|
476 | if(o.element == "spider_poly"){ |
---|
477 | if(!a.color){ |
---|
478 | var color = o.shape.getFill(); |
---|
479 | if(!color || !(color instanceof Color)){ |
---|
480 | return; |
---|
481 | } |
---|
482 | a.color = { |
---|
483 | start: color, |
---|
484 | end: transColor(color) |
---|
485 | }; |
---|
486 | } |
---|
487 | var start = a.color.start, end = a.color.end; |
---|
488 | if(o.type == "onmouseout"){ |
---|
489 | // swap colors |
---|
490 | var t = start; start = end; end = t; |
---|
491 | } |
---|
492 | a.anim = gfxfx.animateFill({ |
---|
493 | shape: o.shape, |
---|
494 | duration: 800, |
---|
495 | easing: easing.backOut, |
---|
496 | color: {start: start, end: end} |
---|
497 | }); |
---|
498 | a.anim.play(); |
---|
499 | }else if(o.element == "spider_circle"){ |
---|
500 | var init, scale, defaultScale = 1.5; |
---|
501 | if(o.type == "onmouseover"){ |
---|
502 | init = m.identity; |
---|
503 | scale = defaultScale; |
---|
504 | //show tooltip |
---|
505 | var aroundRect = {type: "rect"}; |
---|
506 | aroundRect.x = o.cx; |
---|
507 | aroundRect.y = o.cy; |
---|
508 | aroundRect.width = aroundRect.height = 1; |
---|
509 | var lt = html.coords(this.chart.node, true); |
---|
510 | aroundRect.x += lt.x; |
---|
511 | aroundRect.y += lt.y; |
---|
512 | aroundRect.x = Math.round(aroundRect.x); |
---|
513 | aroundRect.y = Math.round(aroundRect.y); |
---|
514 | aroundRect.width = Math.ceil(aroundRect.width); |
---|
515 | aroundRect.height = Math.ceil(aroundRect.height); |
---|
516 | this.aroundRect = aroundRect; |
---|
517 | var position = ["after", "before"]; |
---|
518 | dc.doIfLoaded("dijit/Tooltip", dojo.hitch(this, function(Tooltip){ |
---|
519 | Tooltip.show(o.tdata.sname + "<br/>" + o.tdata.key + "<br/>" + o.tdata.data, this.aroundRect, position); |
---|
520 | })); |
---|
521 | }else{ |
---|
522 | init = m.scaleAt(defaultScale, o.cx, o.cy); |
---|
523 | scale = 1/defaultScale; |
---|
524 | dc.doIfLoaded("dijit/Tooltip", dojo.hitch(this, function(Tooltip){ |
---|
525 | this.aroundRect && Tooltip.hide(this.aroundRect); |
---|
526 | })); |
---|
527 | } |
---|
528 | var cs = o.shape.getShape(), |
---|
529 | init = m.scaleAt(defaultScale, cs.cx, cs.cy), |
---|
530 | kwArgs = { |
---|
531 | shape: o.shape, |
---|
532 | duration: 200, |
---|
533 | easing: easing.backOut, |
---|
534 | transform: [ |
---|
535 | {name: "scaleAt", start: [1, cs.cx, cs.cy], end: [scale, cs.cx, cs.cy]}, |
---|
536 | init |
---|
537 | ] |
---|
538 | }; |
---|
539 | a.anim = gfxfx.animateTransform(kwArgs); |
---|
540 | a.anim.play(); |
---|
541 | }else if(o.element == "spider_plot"){ |
---|
542 | //dojo gfx function "moveToFront" not work in IE |
---|
543 | if (o.type == "onmouseover" && !has("ie")) { |
---|
544 | o.shape.moveToFront(); |
---|
545 | } |
---|
546 | } |
---|
547 | }, |
---|
548 | _getBoundary: function(points){ |
---|
549 | var xmax = points[0].x, |
---|
550 | xmin = points[0].x, |
---|
551 | ymax = points[0].y, |
---|
552 | ymin = points[0].y; |
---|
553 | for(var i = 0; i < points.length; i++){ |
---|
554 | var point = points[i]; |
---|
555 | xmax = Math.max(point.x, xmax); |
---|
556 | ymax = Math.max(point.y, ymax); |
---|
557 | xmin = Math.min(point.x, xmin); |
---|
558 | ymin = Math.min(point.y, ymin); |
---|
559 | } |
---|
560 | return { |
---|
561 | x: xmin, |
---|
562 | y: ymin, |
---|
563 | width: xmax - xmin, |
---|
564 | height: ymax - ymin |
---|
565 | }; |
---|
566 | }, |
---|
567 | |
---|
568 | _drawArrow: function(s, start, end, stroke){ |
---|
569 | var len = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)), |
---|
570 | sin = (end.y - start.y)/len, cos = (end.x - start.x)/len, |
---|
571 | point2 = {x: end.x + (len/3)*(-sin), y: end.y + (len/3)*cos}, |
---|
572 | point3 = {x: end.x + (len/3)*sin, y: end.y + (len/3)*(-cos)}; |
---|
573 | s.createPolyline([start, point2, point3]).setFill(stroke.color).setStroke(stroke); |
---|
574 | }, |
---|
575 | |
---|
576 | _buildPoints: function(points, count, circle, radius, angle, recursive){ |
---|
577 | for (var i = 0; i < count; i++) { |
---|
578 | var end = angle + 2 * Math.PI * i / count; |
---|
579 | points.push(this._getCoordinate(circle, radius, end)); |
---|
580 | } |
---|
581 | if(recursive){ |
---|
582 | points.push(this._getCoordinate(circle, radius, angle + 2 * Math.PI)); |
---|
583 | } |
---|
584 | }, |
---|
585 | |
---|
586 | _getCoordinate: function(circle, radius, angle){ |
---|
587 | return { |
---|
588 | x: circle.cx + radius * Math.cos(angle), |
---|
589 | y: circle.cy + radius * Math.sin(angle) |
---|
590 | } |
---|
591 | }, |
---|
592 | |
---|
593 | _getObjectLength: function(obj){ |
---|
594 | var count = 0; |
---|
595 | if(lang.isObject(obj)){ |
---|
596 | for(var key in obj){ |
---|
597 | count++; |
---|
598 | } |
---|
599 | } |
---|
600 | return count; |
---|
601 | }, |
---|
602 | |
---|
603 | // utilities |
---|
604 | _getLabel: function(number){ |
---|
605 | return dc.getLabel(number, this.opt.fixed, this.opt.precision); |
---|
606 | } |
---|
607 | }); |
---|
608 | |
---|
609 | function transColor(color){ |
---|
610 | var a = new dxcolor.Color(color), |
---|
611 | x = a.toHsl(); |
---|
612 | if(x.s == 0){ |
---|
613 | x.l = x.l < 50 ? 100 : 0; |
---|
614 | }else{ |
---|
615 | x.s = 100; |
---|
616 | if(x.l < 50){ |
---|
617 | x.l = 75; |
---|
618 | }else if(x.l > 75){ |
---|
619 | x.l = 50; |
---|
620 | }else{ |
---|
621 | x.l = x.l - 50 > 75 - x.l ? |
---|
622 | 50 : 75; |
---|
623 | } |
---|
624 | } |
---|
625 | var color = dxcolor.fromHsl(x); |
---|
626 | color.a = 0.7; |
---|
627 | return color; |
---|
628 | } |
---|
629 | |
---|
630 | return Spider; // dojox.plot2d.Spider |
---|
631 | }); |
---|