source: Dev/trunk/src/client/dojox/treemap/TreeMap.js @ 529

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

Added Dojo 1.9.3 release.

File size: 23.5 KB
Line 
1define(["dojo/_base/array", "dojo/_base/lang", "dojo/_base/declare", "dojo/_base/event", "dojo/_base/Color", "dojo/touch",
2                "dojo/when", "dojo/on", "dojo/query", "dojo/dom-construct", "dojo/dom-geometry", "dojo/dom-class", "dojo/dom-style",
3                "./_utils", "dijit/_WidgetBase", "dojox/widget/_Invalidating", "dojox/widget/Selection",
4                "dojo/_base/sniff", "dojo/uacss"],
5        function(arr, lang, declare, event, Color, touch, when, on, query, domConstruct, domGeom, domClass, domStyle,
6                utils, _WidgetBase, _Invalidating, Selection, has){
7
8        return declare("dojox.treemap.TreeMap", [_WidgetBase, _Invalidating, Selection], {
9                // summary:
10                //              A treemap widget.
11               
12                baseClass: "dojoxTreeMap",
13               
14                // store: dojo/store/api/Store
15                //              The store that contains the items to display.
16                store: null,
17               
18                // query: Object
19                //              A query that can be passed to when querying the store.
20                query: {},
21
22                // queryOptions: dojo/store/api/Store.QueryOptions?
23                //              Options to be applied when querying the store.
24                queryOptions: null,
25               
26                // itemToRenderer: [protected] Object
27                //              The associated array item to renderer list.
28                itemToRenderer: null,
29
30                // Data
31                _dataChanged: false,
32       
33                // rootItem: Object
34                //              The root item of the treemap, that is the first visible item.
35                //              If null the entire treemap hierarchy is shown. 
36                //              Default is null.
37                rootItem: null,
38                _rootItemChanged: false,
39       
40                // tooltipAttr: String
41                //              The attribute of the store item that contains the tooltip text of a treemap cell.       
42                //              Default is "".
43                tooltipAttr: "",
44       
45                // areaAttr: String
46                //              The attribute of the store item that contains the data used to compute the area of a treemap cell.     
47                //              Default is "".
48                areaAttr: "",
49                _areaChanged: false,
50       
51                // labelAttr: String
52                //              The attribute of the store item that contains the label of a treemap cell.     
53                //              Default is "label".
54                labelAttr: "label",
55               
56                // labelThreshold: Number
57                //              The starting depth level at which the labels are not displayed anymore on cells. 
58                //              If NaN no threshold is applied. The depth is the visual depth of the items on the screen not
59                //              in the data (i.e. after drill down the depth of an item might change).
60                //              Default is NaN.
61                labelThreshold: NaN,
62               
63                // colorAttr: String
64                //              The attribute of the store item that contains the data used to compute the color of a treemap cell.
65                //              Default is "".
66                colorAttr: "",
67                // colorModel: dojox/color/api/ColorModel
68                //              The optional color model that converts data to color.   
69                //              Default is null.
70                colorModel: null,
71                _coloringChanged: false,
72               
73                // groupAttrs: Array
74                //              An array of data attributes used to group data in the treemap. 
75                //              Default is [].
76                groupAttrs: [],
77
78                // groupFuncs: Array
79                //              An array of grouping functions used to group data in the treemap.
80                //              When null, groupAttrs is to compute grouping functions.
81                //              Default is null.
82                groupFuncs: null,
83
84        _groupFuncs: null,
85                _groupingChanged: false,
86       
87                constructor: function(){
88                        this.itemToRenderer = {};
89                        this.invalidatingProperties = [ "colorModel", "groupAttrs", "groupFuncs", "areaAttr", "areaFunc",
90                                "labelAttr", "labelFunc", "labelThreshold", "tooltipAttr", "tooltipFunc",
91                                "colorAttr", "colorFunc", "rootItem" ];
92                },
93               
94                getIdentity: function(item){
95                        return item.__treeID?item.__treeID:this.store.getIdentity(item);
96                },
97       
98                resize: function(box){
99                        if(box){
100                                domGeom.setMarginBox(this.domNode, box);
101                                this.invalidateRendering();                                             
102                        }
103                },
104               
105                postCreate: function(){
106                        this.inherited(arguments);
107                        this.own(on(this.domNode, "mouseover", lang.hitch(this, this._onMouseOver)));
108                        this.own(on(this.domNode, "mouseout", lang.hitch(this, this._onMouseOut)));
109                        this.own(on(this.domNode, touch.release, lang.hitch(this, this._onMouseUp)));
110                        this.domNode.setAttribute("role", "presentation");
111                        this.domNode.setAttribute("aria-label", "treemap");
112                },
113               
114                buildRendering: function(){
115                        this.inherited(arguments);
116                        this.refreshRendering();
117                },
118       
119                refreshRendering: function(){
120                        var forceCreate = false;
121       
122                        if(this._dataChanged){
123                                this._dataChanged = false;
124                                this._groupingChanged = true;
125                                this._coloringChanged = true;
126                        }
127       
128                        if(this._groupingChanged){
129                                this._groupingChanged = false;
130                                this._set("rootItem", null);
131                                this._updateTreeMapHierarchy();
132                                forceCreate = true;
133                        }
134       
135                        if(this._rootItemChanged){
136                                this._rootItemChanged = false;
137                                forceCreate = true;
138                        }
139       
140                        if(this._coloringChanged){
141                                this._coloringChanged = false;                 
142                                if(this.colorModel != null && this._data != null && this.colorModel.initialize){
143                                        this.colorModel.initialize(this._data, lang.hitch(this, function(item){
144                                                return this.colorFunc(item, this.store);
145                                        }));
146                                }
147                        }
148       
149                        if(this._areaChanged){
150                                this._areaChanged = false;
151                                this._removeAreaForGroup();
152                        }
153       
154                        if(this.domNode == undefined || this._items == null){
155                                return;
156                        }
157                       
158                        if(forceCreate){
159                                domConstruct.empty(this.domNode);
160                        }
161       
162                        var rootItem = this.rootItem;
163       
164                        if(rootItem != null){
165                                if(this._isLeaf(rootItem)){
166                                        rootItem = this._getRenderer(rootItem).parentItem;
167                                }
168                        }
169
170                        var box = domGeom.getMarginBox(this.domNode);
171                        if(rootItem != null){
172                                this._buildRenderer(this.domNode, null, rootItem, {
173                                        x: box.l, y: box.t, w: box.w, h: box.h
174                                }, 0, forceCreate);
175                        }else{
176                                this._buildChildrenRenderers(this.domNode, rootItem?rootItem:{ __treeRoot: true, children : this._items },
177                                        0, forceCreate, box);
178                        }
179                },
180       
181                _setRootItemAttr: function(value){
182                        this._rootItemChanged = true;
183                        this._set("rootItem", value);
184                },
185       
186                _setStoreAttr: function(value){
187                        var r;
188                        if(this._observeHandler){
189                                this._observeHandler.remove();
190                                this._observeHandler = null;
191                        }
192                        if(value != null){
193                                var results = value.query(this.query, this.queryOptions);
194                                if(results.observe){
195                                        // user asked us to observe the store
196                                        this._observeHandler = results.observe(lang.hitch(this, this._updateItem), true);
197                                }                               
198                                r = when(results, lang.hitch(this, this._initItems));
199                        }else{
200                                r = this._initItems([]);
201                        }
202                        this._set("store", value);
203                        return r;
204                },
205       
206                _initItems: function(items){
207                        this._dataChanged = true;
208                        this._data = items;
209                        this.invalidateRendering();
210                        return items;
211                },
212
213                _updateItem: function(item, previousIndex, newIndex){
214                        if(previousIndex!=-1){
215                                if(newIndex!=previousIndex){
216                                        // this is a remove or a move
217                                        this._data.splice(previousIndex, 1);
218                                }else{
219                                        // this is a put, previous and new index identical
220                                        // we don't know what has change exactly with store API
221                                        this._data[newIndex] = item;
222                                }
223                        }else if(newIndex!=-1){
224                                // this is a add
225                                this._data.splice(newIndex, 0, item);
226                        }
227                        // as we have no details let's refresh everything...
228                        this._dataChanged = true;                       
229                        this.invalidateRendering();
230                },
231       
232                _setGroupAttrsAttr: function(value){
233                        this._groupingChanged = true;
234                        if(this.groupFuncs == null){
235                                if(value !=null){
236                                        this._groupFuncs = arr.map(value, function(attr){
237                                                return function(item){
238                                                        return item[attr];
239                                                };
240                                        });
241                                }else{
242                                        this._groupFuncs = null;
243                                }
244                        }
245                        this._set("groupAttrs", value);
246                },
247
248        _setGroupFuncsAttr: function(value){
249                        this._groupingChanged = true;
250                        this._set("groupFuncs", this._groupFuncs = value);
251                        if(value == null && this.groupAttrs != null){
252                                this._groupFuncs = arr.map(this.groupAttrs, function(attr){
253                                        return function(item){
254                                                return item[attr];
255                                        };
256                                });
257                        }
258                },
259
260                _setAreaAttrAttr: function(value){
261                        this._areaChanged = true;
262                        this._set("areaAttr", value);
263                },
264       
265                // areaFunc: Function
266                //              A function that returns the value use to compute the area of cell from a store item.
267                //              Default implementation is using areaAttr.       
268                areaFunc: function(/*Object*/ item, /*dojo/store/api/Store*/ store){
269                        return (this.areaAttr && this.areaAttr.length > 0)?parseFloat(item[this.areaAttr]):1;
270                },
271               
272                _setAreaFuncAttr: function(value){
273                        this._areaChanged = true;
274                        this._set("areaFunc", value);
275                },
276
277                // labelFunc: Function
278                //              A function that returns the label of cell from a store item.   
279                //              Default implementation is using labelAttr.
280                labelFunc: function(/*Object*/ item, /*dojo/store/api/Store*/ store){
281                        var label = (this.labelAttr && this.labelAttr.length > 0)?item[this.labelAttr]:null;
282                        return label?label.toString():null;
283                },
284       
285                // tooltipFunc: Function
286                //              A function that returns the tooltip of cell from a store item. 
287                //              Default implementation is using tooltipAttr.
288                tooltipFunc: function(/*Object*/ item, /*dojo/store/api/Store*/ store){
289                        var tooltip = (this.tooltipAttr && this.tooltipAttr.length > 0)?item[this.tooltipAttr]:null;
290                        return tooltip?tooltip.toString():null;
291                },
292
293                _setColorModelAttr: function(value){
294                        this._coloringChanged = true;
295                        this._set("colorModel", value);
296                },
297       
298                _setColorAttrAttr: function(value){
299                        this._coloringChanged = true;
300                        this._set("colorAttr", value);
301                },
302       
303                // colorFunc: Function
304                //              A function that returns from a store item the color value of cell or the value used by the
305                //              ColorModel to compute the cell color. If a color must be returned it must be in form accepted by the
306                //              dojo/_base/Color constructor. If a value must be returned it must be a Number.
307                //              Default implementation is using colorAttr.
308                colorFunc: function(/*Object*/ item, /*dojo/store/api/Store*/ store){
309                        var color = (this.colorAttr && this.colorAttr.length > 0)?item[this.colorAttr]:0;
310                        if(color == null){
311                                color = 0;
312                        }
313                        return parseFloat(color);
314                },
315               
316                _setColorFuncAttr: function(value){
317                        this._coloringChanged = true;
318                        this._set("colorFunc", value);
319                },
320               
321                createRenderer: function(item, level, kind){
322                        // summary:
323                        //              Creates an item renderer of the specified kind. This is called only when the treemap
324                        //              is created. Default implementation always create div nodes. It also sets overflow
325                        //              to hidden and position to absolute on non-header renderers.
326                        // item: Object
327                        //              The data item.
328                        // level: Number
329                        //              The item depth level.           
330                        // kind: String
331                        //              The specified kind. This can either be "leaf", "group", "header" or "content".
332                        // returns: DomNode
333                        //              The renderer use for the specified kind.
334                        // tags:
335                        //              protected                                       
336                        var div = domConstruct.create("div");
337                        if(kind != "header"){
338                                domStyle.set(div, "overflow", "hidden");
339                                domStyle.set(div, "position", "absolute");                                     
340                        }
341                        return div;
342                },
343               
344                styleRenderer: function(renderer, item, level, kind){
345                        // summary:
346                        //              Style the item renderer. This is called each time the treemap is refreshed.
347                        //              For leaf items it colors them with the color computed from the color model.
348                        //              For other items it does nothing.
349                        // renderer: DomNode
350                        //              The item renderer.
351                        // item: Object
352                        //              The data item.
353                        // level: Number
354                        //              The item depth level.
355                        // kind: String
356                        //              The specified kind. This can either be "leaf", "group", "header" or "content".
357                        // tags:
358                        //              protected
359                        switch(kind){
360                                case "leaf":
361                                        domStyle.set(renderer, "background", this.getColorForItem(item).toHex());
362                                case "header":
363                                        var label = this.getLabelForItem(item);
364                                        if(label && (isNaN(this.labelThreshold) || level < this.labelThreshold)){
365                                                renderer.innerHTML = label;
366                                        }else{
367                                                domConstruct.empty(renderer);
368                                        }
369                                        break;
370                                default:
371                               
372                        }                               
373                },
374               
375                _updateTreeMapHierarchy: function(){
376                        if(this._data == null){
377                                return;
378                        }
379                        if(this._groupFuncs != null && this._groupFuncs.length > 0){
380                                this._items = utils.group(this._data, this._groupFuncs, lang.hitch(this, this._getAreaForItem)).children;
381                        }else{
382                                this._items = this._data;
383                        }
384                },
385       
386                _removeAreaForGroup: function(item){
387                        var children;
388                        if(item != null){
389                                if(item.__treeValue){
390                                        delete item.__treeValue;
391                                        children = item.children;
392                                }else{
393                                        // not a grouping item
394                                        return;
395                                }
396                        }else{
397                                children = this._items;
398                        }
399                        if(children){
400                                for(var i = 0; i < children.length; ++i){
401                                        this._removeAreaForGroup(children[i]);
402                                }
403                        }
404                },
405       
406                _getAreaForItem: function(item){
407                        var area = this.areaFunc(item, this.store);
408                        return isNaN(area) ? 0 : area;
409                },
410
411                _computeAreaForItem: function(item){
412                        var value;
413                        if(item.__treeID){ // group
414                                value = item.__treeValue;
415                                if(!value){
416                                        value = 0;
417                                        var children = item.children;
418                                        for(var i = 0; i < children.length; ++i){
419                                                value += this._computeAreaForItem(children[i]);
420                                        }
421                                        item.__treeValue = value;
422                                }
423                        }else{
424                                value = this._getAreaForItem(item);
425                        }
426                        return value;
427                },
428       
429                getColorForItem: function(item){
430                        // summary:
431                        //              Returns the color for a given item. This either use the colorModel if not null
432                        //              or just the result of the colorFunc.
433                        // item: Object
434                        //              The data item.
435                        // tags:
436                        //              protected       
437                        var value = this.colorFunc(item, this.store);
438                        if(this.colorModel != null){
439                                return this.colorModel.getColor(value);
440                        }else{
441                                return new Color(value);
442                        }
443                },
444       
445                getLabelForItem: function(item){
446                        // summary:
447                        //              Returns the label for a given item.
448                        // item: Object
449                        //              The data item.
450                        // tags:
451                        //              protected       
452                        return item.__treeName?item.__treeName:this.labelFunc(item, this.store);
453                },
454       
455                _buildChildrenRenderers: function(domNode, item, level, forceCreate, delta, anim){
456                        var children = item.children;
457                        var box = domGeom.getMarginBox(domNode);
458
459                        var solution = utils.solve(children, box.w, box.h, lang.hitch(this,
460                                        this._computeAreaForItem), !this.isLeftToRight());
461                                       
462                        var rectangles = solution.rectangles;
463                       
464                        if(delta){
465                                rectangles = arr.map(rectangles, function(item){
466                                        item.x += delta.l;
467                                        item.y += delta.t;
468                                        return item;
469                                });
470                        }
471       
472                        var rectangle;
473                        for(var j = 0; j < children.length; ++j){
474                                rectangle = rectangles[j];
475                                this._buildRenderer(domNode, item, children[j], rectangle, level, forceCreate, anim);
476                        }
477                },
478               
479                _isLeaf: function(item){
480                        return !item.children;
481                },
482               
483                _isRoot: function(item){
484                        return item.__treeRoot;
485                },
486               
487                _getRenderer: function(item, anim, parent){
488                        if(anim){
489                                // while animating we do that on a copy of the subtree
490                                // so we can use our hash object to get to the renderer
491                                for(var i = 0; i < parent.children.length; ++i){
492                                if(parent.children[i].item == item){
493                                return parent.children[i];
494                        }
495                                }       
496                        }
497                        return this.itemToRenderer[this.getIdentity(item)];
498                },
499
500                _buildRenderer: function(container, parent, child, rect, level, forceCreate, anim){
501                        var isLeaf = this._isLeaf(child);
502                        var renderer = !forceCreate ? this._getRenderer(child, anim, container) : null;
503                        renderer = isLeaf ? this._updateLeafRenderer(renderer, child, level) : this._updateGroupRenderer(renderer,
504                                        child, level);
505                        if(forceCreate){
506                                renderer.level = level;
507                                renderer.item = child;
508                                renderer.parentItem = parent;
509                                this.itemToRenderer[this.getIdentity(child)] = renderer;
510                                // update its selection status
511                                this.updateRenderers(child);
512                        }
513       
514                        // in some cases the computation might be slightly incorrect (0.0000...1)
515                        // and due to the floor this will cause 1px gaps
516       
517                        var x = Math.floor(rect.x);
518                        var y = Math.floor(rect.y);
519                        var w = Math.floor(rect.x + rect.w + 0.00000000001) - x;
520                        var h = Math.floor(rect.y + rect.h + 0.00000000001) - y;
521
522                        // before sizing put the item inside its parent so that styling
523                        // is applied and taken into account
524                        if(forceCreate){
525                                domConstruct.place(renderer, container);
526                        }
527
528                        domGeom.setMarginBox(renderer, {
529                                l: x, t: y, w: w, h: h
530                        });
531                       
532                        if(!isLeaf){
533                                var box = domGeom.getContentBox(renderer);
534                                this._layoutGroupContent(renderer, box.w, box.h, level + 1, forceCreate, anim);
535                        }
536                       
537                        this.onRendererUpdated({ renderer: renderer, item: child, kind: isLeaf?"leaf":"group", level: level });         
538                },
539       
540                _layoutGroupContent: function(renderer, width, height, level, forceCreate, anim){
541                        var header = query(".dojoxTreeMapHeader", renderer)[0];
542                        var content = query(".dojoxTreeMapGroupContent", renderer)[0];
543                        if(header == null || content == null){
544                                return;
545                        }
546       
547                        var box = domGeom.getMarginBox(header);
548       
549                        // If the header is too high, reduce its area
550                        // and don't show the children..
551                        if(box.h > height){
552                                // TODO: this might cause pb when coming back to visibility later
553                                // as the getMarginBox of the header will keep that value?
554                                box.h = height;
555                                domStyle.set(content, "display", "none");
556                        }else{
557                                domStyle.set(content, "display", "block");
558                                domGeom.setMarginBox(content, {
559                                        l: 0, t: box.h, w: width, h: (height - box.h)
560                                });
561                                this._buildChildrenRenderers(content, renderer.item, level, forceCreate, null, anim);
562                        }
563       
564                        domGeom.setMarginBox(header, {
565                                l: 0, t: 0, w: width, h: box.h
566                        });
567                },
568       
569                _updateGroupRenderer: function(renderer, item, level){
570                        // summary:
571                        //              Update a group renderer. This creates the renderer if not already created,
572                        //              call styleRender for it and recurse into children.
573                        // renderer: DomNode
574                        //              The item renderer.
575                        // item: Object
576                        //              The data item.
577                        // level: Number
578                        //              The item depth level.
579                        // tags:
580                        //              private                         
581                        var forceCreate = renderer == null;
582                        if(renderer == null){
583                                renderer = this.createRenderer("div", level, "group");
584                                domClass.add(renderer, "dojoxTreeMapGroup");
585                        }
586                        this.styleRenderer(renderer, item, level, "group");
587                        var header = query(".dojoxTreeMapHeader", renderer)[0];
588                        header = this._updateHeaderRenderer(header, item, level);
589                        if(forceCreate){
590                                domConstruct.place(header, renderer);
591                        }
592                        var content = query(".dojoxTreeMapGroupContent", renderer)[0];
593                        content = this._updateGroupContentRenderer(content, item, level);
594                        if(forceCreate){
595                                domConstruct.place(content, renderer);
596                        }
597                        return renderer;
598                },
599       
600                _updateHeaderRenderer: function(renderer, item, level){
601                        // summary:
602                        //              Update a leaf renderer. This creates the renderer if not already created,
603                        //              call styleRender for it and set the label as its innerHTML.
604                        // renderer: DomNode
605                        //              The item renderer.
606                        // item: Object
607                        //              The data item.
608                        // level: Number
609                        //              The item depth level.
610                        // tags:
611                        //              private                 
612                        if(renderer == null){
613                                renderer = this.createRenderer(item, level, "header");
614                                domClass.add(renderer, "dojoxTreeMapHeader");
615                                domClass.add(renderer, "dojoxTreeMapHeader_" + level);                         
616                        }
617                        this.styleRenderer(renderer, item, level, "header");
618                        return renderer;
619                },
620       
621                _updateLeafRenderer: function(renderer, item, level){
622                        // summary:
623                        //              Update a leaf renderer. This creates the renderer if not already created,
624                        //              call styleRender for it and set the label as its innerHTML.
625                        // renderer: DomNode
626                        //              The item renderer.
627                        // item: Object
628                        //              The data item.
629                        // level: Number
630                        //              The item depth level.
631                        // tags:
632                        //              private                         
633                        if(renderer == null){
634                                renderer = this.createRenderer(item, level, "leaf");
635                                domClass.add(renderer, "dojoxTreeMapLeaf");
636                                domClass.add(renderer, "dojoxTreeMapLeaf_" + level);
637                        }               
638                        this.styleRenderer(renderer, item, level, "leaf");
639                        var tooltip = this.tooltipFunc(item, this.store);
640                        if(tooltip){
641                                renderer.title = tooltip;
642                        }
643                        return renderer;
644                },
645       
646                _updateGroupContentRenderer: function(renderer, item, level){
647                        // summary:
648                        //              Update a group content renderer. This creates the renderer if not already created,
649                        //              and call styleRender for it.
650                        // renderer:
651                        //              The item renderer.
652                        // item: Object
653                        //              The data item.
654                        // level: Number
655                        //              The item depth level.
656                        // tags:
657                        //              private                         
658                        if(renderer == null){
659                                renderer = this.createRenderer(item, level, "content");
660                                domClass.add(renderer, "dojoxTreeMapGroupContent");
661                                domClass.add(renderer, "dojoxTreeMapGroupContent_" + level);
662                        }
663                        this.styleRenderer(renderer, item, level, "content");
664                        return renderer;
665                },
666               
667                _getRendererFromTarget: function(target){
668                        var renderer = target;
669                        while(renderer != this.domNode && !renderer.item){
670                                renderer = renderer.parentNode;
671                        }                       
672                        return renderer;
673                },
674
675                _onMouseOver: function(e){
676                        var renderer = this._getRendererFromTarget(e.target);
677                        if(renderer.item){     
678                                var item = renderer.item;
679                                this._hoveredItem = item;
680                                this.updateRenderers(item);
681                                this.onItemRollOver({renderer: renderer, item : item, triggerEvent: e});
682                        }
683                },
684       
685                _onMouseOut: function(e){
686                        var renderer = this._getRendererFromTarget(e.target);
687                        if(renderer.item){     
688                                var item = renderer.item;
689                                this._hoveredItem = null;
690                                this.updateRenderers(item);
691                                this.onItemRollOut({renderer: renderer, item : item, triggerEvent: e});
692                        }
693                },
694               
695                _onMouseUp: function(e){
696                        var renderer = this._getRendererFromTarget(e.target);
697                        if(renderer.item){
698                                this.selectFromEvent(e, renderer.item, renderer, true);
699                                //event.stop(e);
700                        }
701                },
702               
703                onRendererUpdated: function(){
704                        // summary:
705                        //              Called when a renderer has been updated. This is called after creation, styling and sizing for
706                        //              each group and leaf renderers. For group renders this is also called after creation of children
707                        //              renderers.
708                        // tags:
709                        //              callback                       
710                },
711               
712                onItemRollOver: function(){
713                        // summary:
714                        //              Called when an item renderer has been hovered.
715                        // tags:
716                        //              callback                       
717                },
718               
719                onItemRollOut: function(){
720                        // summary:
721                        //              Called when an item renderer has been rolled out.
722                        // tags:
723                        //              callback                       
724                },             
725               
726                updateRenderers: function(items){
727                        // summary:
728                        //              Updates the renderer(s) that represent the specified item(s).
729                        // item: Object|Array
730                        //              The item(s).
731                        if(!items){
732                                return;
733                        }                       
734                        if(!lang.isArray(items)){
735                                items = [items];
736                        }
737                        for(var i=0; i<items.length;i++){
738                                var item = items[i];
739                                var renderer = this._getRenderer(item);
740                                // at init time the renderer might not be ready
741                                if(!renderer){
742                                        continue;
743                                }
744                                var selected = this.isItemSelected(item);
745                                var ie = has("ie");
746                                var div;
747                                if(selected){
748                                        domClass.add(renderer, "dojoxTreeMapSelected");
749                                        if(ie && (has("quirks") || ie < 9)){
750                                                // let's do all of this only if not already done
751                                                div = renderer.previousSibling;
752                                                var rStyle = domStyle.get(renderer);
753                                                if(!div || !domClass.contains(div, "dojoxTreeMapIEHack")){
754                                                        div = this.createRenderer(item, -10, "group");
755                                                        domClass.add(div, "dojoxTreeMapIEHack");
756                                                        domClass.add(div, "dojoxTreeMapSelected");
757                                                        domStyle.set(div, {
758                                                                position: "absolute",
759                                                                overflow: "hidden"
760                                                        });
761                                                        domConstruct.place(div, renderer, "before");
762                                                }
763                                                // TODO: might fail if different border widths for different sides
764                                                var bWidth = 2*parseInt(domStyle.get(div, "border-width"));
765                                                if(this._isLeaf(item)){
766                                                        bWidth -= 1;
767                                                }else{
768                                                        bWidth += 1;
769                                                }
770                                                // if we just drill down some renders might not be laid out?
771                                                if(rStyle["left"] != "auto"){
772                                                        domStyle.set(div, {
773                                                                left: (parseInt(rStyle["left"])+1)+"px",
774                                                                top: (parseInt(rStyle["top"])+1)+"px",
775                                                                width: (parseInt(rStyle["width"])-bWidth)+"px",
776                                                                height: (parseInt(rStyle["height"])-bWidth)+"px"
777                                                        });
778                                                }
779                                        }
780                                }else{
781                                        if(ie && (has("quirks") || ie < 9)){
782                                                div = renderer.previousSibling;
783                                                if(div && domClass.contains(div, "dojoxTreeMapIEHack")){
784                                                        div.parentNode.removeChild(div);
785                                                }
786                                        }
787                                        domClass.remove(renderer, "dojoxTreeMapSelected");
788
789                                }
790                                if(this._hoveredItem == item){
791                                        domClass.add(renderer, "dojoxTreeMapHovered");
792                                }else{
793                                        domClass.remove(renderer, "dojoxTreeMapHovered");
794                                }
795                                if(selected || this._hoveredItem == item){
796                                        domStyle.set(renderer, "zIndex", 20);
797                                }else{
798                                        domStyle.set(renderer, "zIndex", (has("ie")<=7)?0:"auto");
799                                }
800                        }
801                }
802        });
803});
Note: See TracBrowser for help on using the repository browser.