OpenLayers OpenLayers

Ticket #1357: ordering.2.patch

File ordering.2.patch, 32.2 kB (added by tcoulter, 1 month ago)

Updated ordering patch with background graphic/shadow example.

  • tests/Renderer/Elements.html

    old new  
    33<script src="../../lib/OpenLayers.js"></script> 
    44  <script type="text/javascript"> 
    55 
    6     function test_Elements_constructor(t) { 
    7         t.plan(5); 
    8         var el = document.createElement('div'); 
    9         document.body.appendChild(el); 
    10         el.id = "foo"; 
    11          
     6    function setUp() { 
     7        // Stub out functions that are meant to be overridden by 
     8        // subclasses. 
    129        OpenLayers.Renderer.Elements.prototype._createRenderRoot = 
    1310            OpenLayers.Renderer.Elements.prototype.createRenderRoot; 
    1411         
     
    2522            return root; 
    2623        }; 
    2724         
    28         var r = new OpenLayers.Renderer.Elements("foo"); 
     25        OpenLayers.Renderer.Elements.prototype._createNode = 
     26            OpenLayers.Renderer.Elements.prototype.createNode; 
    2927         
    30         t.ok(r instanceof OpenLayers.Renderer.Elements, "new OpenLayers.Renderer.Elements returns Elements object" ); 
    31         t.ok(r.rendererRoot != null, "elements rendererRoot is not null"); 
    32         t.ok(r.root != null, "elements root is not null"); 
     28        OpenLayers.Renderer.Elements.prototype.createNode = function() { 
     29            return document.createElement("div"); 
     30        }; 
     31    } 
     32     
     33    // Create a new Elements renderer based on an id and an ordering 
     34    // type. For these tests, both of these parameters are optional. 
     35    function create_renderer(id, ordering) { 
    3336         
    34         t.ok(r.root.parentNode == rendererRoot, "elements root is correctly appended to rendererRoot"); 
    35         t.ok(r.rendererRoot.parentNode == el, "elements rendererRoot is correctly appended to container"); 
     37        rendererRoot = null; 
    3638         
     39        if (id == null) { 
     40            var el = document.createElement('div'); 
     41            document.body.appendChild(el); 
     42            el.id = OpenLayers.Util.createUniqueID(); 
     43            id = el.id; 
     44        } 
     45         
     46        return new OpenLayers.Renderer.Elements(id, ordering); 
     47    } 
     48     
     49    // Cleanup stubs made in the function above. 
     50    function tearDown() { 
    3751        OpenLayers.Renderer.Elements.prototype.createRenderRoot = 
    3852            OpenLayers.Renderer.Elements.prototype._createRenderRoot; 
    3953        OpenLayers.Renderer.Elements.prototype.createRoot = 
    4054            OpenLayers.Renderer.Elements.prototype._createRoot; 
     55        OpenLayers.Renderer.Elements.prototype.createNode = 
     56            OpenLayers.Renderer.Elements.prototype._createNode; 
    4157    } 
     58 
     59    function test_Elements_constructor(t) { 
     60        t.plan(6); 
     61         
     62        setUp(); 
     63         
     64        var r = create_renderer(); 
     65         
     66        t.ok(r instanceof OpenLayers.Renderer.Elements, "new OpenLayers.Renderer.Elements returns Elements object" ); 
     67        t.ok(r.rendererRoot != null, "elements rendererRoot is not null"); 
     68        t.ok(r.root != null, "elements root is not null"); 
     69        t.ok(r.indexer != null, "indexer is not null."); 
     70         
     71        t.ok(r.root.parentNode == r.rendererRoot, "elements root is correctly appended to rendererRoot"); 
     72        t.ok(r.rendererRoot.parentNode == r.container, "elements rendererRoot is correctly appended to container"); 
     73         
     74        tearDown(); 
     75    } 
    4276     
    4377    function test_Elements_destroy(t) { 
    4478        t.plan(5); 
    4579         
    46         OpenLayers.Renderer.Elements.prototype._initialize = 
    47             OpenLayers.Renderer.Elements.prototype.initialize; 
    48          
    49         OpenLayers.Renderer.Elements.prototype.initialize = function() {} 
    50          
    51         var g_Clear = false, g_Destroy = false; 
    52          
     80        var elems = { 
     81            'clear': function() { 
     82                t.ok(true, "clear called"); 
     83            }, 
     84            'rendererRoot': {}, 
     85            'root': {}, 
     86            'xmlns': {} 
     87        }; 
     88 
    5389        OpenLayers.Renderer.prototype._destroy =  
    5490            OpenLayers.Renderer.prototype.destroy; 
    55              
     91 
     92        var args = [{}, {}, {}]; 
    5693        OpenLayers.Renderer.prototype.destroy = function() { 
    57             g_Destroy = true; 
     94            t.ok((arguments[0] == args[0]) && 
     95                 (arguments[1] == args[1]) && 
     96                 (arguments[2] == args[2]), "correct arguments passed to OpenLayers.Renderer.destroy()"); 
    5897        }; 
    59          
    60         var r = new OpenLayers.Renderer.SVG(document.body); 
    61         r.clear = function() { 
    62             g_Clear = true; 
    63         }; 
    64         r.rendererRoot = 'foo'; 
    65         r.root = 'bar'; 
    66         r.xmlns = 'dude'; 
    67          
    68         r.destroy(); 
    69          
    70         t.eq(g_Clear, true, "OpenLayers.Renderer.Elements.clear() called"); 
    71         t.eq(r.rendererRoot, null, "rendererRoot nullified"); 
    72         t.eq(r.root, null, "root nullified"); 
    73         t.eq(r.xmlns, null, "xmlns nullified"); 
    74         t.eq(g_Destroy, true, "OpenLayers.Renderer.destroy() called"); 
    75          
    76         OpenLayers.Renderer.Elements.prototype.initialize = 
    77             OpenLayers.Renderer.Elements.prototype._initialize; 
     98 
     99        OpenLayers.Renderer.Elements.prototype.destroy.apply(elems, args); 
     100 
     101        t.ok(elems.rendererRoot == null, "rendererRoot nullified"); 
     102        t.ok(elems.root == null, "root nullified"); 
     103        t.ok(elems.xmlns == null, "xmlns nullified"); 
     104 
    78105        OpenLayers.Renderer.prototype.destroy =  
    79106            OpenLayers.Renderer.prototype._destroy; 
     107 
    80108    } 
    81109     
    82110    function test_Elements_clear(t) { 
    83111        t.plan(1); 
    84112         
    85         OpenLayers.Renderer.Elements.prototype._initialize = 
    86             OpenLayers.Renderer.Elements.prototype.initialize; 
     113        setUp(); 
    87114         
    88         OpenLayers.Renderer.Elements.prototype.initialize = function() {} 
    89          
    90         var r = new OpenLayers.Renderer.Elements(); 
     115        var r = create_renderer(); 
    91116        var element = document.createElement("div"); 
    92117        r.root = element; 
    93118         
     
    98123         
    99124        t.ok(r.root.childNodes.length == 0, "root is correctly cleared"); 
    100125         
    101         OpenLayers.Renderer.Elements.prototype.initialize = 
    102             OpenLayers.Renderer.Elements.prototype._initialize; 
     126        tearDown(); 
    103127    } 
    104128     
    105129    function test_Elements_drawGeometry(t) { 
    106130        t.plan(5); 
     131 
     132        setUp(); 
     133 
     134        var r = create_renderer(); 
    107135         
    108         OpenLayers.Renderer.Elements.prototype._initialize = 
    109             OpenLayers.Renderer.Elements.prototype.initialize; 
    110          
    111         OpenLayers.Renderer.Elements.prototype.initialize = function() {}; 
    112          
    113         var r = new OpenLayers.Renderer.Elements(); 
    114          
    115136        var element = document.createElement("div"); 
    116137        r.root = element; 
    117138 
     
    147168        var style = {'display':'none'}; 
    148169        r.drawGeometry(geometry, style, featureId); 
    149170        t.ok(g_Node.parentNode != r.root, "node is correctly removed"); 
    150         
    151         OpenLayers.Util.getElement = _getElement; 
    152         OpenLayers.Renderer.Elements.prototype.initialize = 
    153             OpenLayers.Renderer.Elements.prototype._initialize; 
     171             
     172        tearDown(); 
    154173    } 
    155174 
    156175    function test_Elements_drawGeometry_2(t) { 
    157176        t.plan(9); 
    158177         
    159         OpenLayers.Renderer.Elements.prototype._initialize = 
    160             OpenLayers.Renderer.Elements.prototype.initialize; 
    161              
    162         OpenLayers.Renderer.Elements.prototype.initialize = function() {}; 
    163  
    164         var r = new OpenLayers.Renderer.Elements(); 
     178        setUp(); 
    165179         
     180        var r = create_renderer(); 
     181         
    166182        var element = document.createElement("div"); 
    167183        r.root = element; 
    168184         
     
    281297        style = true; 
    282298        r.drawGeometry(geometry, style); 
    283299        t.ok(properDraw, "drawGeometry called drawPolygon when passed a multi-polygon"); 
    284          
    285         OpenLayers.Renderer.Elements.prototype.initialize = 
    286             OpenLayers.Renderer.Elements.prototype._initialize; 
     300       
     301        tearDown(); 
    287302    } 
    288303     
    289304    function test_Elements_getfeatureidfromevent(t) { 
     
    309324     
    310325    function test_Elements_erasegeometry(t) { 
    311326        t.plan(5); 
    312          
     327 
     328        setUp(); 
     329 
    313330        var el = document.createElement('div'); 
    314331        document.body.appendChild(el); 
    315332        el.id = 'bar'; 
    316333        var geometry = { 
    317334            id: 'bar' 
    318335        }; 
     336 
     337        var r = create_renderer(el.id); 
    319338         
    320         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
    321         t.ok(el.parentNode != document.body, "element correctly removed"); 
     339        r.eraseGeometry(geometry); 
     340        //t.ok(el.parentNode != document.body, "element correctly removed"); 
     341        t.ok(el.parentNode != document.body, "element correctry removed"); 
    322342 
    323         var el = document.createElement('div'); 
     343 
     344      //multipoint 
    324345        document.body.appendChild(el); 
    325         el.id = 'bar'; 
    326346        var geometry = { 
    327347            CLASS_NAME: "OpenLayers.Geometry.MultiPoint", 
    328348            components: [{ 
    329349                id: 'bar' 
    330350            }] 
    331351        }; 
    332  
    333         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     352        r.eraseGeometry(geometry); 
    334353        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a multipoint"); 
    335354         
    336         var el = document.createElement('div'); 
     355 
     356      //multilinestring 
    337357        document.body.appendChild(el); 
    338         el.id = 'bar'; 
    339358        var geometry = { 
    340359            CLASS_NAME: "OpenLayers.Geometry.MultiLineString", 
    341360            components: [{ 
    342361                id: 'bar' 
    343362            }] 
    344363        }; 
    345          
    346         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     364        r.eraseGeometry(geometry); 
    347365        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a multilinestring"); 
    348366         
    349         var el = document.createElement('div'); 
     367      //multipolygon 
    350368        document.body.appendChild(el); 
    351         el.id = 'bar'; 
    352369        var geometry = { 
    353370            CLASS_NAME: "OpenLayers.Geometry.MultiPolygon", 
    354371            components: [{ 
    355372                id: 'bar' 
    356373            }] 
    357374        }; 
    358          
    359         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     375        r.eraseGeometry(geometry); 
    360376        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a multipolygon"); 
    361          
    362         var el = document.createElement('div'); 
     377 
     378      //collection         
    363379        document.body.appendChild(el); 
    364         el.id = 'bar'; 
    365380        var geometry = { 
    366381            CLASS_NAME: "OpenLayers.Geometry.Collection", 
    367382            components: [{ 
    368383                id: 'bar' 
    369384            }] 
    370385        }; 
     386        r.eraseGeometry(geometry); 
     387        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a collection"); 
    371388         
    372         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
    373         t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a collection"); 
     389        tearDown(); 
    374390    }     
    375391 
    376392  </script> 
  • lib/OpenLayers/Renderer/Elements.js

    old new  
    77 */ 
    88 
    99/** 
     10 * Class: OpenLayers.ElementsIndexer 
     11 * This class takes care of figuring out which order elements should be 
     12 *     placed in the DOM based on given indexing methods.  
     13 */ 
     14OpenLayers.ElementsIndexer = OpenLayers.Class({ 
     15    
     16    /** 
     17     * Property: maxZIndex 
     18     * {Integer} This is the largest-most z-index value for a node 
     19     *     contained within the indexer. 
     20     */ 
     21    maxZIndex: null, 
     22     
     23    /** 
     24     * Property: order 
     25     * {Array<String>} This is an array of node id's stored in the 
     26     *     order that they should show up on screen. Id's higher up in the 
     27     *     array (higher array index) represent nodes with higher z-indeces. 
     28     */ 
     29    order: null,  
     30     
     31    /** 
     32     * Property: indices 
     33     * {Object} This is a hash that maps node ids to their z-index value 
     34     *     stored in the indexer. This is done to make finding a nodes z-index  
     35     *     value O(1). 
     36     */ 
     37    indices: null, 
     38     
     39    /** 
     40     * Property: compare 
     41     * {Function} This is the function used to determine placement of 
     42     *     of a new node within the indexer. If null, this defaults to to 
     43     *     the Z_ORDER_DRAWING_ORDER comparison method. 
     44     */ 
     45    compare: null, 
     46    
     47    /** 
     48     * APIMethod: initialize 
     49     * Create a new indexer with  
     50     *  
     51     * Parameters: 
     52     * yOrdering - {Boolean} Whether to use y-ordering. 
     53     */ 
     54    initialize: function(yOrdering) { 
     55 
     56        this.compare = yOrdering ?  
     57            OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : 
     58            OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; 
     59             
     60        this.order = []; 
     61        this.indices = {}; 
     62        this.maxZIndex = 0; 
     63    }, 
     64     
     65    /** 
     66     * APIMethod: insert 
     67     * Insert a new node into the indexer. In order to find the correct  
     68     *     positioning for the node to be inserted, this method uses a binary  
     69     *     search. This makes inserting O(log(n)).  
     70     *  
     71     * Parameters: 
     72     * newNode - {DOMElement} The new node to be inserted. 
     73     * root - {DOMElement} The root node from which to insert the new node. 
     74     */ 
     75    insert: function(newNode, root) { 
     76        var nodeId = newNode.id; 
     77         
     78        this.determineZIndex(newNode);        
     79 
     80        var leftIndex = -1; 
     81        var rightIndex = this.order.length; 
     82        var middle; 
     83 
     84        while (rightIndex - leftIndex > 1) { 
     85            middle = parseInt((leftIndex + rightIndex) / 2); 
     86             
     87            var nextId = this.order[middle]; 
     88            var nextNode = OpenLayers.Util.getElement(nextId); 
     89             
     90            var placement = this.compare(this, newNode, nextNode); 
     91             
     92            if (placement > 0) { 
     93                leftIndex = middle; 
     94            } else { 
     95                rightIndex = middle; 
     96            }  
     97        } 
     98         
     99        this.order.splice(rightIndex, 0, nodeId); 
     100        this.indices[nodeId] = this.getZIndex(newNode); 
     101         
     102        // If the new node should be before another in the index 
     103        // order, insert the new node before the next; else, lets just 
     104        // append the new one on the end, making it the highest in the index order. 
     105        var nextIndex = rightIndex + 1; 
     106        if (nextIndex < this.order.length) { 
     107            var nextNode = OpenLayers.Util.getElement(this.order[nextIndex]); 
     108            root.insertBefore(newNode, nextNode); 
     109        } else { 
     110            root.appendChild(newNode); 
     111        } 
     112    }, 
     113     
     114    /** 
     115     * APIMethod: remove 
     116     *  
     117     * Parameters: 
     118     * node - {DOMElement} The node to be removed. 
     119     */ 
     120    remove: function(node) { 
     121        var nodeId = node.id; 
     122        var arrayIndex = OpenLayers.Util.indexOf(this.order, nodeId); 
     123        if (arrayIndex >= 0) { 
     124            // Remove it from the order array, as well as deleting the node 
     125            // from the indeces hash. 
     126            this.order.splice(arrayIndex, 1); 
     127            delete this.indices[nodeId]; 
     128             
     129            // Reset the maxium z-index based on the last item in the  
     130            // order array. 
     131            var lastId = this.order[this.order.length - 1]; 
     132            this.maxZIndex = this.indices[lastId]; 
     133        } 
     134    }, 
     135     
     136    /** 
     137     * APIMethod: exists 
     138     *  
     139     * Parameters: 
     140     * node- {DOMElement} The node to test for existence. 
     141     *  
     142     * Returns: 
     143     * {Boolean} Whether or not the node exists in the indexer? 
     144     */ 
     145    exists: function(node) { 
     146        return (this.indices[node.id] != null); 
     147    }, 
     148     
     149    /** 
     150     * APIMethod: getZIndex 
     151     * Get the z-index value for the current node from the node data itself. 
     152     *  
     153     * Parameters: 
     154     * node - {DOMElement} The node whose z-index to get. 
     155     *  
     156     * Returns: 
     157     * {Integer} The z-index value for the specified node (from the node  
     158     *     data itself). 
     159     */ 
     160    getZIndex: function(node) { 
     161        return node._style.graphicZIndex;   
     162    }, 
     163     
     164    /** 
     165     * Method: determineZIndex 
     166     * Determine the z-index for the current node if there isn't one,  
     167     *     and set the maximum value if we've found a new maximum. 
     168     *  
     169     * Parameters: 
     170     * node - {DOMElement}  
     171     */ 
     172    determineZIndex: function(node) { 
     173        var zIndex = node._style.graphicZIndex; 
     174         
     175        // Everything must have a zIndex. If none is specified, 
     176        // this means the user *must* (hint: assumption) want this 
     177        // node to succomb to drawing order. To enforce drawing order 
     178        // over all indexing methods, we'll create a new z-index that's 
     179        // greater than any currently in the indexer. 
     180        if (zIndex == null) { 
     181            zIndex = this.maxZIndex; 
     182            node._style.graphicZIndex = zIndex;  
     183        } else if (zIndex > this.maxZIndex) { 
     184            this.maxZIndex = zIndex; 
     185        } 
     186    }, 
     187     
     188    CLASS_NAME: "OpenLayers.ElementsIndexer" 
     189}); 
     190 
     191/** 
     192 * Namespace: OpenLayers.ElementsIndexer.IndexingMethods 
     193 * These are the compare methods for figuring out where a new node should be  
     194 *     placed within the indexer. These methods are very similar to general  
     195 *     sorting methods in that they return -1, 0, and 1 to specify the  
     196 *     direction in which new nodes fall in the ordering. 
     197 */ 
     198OpenLayers.ElementsIndexer.IndexingMethods = { 
     199     
     200    /** 
     201     * Method: Z_ORDER 
     202     * This compare method is used by other comparison methods. 
     203     *     It can be used individually for ordering, but is not recommended, 
     204     *     because it doesn't subscribe to drawing order. 
     205     *  
     206     * Parameters: 
     207     * indexer - {<OpenLayers.ElementsIndexer>} 
     208     * newNode - {DOMElement} 
     209     * nextNode - {DOMElement} 
     210     *  
     211     * Returns: 
     212     * {Integer} 
     213     */ 
     214    Z_ORDER: function(indexer, newNode, nextNode) { 
     215        var newZIndex = indexer.getZIndex(newNode); 
     216 
     217        var returnVal = 0; 
     218        if (nextNode) { 
     219            var nextZIndex = indexer.getZIndex(nextNode); 
     220            returnVal = newZIndex - nextZIndex;  
     221        } 
     222         
     223        return returnVal; 
     224    }, 
     225 
     226    /** 
     227     * APIMethod: Z_ORDER_DRAWING_ORDER 
     228     * This method orders nodes by their z-index, but does so in a way 
     229     *     that, if there are other nodes with the same z-index, the newest  
     230     *     drawn will be the front most within that z-index. This is the  
     231     *     default indexing method. 
     232     *  
     233     * Parameters: 
     234     * indexer - {<OpenLayers.ElementsIndexer>} 
     235     * newNode - {DOMElement} 
     236     * nextNode - {DOMElement} 
     237     *  
     238     * Returns: 
     239     * {Integer} 
     240     */ 
     241    Z_ORDER_DRAWING_ORDER: function(indexer, newNode, nextNode) { 
     242        var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( 
     243            indexer,  
     244            newNode,  
     245            nextNode 
     246        ); 
     247         
     248        // Make Z_ORDER subscribe to drawing order by pushing it above 
     249        // all of the other nodes with the same z-index. 
     250        if (nextNode && returnVal == 0) { 
     251            returnVal = 1; 
     252        } 
     253         
     254        return returnVal; 
     255    }, 
     256 
     257    /** 
     258     * APIMethod: Z_ORDER_Y_ORDER 
     259     * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it 
     260     *     best describes which ordering methods have precedence (though, the  
     261     *     name would be too long). This method orders nodes by their z-index,  
     262     *     but does so in a way that, if there are other nodes with the same  
     263     *     z-index, the nodes with the lower y position will be "closer" than  
     264     *     those with a higher y position. If two nodes have the exact same y  
     265     *     position, however, then this method will revert to using drawing   
     266     *     order to decide placement. 
     267     *  
     268     * Parameters: 
     269     * indexer - {<OpenLayers.ElementsIndexer>} 
     270     * newNode - {DOMElement} 
     271     * nextNode - {DOMElement} 
     272     *  
     273     * Returns: 
     274     * {Integer} 
     275     */ 
     276    Z_ORDER_Y_ORDER: function(indexer, newNode, nextNode) { 
     277        var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER( 
     278            indexer,  
     279            newNode,  
     280            nextNode 
     281        ); 
     282         
     283        if (nextNode && returnVal == 0) { 
     284            var newLat = newNode._geometry.getBounds().bottom; 
     285            var nextLat = nextNode._geometry.getBounds().bottom; 
     286             
     287            var result = nextLat - newLat; 
     288            returnVal = (result ==0) ? 1 : result; 
     289        } 
     290         
     291        return returnVal;        
     292    } 
     293}; 
     294 
     295/** 
    10296 * Class: OpenLayers.Renderer.Elements 
    11297 * This is another virtual class in that it should never be instantiated by  
    12298 *  itself as a Renderer. It exists because there is *tons* of shared  
     
    42328    xmlns: null, 
    43329     
    44330    /** 
     331     * Property: Indexer 
     332     * {<OpenLayers.ElementIndexer>} An instance of OpenLayers.ElementsIndexer  
     333     *     created upon initialization. 
     334     */ 
     335    indexer: null,  
     336     
     337    /** 
     338     * Constant: BACKGROUND_ID_SUFFIX 
     339     * {String} 
     340     */ 
     341    BACKGROUND_ID_SUFFIX: "_background", 
     342     
     343    /** 
    45344     * Property: minimumSymbolizer 
    46345     * {Object} 
    47346     */ 
     
    57356     *  
    58357     * Parameters: 
    59358     * containerID - {String} 
     359     * yOrdering - {Boolean} Whether or not y-ordering is enabled. 
    60360     */ 
    61     initialize: function(containerID) { 
     361    initialize: function(containerID, yOrdering) { 
    62362        OpenLayers.Renderer.prototype.initialize.apply(this, arguments); 
    63363 
    64364        this.rendererRoot = this.createRenderRoot(); 
     
    66366         
    67367        this.rendererRoot.appendChild(this.root); 
    68368        this.container.appendChild(this.rendererRoot); 
     369         
     370        this.indexer = new OpenLayers.ElementsIndexer(yOrdering); 
    69371    }, 
    70372     
    71373    /** 
     
    135437            return; 
    136438        }; 
    137439 
     440        // 
     441        if (style.backgroundGraphic) { 
     442            this.redrawBackgroundNode(geometry.id, geometry, style, featureId); 
     443        } 
     444         
    138445        if (style.display != "none") { 
    139             //first we create the basic node and add it to the root 
    140             var nodeType = this.getNodeType(geometry, style); 
    141             var node = this.nodeFactory(geometry.id, nodeType); 
    142             node._featureId = featureId; 
    143             node._geometryClass = geometry.CLASS_NAME; 
    144             node._style = style; 
    145              
    146             //now actually draw the node, and style it 
    147             node = this.drawGeometryNode(node, geometry); 
    148              
    149             // append the node to root (but only if it's new) 
    150             if (node.parentNode != this.root) {  
    151                 this.root.appendChild(node);  
    152             } 
    153             this.postDraw(node); 
     446            this.redrawNode(geometry.id, geometry, style, featureId);  
    154447        } else { 
    155448            node = OpenLayers.Util.getElement(geometry.id); 
    156449            if (node) { 
     
    158451            } 
    159452        } 
    160453    }, 
     454     
     455    /** 
     456     * Method: redrawNode 
     457     *  
     458     * Parameters: 
     459     * id - {String} 
     460     * geometry - {<OpenLayers.Geometry>} 
     461     * style - {Object} 
     462     * featureId - {String} 
     463     */ 
     464    redrawNode: function(id, geometry, style, featureId) { 
     465        // Get the node if it's already on the map. 
     466        var currentNode = OpenLayers.Util.getElement(id); 
     467         
     468        // Create a new node, or use the current one if it's 
     469        // already there. 
     470        var newNode; 
     471        if (!currentNode) { 
     472            var nodeType = this.getNodeType(geometry, style); 
     473            newNode = this.createNode(nodeType, id); 
     474        } else { 
     475            newNode = currentNode; 
     476        } 
     477         
     478        // Set the data for the node, then draw it. 
     479        newNode._featureId = featureId; 
     480        newNode._geometry = geometry; 
     481        newNode._geometryClass = geometry.CLASS_NAME; 
     482        newNode._style = style; 
     483        newNode = this.drawGeometryNode(newNode, geometry, style); 
     484         
     485        // If the node is known to the indexer, remove it so we can 
     486        // recalculate where it should go. 
     487        if (this.indexer.exists(newNode)) { 
     488            this.indexer.remove(newNode); 
     489        } 
     490         
     491        // Insert the node into the indexer so it can show us where to place it. 
     492        //  Note that this operation is O(log(n)). If there's a performance  
     493        //  problem (when dragging, for instance) this is likely where it  
     494        //  would be. 
     495        this.indexer.insert(newNode, this.root); 
     496         
     497        this.postDraw(newNode);  
     498    }, 
     499     
     500    /** 
     501     * Method: redrawBackgroundNode 
     502     * Redraws the node using special 'background' style properties. Basically 
     503     *     just calls redrawNode(), but instead of directly using the  
     504     *     'externalGraphic', 'graphicXOffset', 'graphicYOffset', and  
     505     *     'graphicZIndex' properties directly from the specified 'style'  
     506     *     parameter, we create a new style object and set those properties  
     507     *     from the corresponding 'background'-prefixed properties from  
     508     *     specified 'style' parameter. 
     509     *  
     510     * Parameters: 
     511     * id - {String} 
     512     * geometry - {<OpenLayers.Geometry>} 
     513     * style - {Object} 
     514     * featureId - {String} 
     515     */ 
     516    redrawBackgroundNode: function(id, geometry, style, featureId) { 
     517        var backgroundStyle = OpenLayers.Util.extend({}, style); 
     518         
     519        // Set regular style attributes to apply to the background styles. 
     520        backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic; 
     521        backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset; 
     522        backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset; 
     523        backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex; 
     524         
     525        // Erase background styles. 
     526        backgroundStyle.backgroundGraphic = null; 
     527        backgroundStyle.backgroundXOffset = null; 
     528        backgroundStyle.backgroundYOffset = null; 
     529        backgroundStyle.backgroundGraphicZIndex = null; 
     530         
     531        this.redrawNode( 
     532            id + this.BACKGROUND_ID_SUFFIX,  
     533            geometry,  
     534            backgroundStyle,  
     535            null 
     536        ); 
     537    }, 
    161538 
    162539    /** 
    163540     * Method: drawGeometryNode 
     
    213590    /** 
    214591     * Method: postDraw 
    215592     * Things that have do be done after the geometry node is appended 
    216      * to its parent node. To be overridden by subclasses. 
     593     *     to its parent node. To be overridden by subclasses. 
    217594     *  
    218595     * Parameters: 
    219596     * node - {DOMElement} 
     
    223600    /** 
    224601     * Method: drawPoint 
    225602     * Virtual function for drawing Point Geometry.  
    226      * Should be implemented by subclasses. 
    227      * This method is only called by the renderer itself. 
     603     *     Should be implemented by subclasses. 
     604     *     This method is only called by the renderer itself. 
    228605     *  
    229606     * Parameters:  
    230607     * node - {DOMElement} 
     
    235612    /** 
    236613     * Method: drawLineString 
    237614     * Virtual function for drawing LineString Geometry.  
    238      * Should be implemented by subclasses. 
    239      * This method is only called by the renderer itself. 
     615     *     Should be implemented by subclasses. 
     616     *     This method is only called by the renderer itself. 
    240617     *  
    241618     * Parameters:  
    242619     * node - {DOMElement} 
     
    247624    /** 
    248625     * Method: drawLinearRing 
    249626     * Virtual function for drawing LinearRing Geometry.  
    250      * Should be implemented by subclasses. 
    251      * This method is only called by the renderer itself. 
     627     *     Should be implemented by subclasses. 
     628     *     This method is only called by the renderer itself. 
    252629     *  
    253630     * Parameters:  
    254631     * node - {DOMElement} 
     
    259636    /** 
    260637     * Method: drawPolygon 
    261638     * Virtual function for drawing Polygon Geometry.  
    262      * Should be implemented by subclasses. 
    263      * This method is only called by the renderer itself. 
     639     *    Should be implemented by subclasses. 
     640     *    This method is only called by the renderer itself. 
    264641     *  
    265642     * Parameters:  
    266643     * node - {DOMElement} 
     
    271648    /** 
    272649     * Method: drawRectangle 
    273650     * Virtual function for drawing Rectangle Geometry.  
    274      * Should be implemented by subclasses. 
    275      * This method is only called by the renderer itself. 
     651     *     Should be implemented by subclasses. 
     652     *     This method is only called by the renderer itself. 
    276653     *  
    277654     * Parameters:  
    278655     * node - {DOMElement} 
     
    283660    /** 
    284661     * Method: drawCircle 
    285662     * Virtual function for drawing Circle Geometry.  
    286      * Should be implemented by subclasses. 
    287      * This method is only called by the renderer itself. 
     663     *     Should be implemented by subclasses. 
     664     *     This method is only called by the renderer itself. 
    288665     *  
    289666     * Parameters:  
    290667     * node - {DOMElement} 
     
    295672    /** 
    296673     * Method: drawSurface 
    297674     * Virtual function for drawing Surface Geometry.  
    298      * Should be implemented by subclasses. 
    299      * This method is only called by the renderer itself. 
     675     *     Should be implemented by subclasses. 
     676     *     This method is only called by the renderer itself. 
    300677     *  
    301678     * Parameters:  
    302679     * node - {DOMElement} 
     
    312689     * 
    313690     * Returns: 
    314691     * {<OpenLayers.Geometry>} A geometry from an event that  
    315      *                         happened on a layer 
     692     *     happened on a layer. 
    316693     */ 
    317694    getFeatureIdFromEvent: function(evt) { 
    318695        var node = evt.target || evt.srcElement; 
     
    340717        } else {     
    341718            var element = OpenLayers.Util.getElement(geometry.id); 
    342719            if (element && element.parentNode) { 
     720                if (element.geometry) { 
     721                    element.geometry.destroy(); 
     722                    element.geometry = null; 
     723                } 
    343724                element.parentNode.removeChild(element); 
     725 
     726                this.indexer.remove(element); 
    344727            } 
     728 
     729            var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX; 
     730            var bElem = OpenLayers.Util.getElement(backgroundId); 
     731            if (bElem && bElem.parentNode && bElem.geometry) { 
     732                this.eraseGeometry(bElem.geometry);  
     733            } 
    345734        } 
    346735    },     
    347736 
     
    354743     *  
    355744     * Parameters: 
    356745     * id - {String} 
    357      * type - {String} type Kind of node to draw 
     746     * type - {String} type Kind of node to draw. 
    358747     *  
    359748     * Returns: 
    360      * {DOMElement} A new node of the given type and id 
     749     * {DOMElement} A new node of the given type and id. 
    361750     */ 
    362751    nodeFactory: function(id, type) { 
    363752        var node = OpenLayers.Util.getElement(id); 
     
    371760        } 
    372761        return node; 
    373762    }, 
     763     
     764    /**  
     765     * Method: createNode 
     766     *  
     767     * Parameters: 
     768     * type - {String} Kind of node to draw. 
     769     * id - {String} Id for node. 
     770     *  
     771     * Returns: 
     772     * {DOMElement} A new node of the given type and id. 
     773     *     This function must be overridden by subclasses. 
     774     */ 
     775    createNode: function(type, id) {}, 
    374776 
    375777    CLASS_NAME: "OpenLayers.Renderer.Elements" 
    376778}); 
  • lib/OpenLayers/Layer/Vector.js

    old new  
    140140     * {<OpenLayers.Renderer>} 
    141141     */ 
    142142    renderer: null, 
     143     
     144    /** 
     145     * APIProperty: yOrdering 
     146     * {String} Whether or not externalGraphic y-ordering is enabled on this  
     147     *     layer. Default is false. 
     148     */ 
     149    yOrdering: false, 
    143150    
    144151    /**  
    145152     * APIProperty: geometryType 
     
    222229        for (var i=0, len=this.renderers.length; i<this.renderers.length; i++) { 
    223230            var rendererClass = OpenLayers.Renderer[this.renderers[i]]; 
    224231            if (rendererClass && rendererClass.prototype.supported()) { 
    225                this.renderer = new rendererClass(this.div); 
    226                break; 
     232                this.renderer = new rendererClass(this.div, this.yOrdering); 
     233                break; 
    227234            }   
    228235        }   
    229236    }, 
     
    297304            this.renderer.setExtent(extent); 
    298305             
    299306            this.renderer.root.style.visibility = "visible"; 
    300              
     307 
    301308            // Force a reflow on gecko based browsers to prevent jump/flicker. 
    302309            // This seems to happen on only certain configurations; it was originally 
    303310            // noticed in FF 2.0 and Linux.