OpenLayers OpenLayers

Changeset 5791

Show
Ignore:
Timestamp:
01/16/08 21:16:44 (1 year ago)
Author:
tcoulter
Message:

Added functionality for z-indexing of externalGraphics and backgroundGraphics. New style values will be recognized: "graphicZIndex" and "backgroundGraphicZIndex". Values for each can be positive or negative integers. If a z-index is not specified, items will ordered based on when they were added to the renderer.

To do this, I had to make a couple changes:
1) Removed the nodeFactory() function which wasn't needed.
2) Added Openlayers.ElementsIndexer into Elements.js which handles the z-index ordering.
3) Made Elements.js use functions like replaceChild, insertBefore, and finally, appendChild to have the browser render the nodes in the correct order.

Possible downsides: Adding new nodes are now (likely) O(n) or O(log(n)), as the indexer's insert() functions uses Array's indexOf() and sort() functions. Also, this causes a bit of slowdown when dragging features in IE's VML renderer.

Upsides: Z-indexing!!! As well, this works (functionally) in FF, IE 6 and IE 7.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • sandbox/topp/nymap/lib/OpenLayers/Renderer/Elements.js

    r5629 r5791  
    66 * @requires OpenLayers/Renderer.js 
    77 */ 
     8 
     9OpenLayers.ElementsIndexer = OpenLayers.Class({ 
     10    
     11    maxZIndex: null, 
     12    order: null,  
     13    
     14    initialize: function() { 
     15        this.order = []; 
     16        this.maxZIndex = 0; 
     17    }, 
     18     
     19    /** 
     20     *  
     21     * @param {Object} item 
     22     */ 
     23    insert: function(nodeId, zIndex) { 
     24        
     25        // Everything must have a zIndex. If none is specified, 
     26        // we'll use the maximum at the time of drawing. 
     27        if (zIndex == null) { 
     28            zIndex == this.maxZIndex; 
     29        } 
     30         
     31        if (zIndex > this.maxZIndex) { 
     32            this.maxZIndex = zIndex; 
     33        } 
     34         
     35        var indexer = this; 
     36         
     37        // Create a hash that holds the id of the node and the zIndex. 
     38        var item = { 
     39            id: nodeId, 
     40            zIndex: zIndex 
     41        }; 
     42         
     43        this.order.push(item); 
     44         
     45        // Sort the items in the array based on their zIndex. Since itemA 
     46        // represents the item being added, we want to make it as high 
     47        // up in the index order as possible (ie., if there are other items 
     48        // with the same zIndex, the newest one should be the highest one). 
     49        var sortByZIndex = function(itemA, itemB) { 
     50            var zIndexA = itemA.zIndex; 
     51            var zIndexB = itemB.zIndex; 
     52             
     53            if(zIndexA <= zIndexB) { 
     54                return -1;              
     55            } else { 
     56                return 1; 
     57            } 
     58        } 
     59         
     60        this.order.sort(sortByZIndex); 
     61         
     62        // Return the next item in the array -- the id of the node that should 
     63        // follow this one directly in the index order -- if any. 
     64        var nextIndex = this.order.indexOf(item) + 1; 
     65         
     66        var returnVal = null; 
     67        if (nextIndex > 0 && nextIndex < this.order.length) { 
     68            returnVal = this.order[nextIndex].id; 
     69        } 
     70        return returnVal; 
     71    }, 
     72     
     73    exists: function(nodeId) { 
     74        return this.items[nodeId] != null;   
     75    }, 
     76    
     77    CLASS_NAME: "OpenLayers.ElementsIndexer" 
     78}); 
    879 
    980/** 
     
    42113    xmlns: null, 
    43114     
     115    indexer: null,  
     116     
    44117    BACKGROUND_ID_SUFFIX: "_background", 
    45118     
     
    58131        this.rendererRoot.appendChild(this.root); 
    59132        this.container.appendChild(this.rendererRoot); 
     133         
     134        this.indexer = new OpenLayers.ElementsIndexer(); 
    60135    }, 
    61136     
     
    115190     * featureId - {String} 
    116191     */ 
    117     drawGeometry: function(geometry, style, featureId) { 
     192    drawGeometry: function(geometry, style, featureId) {         
    118193        var className = geometry.CLASS_NAME; 
    119194        if ((className == "OpenLayers.Geometry.Collection") || 
     
    127202        }; 
    128203 
     204        var id = geometry.id; 
     205         
     206        if (style.backgroundGraphic) { 
     207            this.redrawBackgroundNode(id, geometry, style, featureId); 
     208        } 
     209         
    129210        if (style.display != "none") { 
    130             if (style.backgroundGraphic) { 
    131              
    132                 var backgroundStyle = OpenLayers.Util.extend({}, style); 
    133                 backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic; 
    134      
    135                 backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset; 
    136                 backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset; 
    137                  
    138                 var backgroundNode = this.nodeFactory(geometry.id + this.BACKGROUND_ID_SUFFIX, nodeType, geometry); 
    139                 backgroundNode._geometryClass = geometry.CLASS_NAME; 
    140                 backgroundNode._style = backgroundStyle; 
    141                  
    142                 this.root.appendChild(backgroundNode); 
    143                 this.drawGeometryNode(backgroundNode, geometry); 
    144             } 
    145  
    146             //first we create the basic node and add it to the root 
    147             var nodeType = this.getNodeType(geometry, style); 
    148             var node = this.nodeFactory(geometry.id, nodeType); 
    149             node._featureId = featureId; 
    150             node._geometryClass = geometry.CLASS_NAME; 
    151             node._style = style; 
    152              
    153             //now actually draw the node, and style it 
    154             node = this.drawGeometryNode(node, geometry); 
    155             this.root.appendChild(node); 
    156             this.postDraw(node); 
     211            var node = this.redrawNode(id, geometry, style, featureId);  
    157212        } else { 
    158             node = OpenLayers.Util.getElement(geometry.id); 
     213            node = OpenLayers.Util.getElement(id); 
    159214            if (node) { 
    160215                node.parentNode.removeChild(node); 
    161                 if (style.backgroundGraphic) { 
    162                     var backgroundNode = OpenLayers.Util.getElement( 
    163                         geometry.id + this.BACKGROUND_ID_SUFFIX 
    164                     ); 
    165                     backgroundNode.parentNode.removeChild(backgroundNode); 
    166                 } 
    167             } 
    168         } 
     216            } 
     217        } 
     218    }, 
     219     
     220    redrawNode: function(id, geometry, style, featureId) { 
     221        // Get the node if it's already on the map. 
     222        var currentNode = OpenLayers.Util.getElement(id); 
     223         
     224        // Create a new node with the correct data. 
     225        var nodeType = this.getNodeType(geometry, style); 
     226        var newNode = this.createNode(nodeType, id); 
     227        newNode._featureId = featureId; 
     228        newNode._geometryClass = geometry.CLASS_NAME; 
     229        newNode._style = style; 
     230         
     231        // Draw the node (but not append it, yet).  
     232        newNode = this.drawGeometryNode(newNode, geometry, style); 
     233         
     234        // If we currently have a node, replace the current one 
     235        // with the new one. This will get the browser to redraw it. 
     236        if (currentNode) { 
     237            this.root.replaceChild(newNode, currentNode); 
     238        } else { 
     239            // This is a new node. Throw this new node into our 
     240            // indexer so it can show us where to place it. 
     241            var zIndex = style.graphicZIndex; 
     242             
     243            var nextNodeId = this.indexer.insert(id, zIndex); 
     244 
     245            // If the new node should be before another in the index 
     246            // order, insert the new node before the next; else, lets just 
     247            // append new one on the end, making it the highest in the index order). 
     248            if (nextNodeId) { 
     249                var nextNode = OpenLayers.Util.getElement(nextNodeId); 
     250                this.root.insertBefore(newNode, nextNode); 
     251            } else { 
     252                this.root.appendChild(newNode) 
     253            } 
     254        } 
     255         
     256        this.postDraw(newNode);  
     257         
     258        return newNode; 
     259    }, 
     260     
     261    redrawBackgroundNode: function(id, geometry, style, featureId) { 
     262        var backgroundStyle = OpenLayers.Util.extend({}, style); 
     263         
     264        // Set regular style attributes to apply to the background styles. 
     265        backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic; 
     266        backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset; 
     267        backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset; 
     268        backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex; 
     269         
     270        // Erase background styles. 
     271        backgroundStyle.backgroundGraphic = null; 
     272        backgroundStyle.backgroundXOffset = null; 
     273        backgroundStyle.backgroundYOffset = null; 
     274        backgroundStyle.backgroundGraphicZIndex = null; 
     275         
     276        this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null); 
    169277    }, 
    170278 
     
    367475        } 
    368476    },     
    369  
    370     /**  
    371      * Method: nodeFactory 
    372      * Create new node of the specified type, with the (optional) specified id. 
    373      *  
    374      * If node already exists with same ID and type, we remove it and then 
    375      *  call ourselves again to recreate it. 
    376      *  
    377      * Parameters: 
    378      * id - {String} 
    379      * type - {String} type Kind of node to draw 
    380      *  
    381      * Returns: 
    382      * {DOMElement} A new node of the given type and id 
    383      */ 
    384     nodeFactory: function(id, type) { 
    385         var node = OpenLayers.Util.getElement(id); 
    386         if (node) { 
    387             if (!this.nodeTypeCompare(node, type)) { 
    388                 node.parentNode.removeChild(node); 
    389                 node = this.nodeFactory(id, type); 
    390             } 
    391         } else { 
    392             node = this.createNode(type, id); 
    393         } 
    394         return node; 
     477     
     478    replaceNode: function(newNode, previousNode) { 
     479        this.root.replaceChild(newNode, previousNode); 
    395480    }, 
    396481 
  • sandbox/topp/nymap/lib/OpenLayers/Renderer/SVG.js

    r5629 r5791  
    287287     */ 
    288288    createRenderRoot: function() { 
    289         return this.nodeFactory(this.container.id + "_svgRoot", "svg"); 
     289        return this.createNode("svg", this.container.id + "_svgRoot"); 
    290290    }, 
    291291 
     
    297297     */ 
    298298    createRoot: function() { 
    299         return this.nodeFactory(this.container.id + "_root", "g"); 
     299        return this.createNode("g", this.container.id + "_root"); 
    300300    }, 
    301301 
  • sandbox/topp/nymap/lib/OpenLayers/Renderer/VML.js

    r5629 r5791  
    364364     */ 
    365365    createRenderRoot: function() { 
    366         return this.nodeFactory(this.container.id + "_vmlRoot", "div"); 
     366        return this.createNode("div", this.container.id + "_vmlRoot"); 
    367367    }, 
    368368 
     
    375375     */ 
    376376    createRoot: function() { 
    377         return this.nodeFactory(this.container.id + "_root", "v:group"); 
     377        return this.createNode("v:group", this.container.id + "_root"); 
    378378    }, 
    379379