source: Dev/trunk/src/client/dojox/charting/Element.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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