OpenLayers OpenLayers

Ticket #1083: graticule_v2.patch

File graticule_v2.patch, 18.4 kB (added by madair, 10 months ago)
  • examples/graticule.html

    old new  
     1<html xmlns="http://www.w3.org/1999/xhtml"> 
     2    <head> 
     3        <title>OpenLayers Graticule Example</title> 
     4 
     5        <link rel="stylesheet" href="../theme/default/style.css" type="text/css" /> 
     6        <link rel="stylesheet" href="style.css" type="text/css" /> 
     7        <style type="text/css"> 
     8            #map { 
     9                width: 600px; 
     10                height: 300px; 
     11                border: 1px solid black; 
     12                float:left; 
     13            } 
     14            #map2 { 
     15                width: 400px; 
     16                height: 400px; 
     17                border: 1px solid black; 
     18                float:left; 
     19            } 
     20        </style> 
     21        <script src="../lib/OpenLayers.js"></script> 
     22        <script src="http://proj4js.org/lib/proj4js-combined.js"></script> 
     23        <script type="text/javascript"> 
     24            Proj4js.defs["EPSG:42304"]="+title=Atlas of Canada, LCC +proj=lcc +lat_1=49 +lat_2=77 +lat_0=49 +lon_0=-95 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs"; 
     25             
     26            var map1, map2; 
     27            function init(){ 
     28              initLonLat(); 
     29              initProjected(); 
     30            } 
     31            function initLonLat(){ 
     32                map1 = new OpenLayers.Map('map', { 
     33                    controls: [ 
     34                    new OpenLayers.Control.Graticule({ 
     35                          numPoints: 2,  
     36                          labelled: true, 
     37                          visible: true 
     38                      }), 
     39                      new OpenLayers.Control.LayerSwitcher(), 
     40                      new OpenLayers.Control.PanZoomBar(), 
     41                      new OpenLayers.Control.Navigation() 
     42                      ] 
     43                }); 
     44 
     45                var ol_wms = new OpenLayers.Layer.WMS( "OpenLayers WMS", 
     46                    "http://labs.metacarta.com/wms/vmap0", 
     47                    {layers: 'basic'}, {wrapDateLine: true} ); 
     48 
     49                map1.addLayers([ol_wms]); 
     50                if (!map1.getCenter()) map1.zoomToMaxExtent(); 
     51            }; 
     52             
     53            function initProjected(){ 
     54                var extent = new OpenLayers.Bounds(-2200000,-712631,3072800,3840000); 
     55                var mapOptions = { 
     56                      controls: [ 
     57                      new OpenLayers.Control.Graticule({ 
     58                          labelled: true, 
     59                          targetSize: 200 
     60                        }), 
     61                        new OpenLayers.Control.LayerSwitcher(), 
     62                        new OpenLayers.Control.PanZoomBar(), 
     63                        new OpenLayers.Control.Navigation() 
     64                      ], 
     65                      //scales: tempScales, 
     66                      maxExtent: extent, 
     67                      maxResolution: 50000, 
     68                      units: 'm', 
     69                      projection: 'EPSG:42304' 
     70                }; 
     71                map2 = new OpenLayers.Map('map2', mapOptions); 
     72 
     73                var dm_wms = new OpenLayers.Layer.WMS( "DM Solutions Demo", 
     74                  "http://www2.dmsolutions.ca/cgi-bin/mswms_gmap", { 
     75                     layers: "bathymetry", 
     76                     format: "image/png" 
     77                  },{ 
     78                      singleTile: true 
     79                  }); 
     80 
     81                map2.addLayers([dm_wms]); 
     82                if (!map2.getCenter()) map2.zoomToExtent(extent); 
     83            } 
     84        </script> 
     85    </head> 
     86    <body onload="init()"> 
     87        <h1 id="title">Graticule Example</h1> 
     88 
     89        <div id="tags"> 
     90        </div> 
     91 
     92        <p id="shortdesc"> 
     93            Adds a Graticule control to the map to display a grid of  
     94            latitude and longitude.  
     95        </p> 
     96 
     97        <div id="map" class="smallmap"></div> 
     98        <div id="map2" class="smallmap"></div> 
     99 
     100        <div id="docs"></div> 
     101    </body> 
     102</html> 
  • lib/OpenLayers.js

    old new  
    166166            "OpenLayers/Control/NavigationHistory.js", 
    167167            "OpenLayers/Control/Measure.js", 
    168168            "OpenLayers/Control/WMSGetFeatureInfo.js", 
     169            "OpenLayers/Control/Graticule.js", 
    169170            "OpenLayers/Geometry.js", 
    170171            "OpenLayers/Geometry/Rectangle.js", 
    171172            "OpenLayers/Geometry/Collection.js", 
  • lib/OpenLayers/Control/Graticule.js

    old new  
     1/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license. 
     2 * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt  
     3 * for the full text of the license. */ 
     4 
     5/** 
     6 * @requires OpenLayers/Control.js 
     7 */ 
     8 
     9/** 
     10 * Class: OpenLayers.Control.Graticule 
     11 * The Graticule displays a grid of latitude/longitude lines reprojected on 
     12 * the map.   
     13 *  
     14 * Inherits from: 
     15 *  - <OpenLayers.Control> 
     16 *   
     17 */ 
     18OpenLayers.Control.Graticule = OpenLayers.Class(OpenLayers.Control, { 
     19 
     20    /** 
     21    * APIProperty: intervals 
     22    * {Array(Float)} A list of possible graticule widths in degrees. 
     23    */ 
     24    intervals: [ 45, 30, 20, 10, 5, 2, 1, 
     25                 0.5, 0.2, 0.1, 0.05, 0.01,  
     26                 0.005, 0.002, 0.001 ], 
     27 
     28    /** 
     29     * APIProperty: displayInLayerSwitcher 
     30     * {Boolean} Allows the Graticule control to be switched on and off.  
     31     * defaults to true. 
     32     */ 
     33    displayInLayerSwitcher: true, 
     34 
     35    /** 
     36     * APIProperty: visible 
     37     * {Boolean} should the graticule be initially visible (default=true) 
     38     */ 
     39    visible: true, 
     40 
     41    /** 
     42     * APIProperty: numPoints 
     43     * {Integer} The number of points to use in each graticule line.  Higher 
     44     * numbers result in a smoother curve for projected maps  
     45     */ 
     46    numPoints: 50, 
     47 
     48    /** 
     49     * APIProperty: targetSize 
     50     * {Integer} The maximum size of the grid in pixels on the map 
     51     */ 
     52    targetSize: 200, 
     53 
     54    /** 
     55     * APIProperty: labelled 
     56     * {Boolean} Should the graticule lines be labelled?. default=false 
     57     */ 
     58    labelled: true, 
     59 
     60    /** 
     61     * Property: gratLayer 
     62     * {OpenLayers.Layer.Vector} 
     63     */ 
     64    gratLayer: null, 
     65 
     66    /** 
     67     * Constructor: OpenLayers.Control.ScaleLine 
     68     * Create a new scale line control. 
     69     *  
     70     * Parameters: 
     71     * options - {Object} An optional object whose properties will be used 
     72     *     to extend the control. 
     73     */ 
     74    initialize: function(options) { 
     75        OpenLayers.Control.prototype.initialize.apply(this, [options]); 
     76    }, 
     77 
     78    /** 
     79     * Method: draw 
     80     *  
     81     * Returns: 
     82     * {DOMElement} 
     83     */ 
     84    draw: function() { 
     85        OpenLayers.Control.prototype.draw.apply(this, arguments); 
     86        if (!this.gratLayer) { 
     87            var gratStyle = new OpenLayers.Style({ 
     88                strokeColor: "#333", 
     89                strokeWidth: 1, 
     90                strokeOpacity: 0.5, 
     91                label: "${label}", 
     92                align: "ct" 
     93            }); 
     94            this.gratLayer = new OpenLayers.Layer.Vector("Graticule", { 
     95              styleMap: new OpenLayers.StyleMap(gratStyle), 
     96              visibility: this.visible, 
     97              labelOffset: new OpenLayers.Pixel(0,0), 
     98              displayInLayerSwitcher: this.displayInLayerSwitcher 
     99            }); 
     100            this.map.addLayer(this.gratLayer); 
     101        } 
     102        this.map.events.register('moveend', this, this.update); 
     103        this.update(); 
     104        return this.div; 
     105    }, 
     106 
     107    update: function() { 
     108        //wait for the map to be initialized before proceeding 
     109        var mapBounds = this.map.getExtent(); 
     110        if (!mapBounds) { 
     111          return; 
     112        } 
     113        var mapRect = mapBounds.toGeometry(); 
     114         
     115        //clear out the old grid 
     116        this.gratLayer.destroyFeatures(); 
     117         
     118        //get the projection objects required 
     119        var llProj = new OpenLayers.Projection("EPSG:4326"); 
     120        var mapProj = this.map.getProjectionObject(); 
     121        var mapRes = this.map.getResolution(); 
     122        if (mapProj.proj.projName == "longlat") { 
     123          this.numPoints = 1; 
     124        } 
     125         
     126        //get the map center in EPSG:4326 
     127        var mapCenter = this.map.getCenter(); //lon and lat here are really map x and y 
     128        var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); 
     129        OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); 
     130         
     131        /* This block of code determines the lon/lat interval to use for the 
     132         * grid by calculating the diagonal size of one grid cell at the map 
     133         * center.  Iterates through the intervals array until the diagonal 
     134         * length is less than the targetSize option. 
     135         */ 
     136        //find lat/lon interval that results in a grid of less than the target size 
     137        var testSq = this.targetSize*mapRes; 
     138        testSq *= testSq;   //compare squares rather than doing a square root to save time 
     139        var llInterval; 
     140        for (var i=0; i<this.intervals.length; ++i) { 
     141          llInterval = this.intervals[i];   //could do this for both x and y?? 
     142          var delta = llInterval/2;   
     143          var p1 = mapCenterLL.offset(new OpenLayers.Pixel(-delta, -delta));  //test coords in EPSG:4326 space 
     144          var p2 = mapCenterLL.offset(new OpenLayers.Pixel( delta,  delta)); 
     145          OpenLayers.Projection.transform(p1, llProj, mapProj); // convert them back to map projection 
     146          OpenLayers.Projection.transform(p2, llProj, mapProj); 
     147          var distSq = (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y); 
     148          if (distSq <= testSq) { 
     149            break; 
     150          } 
     151        } 
     152        //alert(llInterval); 
     153         
     154        //round the LL center to an even number based on the interval 
     155        mapCenterLL.x = Math.floor(mapCenterLL.x/llInterval)*llInterval; 
     156        mapCenterLL.y = Math.floor(mapCenterLL.y/llInterval)*llInterval; 
     157        //TODO adjust for minutses/seconds? 
     158         
     159        /* The following 2 blocks calculate the nodes of the grid along a  
     160         * line of constant longitude (then latitiude) running through the 
     161         * center of the map until it reaches the map edge.  The calculation 
     162         * goes from the center in both directions to the edge. 
     163         */ 
     164        //get the central longitude line, increment the latitude 
     165        var iter = 0 
     166        var centerLonPoints = [mapCenterLL.clone()]; 
     167        var newPoint = mapCenterLL.clone(); 
     168        var mapXY; 
     169        do { 
     170            newPoint = newPoint.offset(new OpenLayers.Pixel(0,llInterval)); 
     171            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     172            centerLonPoints.unshift(newPoint); 
     173        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     174        newPoint = mapCenterLL.clone(); 
     175        do {           
     176            newPoint = newPoint.offset(new OpenLayers.Pixel(0,-llInterval)); 
     177            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     178            centerLonPoints.push(newPoint); 
     179        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     180         
     181        //get the central latitude line, increment the longitude 
     182        iter = 0 
     183        var centerLatPoints = [mapCenterLL.clone()]; 
     184        newPoint = mapCenterLL.clone(); 
     185        do { 
     186            newPoint = newPoint.offset(new OpenLayers.Pixel(-llInterval, 0)); 
     187            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     188            centerLatPoints.unshift(newPoint); 
     189        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     190        newPoint = mapCenterLL.clone(); 
     191        do {           
     192            newPoint = newPoint.offset(new OpenLayers.Pixel(llInterval, 0)); 
     193            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     194            centerLatPoints.push(newPoint); 
     195        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     196         
     197        //now generate a line for each node in the central lat and lon lines 
     198        //first loop over constant longitude 
     199        var lines = []; 
     200        for(var i=0; i < centerLatPoints.length; ++i) { 
     201          var lon = centerLatPoints[i].x; 
     202          var pointList = []; 
     203          var latEnd = Math.min(centerLonPoints[0].y, 90); 
     204          var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); 
     205          var latDelta = (latEnd - latStart)/this.numPoints; 
     206          var lat = latStart; 
     207          var gridAttrs = { 
     208            value: lon, 
     209            label: this.labelled?OpenLayers.Util.getFormattedLonLat(lon, "lon"):"", 
     210            labelPos: null 
     211          };  
     212          for(var j=0; j<= this.numPoints; ++j) { 
     213            var gridPoint = new OpenLayers.Geometry.Point(lon,lat); 
     214            gridPoint.transform(llProj, mapProj); 
     215            pointList.push(gridPoint); 
     216            if (this.labelled) { 
     217              //keep track of when this grid line crosses the map bounds to set 
     218              //the label position 
     219              //labels along the bottom, add 10 pixel offset up into the map 
     220              //TODO add option for labels on top 
     221              if (gridPoint.y >= mapBounds.bottom && !gridAttrs.labelPos) { 
     222                gridAttrs.labelPos = new OpenLayers.Geometry.Point(gridPoint.x,mapBounds.bottom+10*mapRes); 
     223              } 
     224            } 
     225            lat += latDelta; 
     226          } 
     227          var geom = new OpenLayers.Geometry.LineString(pointList); 
     228          lines.push(new OpenLayers.Feature.Vector(geom, gridAttrs)); 
     229        } 
     230         
     231        //now draw the lines of constant latitude 
     232        for (var j=0; j < centerLonPoints.length; ++j) { 
     233          lat = centerLonPoints[j].y; 
     234          if (lat<-90 || lat>90) {  //latitudes only valid between -90 and 90 
     235            continue; 
     236          } 
     237          var pointList = []; 
     238          var lonStart = centerLatPoints[0].x; 
     239          var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; 
     240          var lonDelta = (lonEnd - lonStart)/this.numPoints; 
     241          var lon = lonStart; 
     242          var gridAttrs = { 
     243            value: lat, 
     244            label: this.labelled?OpenLayers.Util.getFormattedLonLat(lat, "lat"):"", 
     245            labelPos: null 
     246          };  
     247          for(var i=0; i <= this.numPoints ; ++i) { 
     248            var gridPoint = new OpenLayers.Geometry.Point(lon,lat); 
     249            gridPoint.transform(llProj, mapProj); 
     250            pointList.push(gridPoint); 
     251            if (this.labelled) { 
     252              //keep track of when this grid line crosses the map bounds to set 
     253              //the label position 
     254              //labels along the right, 30 pixel offset left into the map 
     255              //TODO add option for labels on left 
     256              if (gridPoint.x < mapBounds.right) { 
     257                gridAttrs.labelPos = new OpenLayers.Geometry.Point(mapBounds.right-30*mapRes, gridPoint.y+6*mapRes); 
     258              } 
     259            } 
     260            lon += lonDelta; 
     261          } 
     262          var geom = new OpenLayers.Geometry.LineString(pointList); 
     263          lines.push(new OpenLayers.Feature.Vector(geom, gridAttrs)); 
     264        } 
     265        this.gratLayer.addFeatures(lines); 
     266    }, 
     267     
     268    CLASS_NAME: "OpenLayers.Control.Graticule" 
     269}); 
     270 
     271OpenLayers.Util.getFormattedLonLat = function(coordinate, axis) { 
     272    var abscoordinate = Math.abs(coordinate) 
     273    var coordinatedegrees = Math.floor(abscoordinate); 
     274 
     275    var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60); 
     276    var tempcoordinateminutes = coordinateminutes; 
     277    coordinateminutes = Math.floor(coordinateminutes); 
     278    var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60); 
     279    coordinateseconds =  Math.round(coordinateseconds*10); 
     280    coordinateseconds /= 10; 
     281 
     282    if( coordinatedegrees < 10 ) { 
     283      coordinatedegrees = "0" + coordinatedegrees; 
     284    } 
     285 
     286    if( coordinateminutes < 10 ) { 
     287      coordinateminutes = "0" + coordinateminutes; 
     288    } 
     289 
     290    if( coordinateseconds < 10 ) { 
     291      coordinateseconds = "0" + coordinateseconds; 
     292    } 
     293    var str = coordinatedegrees + " ";  //get degree symbol here somehow for SVG/VML labelling 
     294    str += coordinateminutes + "'"; 
     295    str += coordinateseconds + '"'; 
     296    if (axis == "lon") { 
     297      str += coordinate < 0 ? "W" : "E"; 
     298    } else { 
     299      str += coordinate < 0 ? "S" : "N"; 
     300    } 
     301    return str; 
     302}; 
     303 
  • lib/OpenLayers/Layer/Vector.js

    old new  
    157157    style: null, 
    158158     
    159159    /** 
    160      * Property: styleMap 
     160     * APIProperty: styleMap 
    161161     * {<OpenLayers.StyleMap>} 
    162162     */ 
    163163    styleMap: null, 
    164164     
    165165    /** 
     166     * APIProperty: labelOffset 
     167     * {<OpenLayers.Pixel>} Offset in pixels to be applied to feature centroid 
     168     * for labels.  An offset value set on the layer applies to all features of 
     169     * the layer but may be overriden by a labelOffest on individual features. 
     170     * deafult is no offset. 
     171     */ 
     172    labelOffset: null, 
     173     
     174    /** 
    166175     * Property: strategies 
    167176     * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer. 
    168177     */ 
  • lib/OpenLayers/Renderer.js

    old new  
    178178                } 
    179179                var rendered = this.drawGeometry(feature.geometry, style, feature.id); 
    180180                if(style.display != "none" && style.label && rendered !== false) { 
    181                     this.drawText(feature.id, style, feature.geometry.getCentroid()); 
     181                    var location = feature.attributes.labelPos ?  
     182                      feature.attributes.labelPos : feature.geometry.getCentroid(); 
     183                    if (feature.layer.labelOffset) { 
     184                      var res = this.getResolution(); 
     185                      location.move(feature.layer.labelOffset.x*res, feature.layer.labelOffset.y*res); 
     186                    } 
     187                    this.drawText(feature.id, style, location); 
    182188                } else { 
    183189                    this.removeText(feature.id); 
    184190                }