5

I want to know if I'm approaching this incorrectly. We are attempting to create an esri-based map where we add graphics to a map thru the javascript API. The points that we're adding are lat/lng coords(wkid:4326). Part of our requirements are to be able to show these items regardless of the spatialreference of the map. So we tried to use the geometry service that esri provides to project the 4326 coords to the map spatialreference.

That all works fine, unless we have a lot of points to project. If the geometry service is fed too many points at a time it returns Error:"timeout exceeded". We've split out the amount we give the service and called it iteratively, but it also errors out if we call it too many times too quickly. So we've tried to spread the interval between calls to limit that. The more I do this, the more I feel like I'm digging myself into a deep hole.

  1. Should we be approaching this problem in another way? If so, any suggestions?
  2. Should we homebrew our own geometry projection service to bypass the limitations we notice with the esri implementation?
    1. If so, any resources that would help with the required algorithms?
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Jose
  • 269
  • 4
  • 6

2 Answers2

4

You can do the reprojection on the client side (in javascript) rather than relying on a Geometry server.

The PROJ4JS library will let you do that. If you know ahead of time which projections your maps will be in, so much the better- you can prune down PROJ4JS to only include what you need. Otherwise, you can just use the whole thing.

mwalker
  • 5,752
  • 25
  • 32
  • how do I create a projection from wkid:4326 to wkid:102100? I don't know what spatialreference.org considers it? – Jose Dec 05 '11 at 23:16
  • 1
    I think they use the "GOOGLE" code, EPSG:900913. They may also use the new EPSG code, EPSG:3857. See http://gis.stackexchange.com/questions/253/what-is-the-current-web-mercator-projection-code – mwalker Dec 06 '11 at 16:55
3

It shouldn't be a problem to send 15 or so points to a geometry service to be projected in a single call.

Below is an example that generates 50 "random" lat, lon points (if you run this locally, provide a URL for a proxy page) and sends them to a geometry service hosted by Esri to be projected to web mercator:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
    <title></title>

    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.5/js/dojo/dijit/themes/tundra/tundra.css">
    <script src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.5" type="text/javascript"></script>

    <script type="text/javascript">
      dojo.require("esri.map");
      dojo.require("esri.tasks.geometry");

      esri.config.defaults.io.proxyUrl = "URL TO YOUR PROXY PAGE";

      var map, gsvc, pt;

      function init() {
        var ext, layer;

        ext = esri.geometry.geographicToWebMercator(new esri.geometry.Extent(-144.13, 7.98, -52.76, 68.89, new esri.SpatialReference({wkid: 4326})));
        map = new esri.Map("map", { "extent": ext });

        layer = new esri.layers.ArcGISTiledMapServiceLayer("http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer");
        map.addLayer(layer);

        gsvc = new esri.tasks.GeometryService("http://tasks.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer");
        dojo.connect(map, "onClick", projectPoints);
      }

      function projectPoints(evt) {
        var pts, symbol, graphic, outSR, coordsTable;

        map.graphics.clear();
        pts = createPoints(evt.mapPoint);

        symbol = new esri.symbol.SimpleMarkerSymbol().setStyle(esri.symbol.SimpleMarkerSymbol.STYLE_DIAMOND);
        graphic = new esri.Graphic(evt.mapPoint, symbol);
        outSR = new esri.SpatialReference({ wkid: 102100 });

        map.graphics.add(graphic);

        gsvc.project(pts, outSR, function(projected) {
          console.log("gsvc returned: ", projected);
          coordsTable = "<table><thead><th>x</th><th>y</th></thead><tbody>";
          dojo.forEach(projected, function(p) {
            coordsTable += "<tr><td>" + p.x.toFixed() + "</td><td>" + p.y.toFixed() + "</td></tr>";
          });
          coordsTable += "</tbody></table>";
          dojo.byId("outCoords").innerHTML = coordsTable;
        });
      }

      function createPoints(mp) {
        var ext, width, height, numGraphics, latLonPts, i, randx, randy, pt;

        ext = map.extent;
        width = ext.xmax - ext.xmin;
        height = ext.ymax - ext.ymin;
        numGraphics = 50;
        latLonPts = [];
        for ( i=0; i<numGraphics; i++ ) {
          randx = (Math.random() * width) + ext.xmin;
          randy = (Math.random() * height) + ext.ymin,
          pt = esri.geometry.webMercatorToGeographic(new esri.geometry.Point(randx, randy, map.spatialReference));
          latLonPts.push(pt);
        }
        return latLonPts;
      }
      dojo.ready(init);
    </script>
  </head>
  <body class="tundra">
    <b>Click a location on the map to Project from LatLng -> Web Mercator:</b>
    <div id="map" style="width:600px; height:400px; border:1px solid #000;"></div>
    <div id="outCoords"></div>
  </body>
</html>

Can you post the code showing how you're talking to the geometry service?

Additionally, there are built-in client side methods to do geographic --> web mercator and web mercator --> geographic conversions. No geometry service necessary.

Derek Swingley
  • 14,462
  • 2
  • 44
  • 63
  • 1
    All i can say is I tried to send more than 15 and it would error out. The esri.geometry.geographicToWebMercator function is what got me where I needed to be. Thanks! – Jose Dec 06 '11 at 16:07
  • Glad you got it sorted. If you're interested in pursuing this further, please email me: dswingley at esri dot com. – Derek Swingley Dec 06 '11 at 16:53