OpenLayers OpenLayers

Ticket #1083: graticule_v3.patch

File graticule_v3.patch, 20.4 kB (added by madair, 5 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-compressed.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  
    168168            "OpenLayers/Control/NavigationHistory.js", 
    169169            "OpenLayers/Control/Measure.js", 
    170170            "OpenLayers/Control/WMSGetFeatureInfo.js", 
     171            "OpenLayers/Control/Graticule.js", 
    171172            "OpenLayers/Geometry.js", 
    172173            "OpenLayers/Geometry/Rectangle.js", 
    173174            "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=true 
     57     */ 
     58    labelled: true, 
     59 
     60    /** 
     61     * APIProperty: labelFormat 
     62     * {String} the format of the labels, default = 'dms' 
     63     */ 
     64    labelFormat: 'dm', 
     65 
     66    /** 
     67     * APIProperty: lineSymbolizer 
     68     * {symbolizer} the symbolizer used to render lines 
     69     */ 
     70    lineSymbolizer: { 
     71                strokeColor: "#333", 
     72                strokeWidth: 1, 
     73                strokeOpacity: 0.5 
     74            }, 
     75 
     76    /** 
     77     * APIProperty: labelSymbolizer 
     78     * {symbolizer} the symbolizer used to render lines 
     79     */ 
     80    labelSymbolizer: { 
     81                stroke: false, 
     82                fill: false, 
     83                label: "${label}", 
     84                labelAlign: "${labelAlign}", 
     85                labelXOffset: "${xOffset}", 
     86                labelYOffset: "${yOffset}" 
     87            }, 
     88 
     89    /** 
     90     * Property: gratLayer 
     91     * {OpenLayers.Layer.Vector} vector layer used to draw the graticule on 
     92     */ 
     93    gratLayer: null, 
     94 
     95    /** 
     96     * Constructor: OpenLayers.Control.Graticule 
     97     * Create a new graticule control to display a grid of latitude longitude 
     98     * lines. 
     99     *  
     100     * Parameters: 
     101     * options - {Object} An optional object whose properties will be used 
     102     *     to extend the control. 
     103     */ 
     104    initialize: function(options) { 
     105        OpenLayers.Control.prototype.initialize.apply(this, [options]); 
     106    }, 
     107 
     108    /** 
     109     * Method: draw 
     110     * 
     111     * initializes the graticule layer and does the initial update 
     112     *  
     113     * Returns: 
     114     * {DOMElement} 
     115     */ 
     116    draw: function() { 
     117        OpenLayers.Control.prototype.draw.apply(this, arguments); 
     118        if (!this.gratLayer) { 
     119          var gratStyle = new OpenLayers.Style({},{ 
     120              rules: [new OpenLayers.Rule({'symbolizer': 
     121                  {"Point":this.labelSymbolizer, 
     122                   "Line":this.lineSymbolizer} 
     123              })] 
     124            }); 
     125            this.gratLayer = new OpenLayers.Layer.Vector("Graticule", { 
     126              styleMap: new OpenLayers.StyleMap({'default':gratStyle}), 
     127              visibility: this.visible, 
     128              displayInLayerSwitcher: this.displayInLayerSwitcher 
     129            }); 
     130            this.map.addLayer(this.gratLayer); 
     131        } 
     132        this.map.events.register('moveend', this, this.update); 
     133        this.update(); 
     134        return this.div; 
     135    }, 
     136 
     137    /** 
     138     * Method: update 
     139     * 
     140     * calculates the grid to be displayed and actually draws it 
     141     *  
     142     * Returns: 
     143     * {DOMElement} 
     144     */ 
     145    update: function() { 
     146        //wait for the map to be initialized before proceeding 
     147        var mapBounds = this.map.getExtent(); 
     148        if (!mapBounds) { 
     149          return; 
     150        } 
     151        var mapRect = mapBounds.toGeometry(); 
     152         
     153        //clear out the old grid 
     154        this.gratLayer.destroyFeatures(); 
     155         
     156        //get the projection objects required 
     157        var llProj = new OpenLayers.Projection("EPSG:4326"); 
     158        var mapProj = this.map.getProjectionObject(); 
     159        var mapRes = this.map.getResolution(); 
     160         
     161        //if the map is in lon/lat, then the lines are straight and only one 
     162        //point is required 
     163        if (mapProj.proj && mapProj.proj.projName == "longlat") { 
     164          this.numPoints = 1; 
     165        } 
     166         
     167        //get the map center in EPSG:4326 
     168        var mapCenter = this.map.getCenter(); //lon and lat here are really map x and y 
     169        var mapCenterLL = new OpenLayers.Pixel(mapCenter.lon, mapCenter.lat); 
     170        OpenLayers.Projection.transform(mapCenterLL, mapProj, llProj); 
     171         
     172        /* This block of code determines the lon/lat interval to use for the 
     173         * grid by calculating the diagonal size of one grid cell at the map 
     174         * center.  Iterates through the intervals array until the diagonal 
     175         * length is less than the targetSize option. 
     176         */ 
     177        //find lat/lon interval that results in a grid of less than the target size 
     178        var testSq = this.targetSize*mapRes; 
     179        testSq *= testSq;   //compare squares rather than doing a square root to save time 
     180        var llInterval; 
     181        for (var i=0; i<this.intervals.length; ++i) { 
     182          llInterval = this.intervals[i];   //could do this for both x and y?? 
     183          var delta = llInterval/2;   
     184          var p1 = mapCenterLL.offset(new OpenLayers.Pixel(-delta, -delta));  //test coords in EPSG:4326 space 
     185          var p2 = mapCenterLL.offset(new OpenLayers.Pixel( delta,  delta)); 
     186          OpenLayers.Projection.transform(p1, llProj, mapProj); // convert them back to map projection 
     187          OpenLayers.Projection.transform(p2, llProj, mapProj); 
     188          var distSq = (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y); 
     189          if (distSq <= testSq) { 
     190            break; 
     191          } 
     192        } 
     193        //alert(llInterval); 
     194         
     195        //round the LL center to an even number based on the interval 
     196        mapCenterLL.x = Math.floor(mapCenterLL.x/llInterval)*llInterval; 
     197        mapCenterLL.y = Math.floor(mapCenterLL.y/llInterval)*llInterval; 
     198        //TODO adjust for minutses/seconds? 
     199         
     200        /* The following 2 blocks calculate the nodes of the grid along a  
     201         * line of constant longitude (then latitiude) running through the 
     202         * center of the map until it reaches the map edge.  The calculation 
     203         * goes from the center in both directions to the edge. 
     204         */ 
     205        //get the central longitude line, increment the latitude 
     206        var iter = 0 
     207        var centerLonPoints = [mapCenterLL.clone()]; 
     208        var newPoint = mapCenterLL.clone(); 
     209        var mapXY; 
     210        do { 
     211            newPoint = newPoint.offset(new OpenLayers.Pixel(0,llInterval)); 
     212            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     213            centerLonPoints.unshift(newPoint); 
     214        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     215        newPoint = mapCenterLL.clone(); 
     216        do {           
     217            newPoint = newPoint.offset(new OpenLayers.Pixel(0,-llInterval)); 
     218            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     219            centerLonPoints.push(newPoint); 
     220        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     221         
     222        //get the central latitude line, increment the longitude 
     223        iter = 0 
     224        var centerLatPoints = [mapCenterLL.clone()]; 
     225        newPoint = mapCenterLL.clone(); 
     226        do { 
     227            newPoint = newPoint.offset(new OpenLayers.Pixel(-llInterval, 0)); 
     228            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     229            centerLatPoints.unshift(newPoint); 
     230        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     231        newPoint = mapCenterLL.clone(); 
     232        do {           
     233            newPoint = newPoint.offset(new OpenLayers.Pixel(llInterval, 0)); 
     234            mapXY = OpenLayers.Projection.transform(newPoint.clone(), llProj, mapProj); 
     235            centerLatPoints.push(newPoint); 
     236        } while (mapBounds.containsPixel(mapXY) && ++iter<1000); 
     237         
     238        //now generate a line for each node in the central lat and lon lines 
     239        //first loop over constant longitude 
     240        var lines = []; 
     241        for(var i=0; i < centerLatPoints.length; ++i) { 
     242          var lon = centerLatPoints[i].x; 
     243          var pointList = []; 
     244          var labelPoint = null; 
     245          var latEnd = Math.min(centerLonPoints[0].y, 90); 
     246          var latStart = Math.max(centerLonPoints[centerLonPoints.length - 1].y, -90); 
     247          var latDelta = (latEnd - latStart)/this.numPoints; 
     248          var lat = latStart; 
     249          for(var j=0; j<= this.numPoints; ++j) { 
     250            var gridPoint = new OpenLayers.Geometry.Point(lon,lat); 
     251            gridPoint.transform(llProj, mapProj); 
     252            pointList.push(gridPoint); 
     253            lat += latDelta; 
     254            if (gridPoint.y >= mapBounds.bottom && !labelPoint) { 
     255              labelPoint = gridPoint; 
     256            } 
     257          } 
     258          if (this.labelled) { 
     259            //keep track of when this grid line crosses the map bounds to set 
     260            //the label position 
     261            //labels along the bottom, add 10 pixel offset up into the map 
     262            //TODO add option for labels on top 
     263            var labelPos = new OpenLayers.Geometry.Point(labelPoint.x,mapBounds.bottom); 
     264            var labelAttrs = { 
     265              value: lon, 
     266              label: this.labelled?OpenLayers.Util.getFormattedLonLat(lon, "lon", this.labelFormat):"", 
     267              labelAlign: "cb", 
     268              xOffset: 0, 
     269              yOffset: 2 
     270            };  
     271            this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos,labelAttrs)); 
     272          } 
     273          var geom = new OpenLayers.Geometry.LineString(pointList); 
     274          lines.push(new OpenLayers.Feature.Vector(geom)); 
     275        } 
     276         
     277        //now draw the lines of constant latitude 
     278        for (var j=0; j < centerLonPoints.length; ++j) { 
     279          lat = centerLonPoints[j].y; 
     280          if (lat<-90 || lat>90) {  //latitudes only valid between -90 and 90 
     281            continue; 
     282          } 
     283          var pointList = []; 
     284          var lonStart = centerLatPoints[0].x; 
     285          var lonEnd = centerLatPoints[centerLatPoints.length - 1].x; 
     286          var lonDelta = (lonEnd - lonStart)/this.numPoints; 
     287          var lon = lonStart; 
     288          var labelPoint = null; 
     289          for(var i=0; i <= this.numPoints ; ++i) { 
     290            var gridPoint = new OpenLayers.Geometry.Point(lon,lat); 
     291            gridPoint.transform(llProj, mapProj); 
     292            pointList.push(gridPoint); 
     293            lon += lonDelta; 
     294            if (gridPoint.x < mapBounds.right) { 
     295              labelPoint = gridPoint; 
     296            } 
     297          } 
     298          if (this.labelled) { 
     299            //keep track of when this grid line crosses the map bounds to set 
     300            //the label position 
     301            //labels along the right, 30 pixel offset left into the map 
     302            //TODO add option for labels on left 
     303              var labelPos = new OpenLayers.Geometry.Point(mapBounds.right, labelPoint.y);  
     304              var labelAttrs = { 
     305                value: lat, 
     306                label: this.labelled?OpenLayers.Util.getFormattedLonLat(lat, "lat", this.labelFormat):"", 
     307                labelAlign: "rb", 
     308                xOffset: -2, 
     309                yOffset: 2 
     310              };  
     311              this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(labelPos,labelAttrs)); 
     312          } 
     313          var geom = new OpenLayers.Geometry.LineString(pointList); 
     314          lines.push(new OpenLayers.Feature.Vector(geom)); 
     315        } 
     316        this.gratLayer.addFeatures(lines); 
     317    }, 
     318     
     319    CLASS_NAME: "OpenLayers.Control.Graticule" 
     320}); 
     321 
  • lib/OpenLayers/Lang/en.js

    old new  
    8181        "target='_blank'>click here</a>", 
    8282 
    8383    'scale': "Scale = 1 : ${scaleDenom}", 
     84     
     85    //labels for the graticule control 
     86    'W': 'W', 
     87    'E': 'E', 
     88    'N': 'N', 
     89    'S': 'S', 
    8490 
    8591    // console message 
    8692    'layerAlreadyAdded': 
  • lib/OpenLayers/Util.js

    old new  
    958958        var end = OpenLayers.String.contains(url, "#") ? 
    959959                    url.indexOf('#') : url.length; 
    960960        paramsString = url.substring(start, end); 
     961    } else { 
     962        paramsString = url; 
    961963    } 
    962964         
    963965    var parameters = {}; 
     
    16421644 
    16431645    return scrollbarWidth; 
    16441646}; 
     1647 
     1648/** 
     1649 * APIFunction: getFormattedLonLat 
     1650 * This function will return latitude or longitude value formatted as  
     1651 * 
     1652 * Parameters: 
     1653 * coordinate - {Float} the coordinate value to be formatted 
     1654 * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to 
     1655 *          to be formatted (default = lat) 
     1656 * dmsOption - {String} specify the precision of the output can be one of: 
     1657 *           'dms' show degrees minutes and seconds 
     1658 *           'dm' show only degrees and minutes 
     1659 *           'd' show only degrees 
     1660 *  
     1661 * Returns: 
     1662 * {String} the coordinate value formatted as a string 
     1663 */ 
     1664OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) { 
     1665    if (!dmsOption) { 
     1666      dmsOption = 'dms';    //default to show degree, minutes, seconds 
     1667    } 
     1668    var abscoordinate = Math.abs(coordinate) 
     1669    var coordinatedegrees = Math.floor(abscoordinate); 
     1670 
     1671    var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60); 
     1672    var tempcoordinateminutes = coordinateminutes; 
     1673    coordinateminutes = Math.floor(coordinateminutes); 
     1674    var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60); 
     1675    coordinateseconds =  Math.round(coordinateseconds*10); 
     1676    coordinateseconds /= 10; 
     1677 
     1678    if( coordinatedegrees < 10 ) { 
     1679      coordinatedegrees = "0" + coordinatedegrees; 
     1680    } 
     1681    var str = coordinatedegrees + " ";  //get degree symbol here somehow for SVG/VML labelling 
     1682 
     1683    if (dmsOption.indexOf('dm') >= 0) { 
     1684      if( coordinateminutes < 10 ) { 
     1685        coordinateminutes = "0" + coordinateminutes; 
     1686      } 
     1687      str += coordinateminutes + "'"; 
     1688 
     1689      if (dmsOption.indexOf('dms') >= 0) { 
     1690        if( coordinateseconds < 10 ) { 
     1691          coordinateseconds = "0" + coordinateseconds; 
     1692        } 
     1693        str += coordinateseconds + '"'; 
     1694      } 
     1695    } 
     1696     
     1697    if (axis == "lon") { 
     1698      str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E"); 
     1699    } else { 
     1700      str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N"); 
     1701    } 
     1702    return str; 
     1703}; 
     1704 
  • tests/list-tests.html

    old new  
    1515    <li>Control/DragPan.html</li> 
    1616    <li>Control/DrawFeature.html</li> 
    1717    <li>Control/GetFeature.html</li> 
     18    <li>Control/Graticule.html</li> 
    1819    <li>Control/KeyboardDefaults.html</li> 
    1920    <li>Control/LayerSwitcher.html</li> 
    2021    <li>Control/Measure.html</li>