source: Dev/branches/rest-dojo-ui/client/dojox/charting/Element.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: 10.8 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/array", "dojo/dom-construct","dojo/_base/declare", "dojox/gfx"],
2        function(lang, arr, domConstruct, declare, gfx){
3       
4        return declare("dojox.charting.Element", null, {
5                //      summary:
6                //              A base class that is used to build other elements of a chart, such as
7                //              a series.
8                //      chart: dojox.charting.Chart
9                //              The parent chart for this element.
10                //      group: dojox.gfx.Group
11                //              The visual GFX group representing this element.
12                //      htmlElement: Array
13                //              Any DOMNodes used as a part of this element (such as HTML-based labels).
14                //      dirty: Boolean
15                //              A flag indicating whether or not this element needs to be rendered.
16       
17                chart: null,
18                group: null,
19                htmlElements: null,
20                dirty: true,
21       
22                constructor: function(chart){
23                        //      summary:
24                        //              Creates a new charting element.
25                        //      chart: dojox.charting.Chart
26                        //              The chart that this element belongs to.
27                        this.chart = chart;
28                        this.group = null;
29                        this.htmlElements = [];
30                        this.dirty = true;
31                        this.trailingSymbol = "...";
32                        this._events = [];
33                },
34                createGroup: function(creator){
35                        //      summary:
36                        //              Convenience function to create a new dojox.gfx.Group.
37                        //      creator: dojox.gfx.Surface?
38                        //              An optional surface in which to create this group.
39                        //      returns: dojox.charting.Element
40                        //              A reference to this object for functional chaining.
41                        if(!creator){ creator = this.chart.surface; }
42                        if(!this.group){
43                                this.group = creator.createGroup();
44                        }
45                        return this;    //      dojox.charting.Element
46                },
47                purgeGroup: function(){
48                        //      summary:
49                        //              Clear any elements out of our group, and destroy the group.
50                        //      returns: dojox.charting.Element
51                        //              A reference to this object for functional chaining.
52                        this.destroyHtmlElements();
53                        if(this.group){
54                                this.group.clear();
55                                this.group.removeShape();
56                                this.group = null;
57                        }
58                        this.dirty = true;
59                        if(this._events.length){
60                                arr.forEach(this._events, function(item){
61                                        item.shape.disconnect(item.handle);
62                                });
63                                this._events = [];
64                        }
65                        return this;    //      dojox.charting.Element
66                },
67                cleanGroup: function(creator){
68                        //      summary:
69                        //              Clean any elements (HTML or GFX-based) out of our group, and create a new one.
70                        //      creator: dojox.gfx.Surface?
71                        //              An optional surface to work with.
72                        //      returns: dojox.charting.Element
73                        //              A reference to this object for functional chaining.
74                        this.destroyHtmlElements();
75                        if(!creator){ creator = this.chart.surface; }
76                        if(this.group){
77                                this.group.clear();
78                        }else{
79                                this.group = creator.createGroup();
80                        }
81                        this.dirty = true;
82                        return this;    //      dojox.charting.Element
83                },
84                destroyHtmlElements: function(){
85                        //      summary:
86                        //              Destroy any DOMNodes that may have been created as a part of this element.
87                        if(this.htmlElements.length){
88                                arr.forEach(this.htmlElements, domConstruct.destroy);
89                                this.htmlElements = [];
90                        }
91                },
92                destroy: function(){
93                        //      summary:
94                        //              API addition to conform to the rest of the Dojo Toolkit's standard.
95                        this.purgeGroup();
96                },
97                //text utilities
98                getTextWidth: function(s, font){
99                        return gfx._base._getTextBox(s, {font: font}).w || 0;
100                },
101                getTextWithLimitLength: function(s, font, limitWidth, truncated){
102                        //      summary:
103                        //              Get the truncated string based on the limited width in px(dichotomy algorithm)
104                        //      s: String?
105                        //              candidate text.
106                        //      font: String?
107                        //              text's font style.
108                        //      limitWidth: Number?
109                        //              text limited width in px.
110                        //      truncated: Boolean?
111                        //              whether the input text(s) has already been truncated.
112                        //      returns: Object
113                        //              {
114                        //                      text: processed text, maybe truncated or not
115                        //                      truncated: whether text has been truncated
116                        //              }
117                        if (!s || s.length <= 0) {
118                                return {
119                                        text: "",
120                                        truncated: truncated || false
121                                };
122                        }
123                        if(!limitWidth || limitWidth <= 0){
124                                return {
125                                        text: s,
126                                        truncated: truncated || false
127                                };
128                        }
129                        var delta = 2,
130                                //golden section for dichotomy algorithm
131                                trucPercentage = 0.618,
132                                minStr = s.substring(0,1) + this.trailingSymbol,
133                                minWidth = this.getTextWidth(minStr, font);
134                        if (limitWidth <= minWidth) {
135                                return {
136                                        text: minStr,
137                                        truncated: true
138                                };
139                        }
140                        var width = this.getTextWidth(s, font);
141                        if(width <= limitWidth){
142                                return {
143                                        text: s,
144                                        truncated: truncated || false
145                                };
146                        }else{
147                                var begin = 0,
148                                        end = s.length;
149                                while(begin < end){
150                                        if(end - begin <= delta ){
151                                                while (this.getTextWidth(s.substring(0, begin) + this.trailingSymbol, font) > limitWidth) {
152                                                        begin -= 1;
153                                                }
154                                                return {
155                                                        text: (s.substring(0,begin) + this.trailingSymbol),
156                                                        truncated: true
157                                                };
158                                        }
159                                        var index = begin + Math.round((end - begin) * trucPercentage),
160                                                widthIntercepted = this.getTextWidth(s.substring(0, index), font);
161                                        if(widthIntercepted < limitWidth){
162                                                begin = index;
163                                                end = end;
164                                        }else{
165                                                begin = begin;
166                                                end = index;
167                                        }
168                                }
169                        }
170                },
171                getTextWithLimitCharCount: function(s, font, wcLimit, truncated){
172                        //      summary:
173                        //              Get the truncated string based on the limited character count(dichotomy algorithm)
174                        //      s: String?
175                        //              candidate text.
176                        //      font: String?
177                        //              text's font style.
178                        //      wcLimit: Number?
179                        //              text limited character count.
180                        //      truncated: Boolean?
181                        //              whether the input text(s) has already been truncated.
182                        //      returns: Object
183                        //              {
184                        //                      text: processed text, maybe truncated or not
185                        //                      truncated: whether text has been truncated
186                        //              }
187                        if (!s || s.length <= 0) {
188                                return {
189                                        text: "",
190                                        truncated: truncated || false
191                                };
192                        }
193                        if(!wcLimit || wcLimit <= 0 || s.length <= wcLimit){
194                                return {
195                                        text: s,
196                                        truncated: truncated || false
197                                };
198                        }
199                        return {
200                                text: s.substring(0, wcLimit) + this.trailingSymbol,
201                                truncated: true
202                        };
203                },
204                // fill utilities
205                _plotFill: function(fill, dim, offsets){
206                        // process a plot-wide fill
207                        if(!fill || !fill.type || !fill.space){
208                                return fill;
209                        }
210                        var space = fill.space;
211                        switch(fill.type){
212                                case "linear":
213                                        if(space === "plot" || space === "shapeX" || space === "shapeY"){
214                                                // clone a fill so we can modify properly directly
215                                                fill = gfx.makeParameters(gfx.defaultLinearGradient, fill);
216                                                fill.space = space;
217                                                // process dimensions
218                                                if(space === "plot" || space === "shapeX"){
219                                                        // process Y
220                                                        var span = dim.height - offsets.t - offsets.b;
221                                                        fill.y1 = offsets.t + span * fill.y1 / 100;
222                                                        fill.y2 = offsets.t + span * fill.y2 / 100;
223                                                }
224                                                if(space === "plot" || space === "shapeY"){
225                                                        // process X
226                                                        var span = dim.width - offsets.l - offsets.r;
227                                                        fill.x1 = offsets.l + span * fill.x1 / 100;
228                                                        fill.x2 = offsets.l + span * fill.x2 / 100;
229                                                }
230                                        }
231                                        break;
232                                case "radial":
233                                        if(space === "plot"){
234                                                // this one is used exclusively for scatter charts
235                                                // clone a fill so we can modify properly directly
236                                                fill = gfx.makeParameters(gfx.defaultRadialGradient, fill);
237                                                fill.space = space;
238                                                // process both dimensions
239                                                var spanX = dim.width  - offsets.l - offsets.r,
240                                                        spanY = dim.height - offsets.t - offsets.b;
241                                                fill.cx = offsets.l + spanX * fill.cx / 100;
242                                                fill.cy = offsets.t + spanY * fill.cy / 100;
243                                                fill.r  = fill.r * Math.sqrt(spanX * spanX + spanY * spanY) / 200;
244                                        }
245                                        break;
246                                case "pattern":
247                                        if(space === "plot" || space === "shapeX" || space === "shapeY"){
248                                                // clone a fill so we can modify properly directly
249                                                fill = gfx.makeParameters(gfx.defaultPattern, fill);
250                                                fill.space = space;
251                                                // process dimensions
252                                                if(space === "plot" || space === "shapeX"){
253                                                        // process Y
254                                                        var span = dim.height - offsets.t - offsets.b;
255                                                        fill.y = offsets.t + span * fill.y / 100;
256                                                        fill.height = span * fill.height / 100;
257                                                }
258                                                if(space === "plot" || space === "shapeY"){
259                                                        // process X
260                                                        var span = dim.width - offsets.l - offsets.r;
261                                                        fill.x = offsets.l + span * fill.x / 100;
262                                                        fill.width = span * fill.width / 100;
263                                                }
264                                        }
265                                        break;
266                        }
267                        return fill;
268                },
269                _shapeFill: function(fill, bbox){
270                        // process shape-specific fill
271                        if(!fill || !fill.space){
272                                return fill;
273                        }
274                        var space = fill.space;
275                        switch(fill.type){
276                                case "linear":
277                                        if(space === "shape" || space === "shapeX" || space === "shapeY"){
278                                                // clone a fill so we can modify properly directly
279                                                fill = gfx.makeParameters(gfx.defaultLinearGradient, fill);
280                                                fill.space = space;
281                                                // process dimensions
282                                                if(space === "shape" || space === "shapeX"){
283                                                        // process X
284                                                        var span = bbox.width;
285                                                        fill.x1 = bbox.x + span * fill.x1 / 100;
286                                                        fill.x2 = bbox.x + span * fill.x2 / 100;
287                                                }
288                                                if(space === "shape" || space === "shapeY"){
289                                                        // process Y
290                                                        var span = bbox.height;
291                                                        fill.y1 = bbox.y + span * fill.y1 / 100;
292                                                        fill.y2 = bbox.y + span * fill.y2 / 100;
293                                                }
294                                        }
295                                        break;
296                                case "radial":
297                                        if(space === "shape"){
298                                                // this one is used exclusively for bubble charts and pie charts
299                                                // clone a fill so we can modify properly directly
300                                                fill = gfx.makeParameters(gfx.defaultRadialGradient, fill);
301                                                fill.space = space;
302                                                // process both dimensions
303                                                fill.cx = bbox.x + bbox.width  / 2;
304                                                fill.cy = bbox.y + bbox.height / 2;
305                                                fill.r  = fill.r * bbox.width  / 200;
306                                        }
307                                        break;
308                                case "pattern":
309                                        if(space === "shape" || space === "shapeX" || space === "shapeY"){
310                                                // clone a fill so we can modify properly directly
311                                                fill = gfx.makeParameters(gfx.defaultPattern, fill);
312                                                fill.space = space;
313                                                // process dimensions
314                                                if(space === "shape" || space === "shapeX"){
315                                                        // process X
316                                                        var span = bbox.width;
317                                                        fill.x = bbox.x + span * fill.x / 100;
318                                                        fill.width = span * fill.width / 100;
319                                                }
320                                                if(space === "shape" || space === "shapeY"){
321                                                        // process Y
322                                                        var span = bbox.height;
323                                                        fill.y = bbox.y + span * fill.y / 100;
324                                                        fill.height = span * fill.height / 100;
325                                                }
326                                        }
327                                        break;
328                        }
329                        return fill;
330                },
331                _pseudoRadialFill: function(fill, center, radius, start, end){
332                        // process pseudo-radial fills
333                        if(!fill || fill.type !== "radial" || fill.space !== "shape"){
334                                return fill;
335                        }
336                        // clone and normalize fill
337                        var space = fill.space;
338                        fill = gfx.makeParameters(gfx.defaultRadialGradient, fill);
339                        fill.space = space;
340                        if(arguments.length < 4){
341                                // process both dimensions
342                                fill.cx = center.x;
343                                fill.cy = center.y;
344                                fill.r  = fill.r * radius / 100;
345                                return fill;
346                        }
347                        // convert to a linear gradient
348                        var angle = arguments.length < 5 ? start : (end + start) / 2;
349                        return {
350                                type: "linear",
351                                x1: center.x,
352                                y1: center.y,
353                                x2: center.x + fill.r * radius * Math.cos(angle) / 100,
354                                y2: center.y + fill.r * radius * Math.sin(angle) / 100,
355                                colors: fill.colors
356                        };
357                        return fill;
358                }
359        });
360});
Note: See TracBrowser for help on using the repository browser.