source: Dev/branches/rest-dojo-ui/client/dojox/charting/plot2d/Spider.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 20.3 KB
Line 
1define(["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/*=====
10var Element = dojox.charting.Element;
11var 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});
Note: See TracBrowser for help on using the repository browser.