OpenLayers OpenLayers

Ticket #1357: reviewwithexample.patch

File reviewwithexample.patch, 34.9 kB (added by tcoulter, 1 month ago)

Now with 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) { 
    44         t.plan(5); 
     78        t.plan(8); 
    4579         
    46         OpenLayers.Renderer.Elements.prototype._initialize = 
    47             OpenLayers.Renderer.Elements.prototype.initialize; 
    48          
    49         OpenLayers.Renderer.Elements.prototype.initialize = function() {} 
    50          
    5180        var g_Clear = false, g_Destroy = false; 
    5281         
    5382        OpenLayers.Renderer.prototype._destroy =  
     
    5786            g_Destroy = true; 
    5887        }; 
    5988         
     89        // Stub out SVG's nodeFactory 
     90        OpenLayers.Renderer.SVG.prototype.nodeFactory = function() { 
     91            return document.createElement("div"); 
     92        } 
     93         
    6094        var r = new OpenLayers.Renderer.SVG(document.body); 
     95         
    6196        r.clear = function() { 
    6297            g_Clear = true; 
    6398        }; 
    64         r.rendererRoot = 'foo'; 
    65         r.root = 'bar'; 
    66         r.xmlns = 'dude'; 
    6799         
     100        // Test assumptions. 
     101        t.ok(r.rendererRoot !== null, "rendererRoot not null"); 
     102        t.ok(r.rootnull !== "root not null"); 
     103        t.ok(r.xmlns !== "xmlns not null"); 
     104 
    68105        r.destroy(); 
    69106         
    70107        t.eq(g_Clear, true, "OpenLayers.Renderer.Elements.clear() called"); 
     
    73110        t.eq(r.xmlns, null, "xmlns nullified"); 
    74111        t.eq(g_Destroy, true, "OpenLayers.Renderer.destroy() called"); 
    75112         
    76         OpenLayers.Renderer.Elements.prototype.initialize = 
    77             OpenLayers.Renderer.Elements.prototype._initialize; 
    78113        OpenLayers.Renderer.prototype.destroy =  
    79114            OpenLayers.Renderer.prototype._destroy; 
    80115    } 
     
    82117    function test_Elements_clear(t) { 
    83118        t.plan(1); 
    84119         
    85         OpenLayers.Renderer.Elements.prototype._initialize = 
    86             OpenLayers.Renderer.Elements.prototype.initialize; 
     120        setUp(); 
    87121         
    88         OpenLayers.Renderer.Elements.prototype.initialize = function() {} 
    89          
    90         var r = new OpenLayers.Renderer.Elements(); 
     122        var r = create_renderer(); 
    91123        var element = document.createElement("div"); 
    92124        r.root = element; 
    93125         
     
    98130         
    99131        t.ok(r.root.childNodes.length == 0, "root is correctly cleared"); 
    100132         
    101         OpenLayers.Renderer.Elements.prototype.initialize = 
    102             OpenLayers.Renderer.Elements.prototype._initialize; 
     133        tearDown(); 
    103134    } 
    104135     
    105136    function test_Elements_drawGeometry(t) { 
    106137        t.plan(5); 
     138 
     139        setUp(); 
     140 
     141        var r = create_renderer(); 
    107142         
    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          
    115143        var element = document.createElement("div"); 
    116144        r.root = element; 
    117145 
     
    147175        var style = {'display':'none'}; 
    148176        r.drawGeometry(geometry, style, featureId); 
    149177        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; 
     178             
     179        tearDown(); 
    154180    } 
    155181 
    156182    function test_Elements_drawGeometry_2(t) { 
    157183        t.plan(9); 
    158184         
    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(); 
     185        setUp(); 
    165186         
     187        var r = create_renderer(); 
     188         
    166189        var element = document.createElement("div"); 
    167190        r.root = element; 
    168191         
     
    281304        style = true; 
    282305        r.drawGeometry(geometry, style); 
    283306        t.ok(properDraw, "drawGeometry called drawPolygon when passed a multi-polygon"); 
    284          
    285         OpenLayers.Renderer.Elements.prototype.initialize = 
    286             OpenLayers.Renderer.Elements.prototype._initialize; 
     307       
     308        tearDown(); 
    287309    } 
    288310     
    289311    function test_Elements_getfeatureidfromevent(t) { 
     
    310332    function test_Elements_erasegeometry(t) { 
    311333        t.plan(5); 
    312334         
     335        setUp(); 
     336         
    313337        var el = document.createElement('div'); 
    314338        document.body.appendChild(el); 
    315339        el.id = 'bar'; 
    316340        var geometry = { 
    317             id: 'bar' 
     341            id: el.id 
    318342        }; 
    319343         
    320         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     344        var r = create_renderer(el.id); 
     345         
     346        r.eraseGeometry(geometry); 
    321347        t.ok(el.parentNode != document.body, "element correctly removed"); 
    322348 
    323349        var el = document.createElement('div'); 
     
    330356            }] 
    331357        }; 
    332358 
    333         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     359        r.eraseGeometry(geometry); 
    334360        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a multipoint"); 
    335361         
    336362        var el = document.createElement('div'); 
     
    343369            }] 
    344370        }; 
    345371         
    346         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     372        r.eraseGeometry(geometry); 
    347373        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a multilinestring"); 
    348374         
    349375        var el = document.createElement('div'); 
     
    356382            }] 
    357383        }; 
    358384         
    359         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     385        r.eraseGeometry(geometry); 
    360386        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a multipolygon"); 
    361387         
    362388        var el = document.createElement('div'); 
     
    369395            }] 
    370396        }; 
    371397         
    372         OpenLayers.Renderer.Elements.prototype.eraseGeometry(geometry); 
     398        r.eraseGeometry(geometry); 
    373399        t.ok(el.parentNode != document.body, "geometry components correctly removed when passed a collection"); 
     400         
     401        tearDown(); 
    374402    }     
    375403 
    376404  </script> 
  • lib/OpenLayers/Renderer/Elements.js

    old new  
    55/** 
    66 * @requires OpenLayers/Renderer.js 
    77 */ 
     8/** 
     9 * Class: OpenLayers.ElementsIndexer 
     10 * This class takes care of figuring out which order elements should be 
     11 * placed in the DOM based on given indexing methods.  
     12 */ 
     13OpenLayers.ElementsIndexer = OpenLayers.Class({ 
     14    
     15    /** 
     16     * Property: maxZIndex 
     17     * {Integer} This is the largest-most z-index value for a node 
     18     * contained within the indexer. 
     19     */ 
     20    maxZIndex: null, 
     21     
     22    /** 
     23     * Property: order 
     24     * {Array<String>} This is an array of node id's stored in the 
     25     * order that they should show up on screen. Id's higher up in the 
     26     * array (higher array index) represent nodes with higher z-indeces. 
     27     */ 
     28    order: null,  
     29     
     30    /** 
     31     * Property: indices 
     32     * {Hash} This is a hash that maps node ids to their z-index value 
     33     * stored in the indexer. This is done to make finding a nodes z-index  
     34     * value O(1). 
     35     */ 
     36    indices: null, 
     37     
     38    /** 
     39     * Property: compare 
     40     * {Function} This is the function used to determine placement of 
     41     * of a new node within the indexer. If null, this defaults to to 
     42     * the Z_ORDER_DRAWING_ORDER comparison method. 
     43     */ 
     44    compare: null, 
     45    
     46    /** 
     47     * APIMethod: initialize 
     48     * Create a new indexer with  
     49     *  
     50     * Parameters: 
     51     * yOordering - {Function} Whether to use y-ordering. 
     52     */ 
     53    initialize: function(yOrdering) { 
    854 
     55        this.compare = yOrdering ?  
     56            OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER : 
     57            OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER; 
     58             
     59        this.order = []; 
     60        this.indices = {}; 
     61        this.maxZIndex = 0; 
     62    }, 
     63     
     64    /** 
     65     * APIMethod: insert 
     66     * Insert a new node into the indexer. In order to find the correct positioning for 
     67     * the node to be inserted, this method uses a binary search. This makes inserting 
     68     * O(log(n)).  
     69     *  
     70     * Parameters: 
     71     * newNode - The new node to be inserted. 
     72     */ 
     73    insert: function(newNode) { 
     74        var nodeId = this.getNodeId(newNode); 
     75         
     76        this.determineZIndex(newNode);        
     77 
     78        var leftIndex = -1; 
     79        var rightIndex = this.order.length; 
     80        var middle; 
     81 
     82        while (rightIndex - leftIndex > 1) { 
     83            middle = parseInt((leftIndex + rightIndex) / 2); 
     84             
     85            var nextId = this.order[middle]; 
     86            var next = OpenLayers.Util.getElement(nextId); 
     87             
     88            var placement = this.compare(this, newNode, next); 
     89             
     90            if (placement > 0) { 
     91                leftIndex = middle; 
     92            } else { 
     93                rightIndex = middle; 
     94            }  
     95        } 
     96         
     97        this.order.splice(rightIndex, 0, nodeId); 
     98        this.indices[nodeId] = this.getZIndex(newNode); 
     99         
     100        // Return the next item in the array -- the id of the node that should 
     101        // follow this one directly in the index order -- if any. 
     102        var nextIndex = rightIndex + 1; 
     103         
     104        var returnVal = null; 
     105        if (nextIndex > 0 && nextIndex < this.order.length) { 
     106            returnVal = this.order[nextIndex]; 
     107        } 
     108        return returnVal; 
     109    }, 
     110     
     111    remove: function(node) { 
     112        var nodeId = this.getNodeId(node); 
     113        var arrayIndex = this.order.indexOf(nodeId); 
     114        if (arrayIndex >= 0) { 
     115            // Remove it from the order array, as well as deleting the node 
     116            // from the indeces hash. 
     117            this.order.splice(arrayIndex, 1); 
     118            delete this.indices[nodeId]; 
     119             
     120            // Reset the maxium z-index based on the last item in the order array. 
     121            var lastId = this.order[this.order.length - 1]; 
     122            this.maxZIndex = this.indices[lastId]; 
     123        } 
     124    }, 
     125     
     126    exists: function(node) { 
     127        var nodeId = this.getNodeId(node); 
     128        return this.indices[nodeId] != null;   
     129    }, 
     130     
     131    /** 
     132     * APIMethod: getZIndex 
     133     * Get the z-index value for the current node from the node data itself. 
     134     */ 
     135    getZIndex: function(node) { 
     136        return node._style.graphicZIndex;   
     137    }, 
     138 
     139    /** 
     140     * APIMethod: getMaxZIndex 
     141     * Get the maximum z-index stored within the indexer. 
     142     */ 
     143    getMaxZIndex: function() { 
     144        return this.maxZIndex; 
     145    }, 
     146     
     147    /** 
     148     * APIMethod: setZIndex 
     149     * Set the z-index for the given node. 
     150     */ 
     151    setZIndex: function(node, zIndex) { 
     152        node._style.graphicZIndex = zIndex;   
     153    }, 
     154     
     155    /** 
     156     * Method: determineZIndex 
     157     * Determine the z-index for the current node if there isn't one,  
     158     * and set the maximum value if we've found a new maximum. 
     159     */ 
     160    determineZIndex: function(node) { 
     161        var zIndex = node._style.graphicZIndex; 
     162         
     163        // Everything must have a zIndex. If none is specified, 
     164        // this means the user *must* (hint: assumption) want this 
     165        // node to succomb to drawing order. To enforce drawing order 
     166        // over all indexing methods, we'll create a new z-index that's 
     167        // greater than any currently in the indexer. 
     168        if (zIndex == null) { 
     169            zIndex = this.maxZIndex; 
     170        } 
     171         
     172        if (zIndex > this.maxZIndex) { 
     173            this.maxZIndex = zIndex; 
     174        } 
     175         
     176        node._style.graphicZIndex = zIndex; 
     177    }, 
     178     
     179    /** 
     180     * Method: getNodeId 
     181     * Get the id of the node passed in. 
     182     */ 
     183    getNodeId: function(node) { 
     184        return node.id;   
     185    }, 
     186    
     187    CLASS_NAME: "OpenLayers.ElementsIndexer" 
     188}); 
     189 
     190 
     191// These are the compare methods for figuring out where a new 
     192// node should be placed within the indexer. These methods are very  
     193// similar to general sorting methods in that they return -1, 0, and 1  
     194// to specify the direction in which new nodes fall in the ordering. 
     195OpenLayers.ElementsIndexer.IndexingMethods = { 
     196    /** 
     197     * Method: Z_ORDER 
     198     * This compare method is used by other comparison methods. 
     199     * It can be used individually for ordering, but is not recommended, 
     200     * because it doesn't subscribe to drawing order. 
     201     */     
     202    Z_ORDER: function(indexer, newNode, next) { 
     203        var newZIndex = indexer.getZIndex(newNode); 
     204 
     205        var returnVal = 0; 
     206        if (next) { 
     207            var nextZIndex = indexer.getZIndex(next); 
     208            returnVal = newZIndex - nextZIndex;  
     209        } 
     210         
     211        return returnVal; 
     212    }, 
     213    /** 
     214     * API Method: Z_ORDER_DRAWING_ORDER 
     215     * This method orders nodes by their z-index, but does so in a way 
     216     * that, if there are other nodes with the same z-index, the newest drawn 
     217     * will be the front most within that z-index. This is the default 
     218     * indexing method. 
     219     */ 
     220    Z_ORDER_DRAWING_ORDER: function(indexer, newNode, next) { 
     221        var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, next); 
     222         
     223        // Make Z_ORDER subscribe to drawing order by pushing it above 
     224        // all of the other nodes with the same z-index. 
     225        if (next && returnVal == 0) { 
     226            returnVal = 1; 
     227        } 
     228         
     229        return returnVal; 
     230    }, 
     231    /** 
     232     * API Method: Z_ORDER_Y_ORDER 
     233     * This one should really be called Z_ORDER_Y_ORDER_DRAWING_ORDER, as it 
     234     * best describes which ordering methods have precedence (though, the name would 
     235     * be too long). This method orders nodes by their z-index, but does so in a way 
     236     * that, if there are other nodes with the same z-index, the nodes with the 
     237     * lower y position will be "closer" than those with a higher y position.  
     238     * If two nodes have the exact same y position, however, then this method 
     239     * will revert to using drawing order to decide placement. 
     240     */ 
     241    Z_ORDER_Y_ORDER: function(indexer, newNode, next) { 
     242        var returnVal = OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(indexer, newNode, next); 
     243         
     244        if (next && returnVal == 0) { 
     245            var newLat = newNode._geometry.getBounds().bottom; 
     246            var nextLat = next._geometry.getBounds().bottom; 
     247             
     248            var result = nextLat - newLat; 
     249             
     250            if (result == 0) { 
     251                returnVal = 1; 
     252            } else { 
     253                returnVal = result; 
     254            } 
     255        } 
     256         
     257        return returnVal;        
     258    } 
     259} 
     260 
    9261/** 
    10262 * Class: OpenLayers.Renderer.Elements 
    11263 * This is another virtual class in that it should never be instantiated by  
     
    42294    xmlns: null, 
    43295     
    44296    /** 
     297     * Property: Indexer 
     298     * An instance of OpenLayers.ElementsIndexer created upon 
     299     * initialization. 
     300     */ 
     301    indexer: null,  
     302     
     303    BACKGROUND_ID_SUFFIX: "_background", 
     304     
     305    /** 
    45306     * Property: minimumSymbolizer 
    46307     * {Object} 
    47308     */ 
     
    57318     *  
    58319     * Parameters: 
    59320     * containerID - {String} 
     321     * yOrdering - {Boolean} Whether or not y-ordering is enabled. 
    60322     */ 
    61     initialize: function(containerID) { 
     323    initialize: function(containerID, yOrdering) { 
    62324        OpenLayers.Renderer.prototype.initialize.apply(this, arguments); 
    63325 
    64326        this.rendererRoot = this.createRenderRoot(); 
     
    66328         
    67329        this.rendererRoot.appendChild(this.root); 
    68330        this.container.appendChild(this.rendererRoot); 
     331         
     332        this.indexer = new OpenLayers.ElementsIndexer(yOrdering); 
    69333    }, 
    70334     
    71335    /** 
     
    135399            return; 
    136400        }; 
    137401 
     402        var id = geometry.id; 
     403         
     404        if (style.backgroundGraphic) { 
     405            this.redrawBackgroundNode(id, geometry, style, featureId); 
     406        } 
     407         
    138408        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); 
     409            this.redrawNode(id, geometry, style, featureId);  
    154410        } else { 
    155             node = OpenLayers.Util.getElement(geometry.id); 
     411            node = OpenLayers.Util.getElement(id); 
    156412            if (node) { 
    157413                node.parentNode.removeChild(node); 
    158414            } 
    159415        } 
    160416    }, 
     417     
     418    redrawNode: function(id, geometry, style, featureId) { 
     419        // Get the node if it's already on the map. 
     420        var currentNode = OpenLayers.Util.getElement(id); 
     421         
     422        // Create a new node, or use the current one if it's 
     423        // already there. 
     424        var newNode; 
     425        if (!currentNode) { 
     426            var nodeType = this.getNodeType(geometry, style); 
     427            newNode = this.createNode(nodeType, id); 
     428        } else { 
     429            newNode = currentNode; 
     430        } 
     431         
     432        // Set the data for the node, then draw it. 
     433        newNode._featureId = featureId; 
     434        newNode._geometry = geometry; 
     435        newNode._geometryClass = geometry.CLASS_NAME; 
     436        newNode._style = style; 
     437        newNode = this.drawGeometryNode(newNode, geometry, style); 
     438         
     439        // If the node is known to the indexer, remove it so we can 
     440        // recalculate where it should go. 
     441        if (this.indexer.exists(newNode)) { 
     442            this.indexer.remove(newNode); 
     443        } 
     444         
     445        // Insert the node into the indexer so it can show us where to place it. 
     446        // Note that this operation is O(log(n)). If there's a performance problem 
     447        // (when dragging, for instance) this is likely where it would be. 
     448        var nextNodeId = this.indexer.insert(newNode); 
    161449 
     450        // If the new node should be before another in the index 
     451        // order, insert the new node before the next; else, lets just 
     452        // append the new one on the end, making it the highest in the index order. 
     453        if (nextNodeId) { 
     454            var nextNode = OpenLayers.Util.getElement(nextNodeId); 
     455            this.root.insertBefore(newNode, nextNode); 
     456        } else { 
     457            this.root.appendChild(newNode); 
     458        } 
     459         
     460        this.postDraw(newNode);  
     461    }, 
     462     
     463    redrawBackgroundNode: function(id, geometry, style, featureId) { 
     464        var backgroundStyle = OpenLayers.Util.extend({}, style); 
     465         
     466        // Set regular style attributes to apply to the background styles. 
     467        backgroundStyle.externalGraphic = backgroundStyle.backgroundGraphic; 
     468        backgroundStyle.graphicXOffset = backgroundStyle.backgroundXOffset; 
     469        backgroundStyle.graphicYOffset = backgroundStyle.backgroundYOffset; 
     470        backgroundStyle.graphicZIndex = backgroundStyle.backgroundGraphicZIndex; 
     471         
     472        // Erase background styles. 
     473        backgroundStyle.backgroundGraphic = null; 
     474        backgroundStyle.backgroundXOffset = null; 
     475        backgroundStyle.backgroundYOffset = null; 
     476        backgroundStyle.backgroundGraphicZIndex = null; 
     477         
     478        this.redrawNode(id + this.BACKGROUND_ID_SUFFIX, geometry, backgroundStyle, null); 
     479    }, 
     480 
    162481    /** 
    163482     * Method: drawGeometryNode 
    164483     * Given a node, draw a geometry on the specified layer. 
     
    338657                this.eraseGeometry(geometry.components[i]); 
    339658            } 
    340659        } else {     
    341             var element = OpenLayers.Util.getElement(geometry.id); 
     660         
     661            // TODO: Functionalize the next two blocks. 
     662            var elementId = geometry.id; 
     663            var element = OpenLayers.Util.getElement(elementId); 
    342664            if (element && element.parentNode) { 
     665                if (element.geometry) { 
     666                    element.geometry.destroy(); 
     667                    element.geometry = null; 
     668                } 
    343669                element.parentNode.removeChild(element); 
     670                 
     671                this.indexer.remove(element); 
    344672            } 
     673             
     674            var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX; 
     675            var backgroundElement = OpenLayers.Util.getElement(backgroundId); 
     676            if (backgroundElement && backgroundElement.parentNode) { 
     677                if (backgroundElement.geometry) { 
     678                    backgroundElement.geometry.destroy(); 
     679                    backgroundElement.geometry = null; 
     680                } 
     681                backgroundElement.parentNode.removeChild(backgroundElement); 
     682                 
     683                this.indexer.remove(backgroundElement); 
     684            } 
    345685        } 
    346     },     
    347  
     686    }, 
     687     
    348688    /**  
    349689     * Method: nodeFactory 
    350690     * Create new node of the specified type, with the (optional) specified id. 
     
    371711        } 
    372712        return node; 
    373713    }, 
     714     
     715    /**  
     716     * Method: createNode 
     717     *  
     718     * Parameters: 
     719     * type - {String} Kind of node to draw 
     720     * id - {String} Id for node 
     721     *  
     722     * Returns: 
     723     * {DOMElement} A new node of the given type and id. 
     724     * This function must be overridden by subclasses. 
     725     */ 
     726    createNode: function(type, id) {}, 
    374727 
    375728    CLASS_NAME: "OpenLayers.Renderer.Elements" 
    376729}); 
  • 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; 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    }, 
  • examples/ordering.html

    old new  
     1<html xmlns="http://www.w3.org/1999/xhtml"> 
     2  <head> 
     3    <link rel="stylesheet" href="../theme/default/style.css" type="text/css" /> 
     4    <link rel="stylesheet" href="style.css" type="text/css" /> 
     5    <style type="text/css"> 
     6        .smallmap { 
     7            width: 300px; 
     8        } 
     9         
     10        .docs { 
     11            padding: 0px 5px; 
     12        } 
     13         
     14        td { 
     15            vertical-align: top; 
     16        } 
     17         
     18    </style> 
     19    <script src="../lib/OpenLayers.js" type="text/javascript"></script> 
     20    <script type="text/javascript"> 
     21         
     22        var GOLD_Z_INDEX = 15; 
     23        var FIRST_RED_Z_INDEX = 10; 
     24        var SECOND_RED_Z_INDEX = 11; 
     25         
     26        var RADIUS_FROM_CENTER = 40; 
     27        var POINT_DISTANCE = 10; 
     28             
     29        function initYOrderMap() { 
     30            var map = new OpenLayers.Map("yorder"); 
     31             
     32            var layer = new OpenLayers.Layer.Vector( 
     33                "Y-Order", 
     34                { 
     35                    styleMap: new OpenLayers.StyleMap({ 
     36                        externalGraphic: "../img/marker-gold.png", 
     37                        pointRadius: 10, 
     38                        graphicZIndex: GOLD_Z_INDEX 
     39                    }), 
     40                    isBaseLayer: true, 
     41                    yOrdering: true 
     42                } 
     43            ); 
     44             
     45            map.addLayers([layer]); 
     46            map.zoomToMaxExtent(); 
     47             
     48            // Add features to the layers to show off z-index/y-ordering. 
     49            // We do this after adding the layer so we can work in pixels. 
     50            var center = map.getViewPortPxFromLonLat(map.getCenter()); 
     51             
     52            var top = new OpenLayers.Pixel(center.x, center.y - RADIUS_FROM_CENTER); 
     53            var bottom = new OpenLayers.Pixel(center.x, center.y + RADIUS_FROM_CENTER); 
     54            var left = new OpenLayers.Pixel(center.x - RADIUS_FROM_CENTER, center.y - POINT_DISTANCE / 2); 
     55            var right = new OpenLayers.Pixel(center.x + RADIUS_FROM_CENTER, center.y - POINT_DISTANCE / 2); 
     56             
     57            // Add the ordering features. These are the gold ones that all have the same z-index 
     58            // and succomb to y-ordering. 
     59            var orderingFeatures = []; 
     60            // Note: We use > here on purpose (instead of >= ), as well as subtracting the 
     61            // the POINT_DISTANCE in the beginning of the loop (as opposed to the end). 
     62            // This is purely for symmetry. Also note that the gold features are drawn 
     63            // from bottom to top so as to quickly signal whether or not y-ordering is working. 
     64            while (bottom.y > top.y) { 
     65                bottom.y -= POINT_DISTANCE; 
     66                var lonLat = map.getLonLatFromViewPortPx(bottom); 
     67                orderingFeatures.push( 
     68                    new OpenLayers.Feature.Vector( 
     69                        new OpenLayers.Geometry.Point(lonLat.lon, lonLat.lat) 
     70                    ) 
     71                ); 
     72            } 
     73           
     74            layer.addFeatures(orderingFeatures); 
     75             
     76            // Add the z-index features. Technically, these features succomb to y-ordering 
     77            // as well; however, since they have different z-indexes, the z-indexes take  
     78            // precedence. 
     79            var indexFeatures = []; 
     80            var useFirst = true; 
     81            while (left.x <= right.x) { 
     82                var lonLat = map.getLonLatFromViewPortPx(left); 
     83                var point = new OpenLayers.Feature.Vector( 
     84                    new OpenLayers.Geometry.Point(lonLat.lon, lonLat.lat) 
     85                ); 
     86                 
     87                // This is where the magic happens. We override the style on the layer 
     88                // to give our own style with alternativing z-indexes. 
     89                point.style = { 
     90                    graphicZIndex: useFirst ? FIRST_RED_Z_INDEX : SECOND_RED_Z_INDEX, 
     91                    externalGraphic: "../img/marker.png", 
     92                    pointRadius: 10 
     93                } 
     94                 
     95                indexFeatures.push( 
     96                    point 
     97                ); 
     98                 
     99                left.x += POINT_DISTANCE; 
     100                useFirst = !useFirst; 
     101            } 
     102             
     103            layer.addFeatures(indexFeatures); 
     104        } 
     105         
     106        function initDrawingOrderMap() { 
     107            var map = new OpenLayers.Map("drawingorder"); 
     108             
     109            var layer = new OpenLayers.Layer.Vector( 
     110                "Drawing Order", 
     111                { 
     112                    // Note there's no z-index set, and yOrdering is left 
     113                    // to its default. 
     114                    styleMap: new OpenLayers.StyleMap({ 
     115                        externalGraphic: "../img/marker-green.png", 
     116                        pointRadius: 10 
     117                    }), 
     118                    isBaseLayer: true 
     119                } 
     120            ); 
     121             
     122            map.addLayers([layer]); 
     123            map.zoomToMaxExtent(); 
     124             
     125            // Add features to the layers to show off z-index/y-ordering. 
     126            // We do this after adding the layer so we can work in pixels. 
     127            var center = map.getViewPortPxFromLonLat(map.getCenter()); 
     128             
     129            var top = new OpenLayers.Pixel(center.x, center.y - RADIUS_FROM_CENTER); 
     130            var bottom = new OpenLayers.Pixel(center.x, center.y + RADIUS_FROM_CENTER); 
     131            var left = new OpenLayers.Pixel(center.x - RADIUS_FROM_CENTER, center.y); 
     132            var right = new OpenLayers.Pixel(center.x + RADIUS_FROM_CENTER, center.y); 
     133             
     134            // Add the ordering features. These are the gold ones that all have the same z-index 
     135            // and succomb to y-ordering. 
     136            var orderingFeatures = []; 
     137            while (bottom.y > top.y && left.x < right.x) { 
     138                var bottomLonLat = map.getLonLatFromViewPortPx(bottom); 
     139                var leftLonLat = map.getLonLatFromViewPortPx(left); 
     140                orderingFeatures.push( 
     141                    new OpenLayers.Feature.Vector( 
     142                        new OpenLayers.Geometry.Point(leftLonLat.lon, bottomLonLat.lat) 
     143                    ) 
     144                ); 
     145                bottom.y -= POINT_DISTANCE / 2; // Divide by 2 for better visual. 
     146                left.x += POINT_DISTANCE / 2; 
     147            } 
     148           
     149            layer.addFeatures(orderingFeatures); 
     150        } 
     151 
     152        function init(){ 
     153            initYOrderMap(); 
     154            initDrawingOrderMap(); 
     155        }; 
     156         
     157    </script> 
     158  </head> 
     159  <body onload="init()"> 
     160        <h1 id="title">Z-Index/Y-Order Example</h1> 
     161 
     162        <div id="tags"> 
     163        </div> 
     164 
     165        <p id="shortdesc"> 
     166           This example shows the use of z-indexing and y-ordering of external graphics. Zoom in and out to see this behavior. 
     167        </p> 
     168 
     169        <h3>Z-Index (with Y-Ordering enabled)</h3> 
     170        <table> 
     171            <tr> 
     172                <td> 
     173                    <div id="yorder" class="smallmap"></div> 
     174                </td> 
     175                <td> 
     176                    <div class="docs"> 
     177                        In this map, the gold features all have the same z-index, and the red features have alternating z-indeces. The gold features' z-index is greater than the red features' z-indeces, which is why gold features look to be drawn on top of the red features. Since each gold feature has the same z-index, gold features succomb to y-ordering: this is where features that seem closest to the viewer (lower lattitude) show up above those that seem farther away (higher lattitude). 
     178                        <br><br> 
     179                        All vector layers have z-indexing enabled by default, but are not enabled with y-ordering. You can enable y-ordering by passing the parameter <i>yOrdering: true</i> in the vector layer's options hash. For all configurations, if features have the same z-index -- and if y-ordering is enabled: the same lattitude -- those features will succomb to drawing order, where the last feature to be drawn will appear above the rest. 
     180                    </div> 
     181                </td> 
     182            </tr> 
     183        </table> 
     184        <br> 
     185        <h3>Drawing Order (no Z-Indexes set, and Y-Ordering disabled)</h3> 
     186        <table> 
     187            <tr> 
     188                <td> 
     189                    <div id="drawingorder" class="smallmap"></div> 
     190                </td> 
     191                <td> 
     192                    <div class="docs"> 
     193                        In this map, features are not given z-indexes, and the layer's <i>yOrdering</i> parameter is set to the default (false). This configuration makes features succomb to drawing order instead of z-index order or y-order. 
     194                        <br><br> 
     195                        The features in this map were drawn from left to right and bottom to top, diagonally, to show that y-ordering is not enabled. 
     196                    </div> 
     197                </td> 
     198            </tr> 
     199        </table> 
     200         
     201         
     202    </body> 
     203</html>