esri leaflet map services

4743
10
Jump to solution
11-23-2016 09:59 AM
Labels (1)
Arnt_OddvarPedersen
New Contributor

Hello!

I'm finally underway with my hybrid app and trying to learn Leaflet+ESRI as I go, I went so far as to buy map services from Geodata, Norway's distributor of ESRI services, however...

I've set-up my map how I want it, added a few feature layers and been messing about with POIs, but when I'm now trying to change the base-map/displayed map to the service I bought from Geodata, it looks absolutely horrible!

It seems very pixilated and low quality.

Now, the default ESRI basemaps (Topographic for example) works wonderfully, is crisp and clear, unlike this one as well as responsive to boot, even on 3G. (Tested the prototype on 3G, 4G, 4G+ and wireless hotspots)

Am I adding the map service wrong? Using the wrong URL?  Here's my code:

// Create a new Mapvar ll = new L.LatLng(65.90378805867515, 13.79491163036881);self.map = L.map('map', {     center: ll,     zoom: 9,     fullscreenControl: true, }); L.esri.dynamicMapLayer({     url: 'https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer' }).addTo(self.map);

Now, this being said, I'm not entirely sure I'm using the right URL even. 

The URL I was given was Geodata REST Services Directory which contains a lot of standards, I've tried looking online for the differences but as far as I understand they're minuscule at best. Am I doing something wrong? According to examples online and the Leaflet-ESRI API I don't think I've overlooked anything.

I hope anyone with a bit more knowledge than me can help.

Thanks in advance!

- A

0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Arnt,

   Here is a working sample with your map service:

<html>
<head>
  <meta charset=utf-8 />
  <title>Non-mercator projection</title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />

  <!-- Load Leaflet from CDN-->
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
  <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet-src.js"></script>

  <!-- Load Esri Leaflet from CDN -->
  <script src="https://unpkg.com/esri-leaflet@2.0.6"></script>

  <style>
    body { margin:0; padding:0; }
    #map { position: absolute; top:0; bottom:0; right:0; left:0; }
  </style>
</head>
<body>

<!-- Include Proj4JS via rawgit.com
in production you'd be better off hosting these libraries yourself -->
<script src="https://rawgit.com/proj4js/proj4js/2.3.12/dist/proj4-src.js"></script>
<script src="https://rawgit.com/kartena/Proj4Leaflet/1.0.0-beta.2/src/proj4leaflet.js"></script>

<!-- Load shapeMarkers from CDN -->
<script src="https://cdn.jsdelivr.net/leaflet.shapemarkers/1.0.4/leaflet-shape-markers.js"></script>

<div id="map"></div>

<script>
  /* create new Proj4Leaflet CRS:
  1. Proj4 and WKT definitions can be found at sites like http://epsg.io, http://spatialreference.org/ or by using gdalsrsinfo http://www.gdal.org/gdalsrsinfo.html
  2. Appropriate values to supply to the resolution and origin constructor options can be found in the ArcGIS Server tile server REST endpoint (ex: https://tiles.arcgis.com/tiles/qHLhLQrcvEnxjtPr/arcgis/rest/services/OS_Open_Background_2/MapServer).
  3. The numeric code within the first parameter (ex: `27700`) will be used to project the dynamic map layer on the fly
  */
  var crs = new L.Proj.CRS('EPSG:32633', '+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs', {
    origin: [-2500000.0, 9045984.0],
    resolutions: [
      21674.7100160867,
      10837.35500804335,
      5418.677504021675,
      2709.3387520108377,
      1354.6693760054188,
      677.3346880027094,
      338.6673440013547,
      169.33367200067735,
      84.66683600033868,
      42.33341800016934,
      21.16670900008467,
      10.583354500042335,
      5.291677250021167,
      2.6458386250105836,
      1.3229193125052918,
      0.6614596562526459,
      0.33072982812632296,
      0.16536491406316148
    ]
  });

  var map = L.map('map', {
    crs: crs
  }).setView([65.90378805867515, 13.79491163036881], 9);

  // The min/maxZoom values provided should match the actual cache thats been published. This information can be retrieved from the service endpoint directly.
  L.esri.tiledMapLayer({
    url: 'https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer'
  }).addTo(map);

  // feature layers will be requested in WGS84 (4326) and reprojected
  var cities = L.esri.featureLayer({
    url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/WorldTimeZones/MapServer/0',
    where: 'POP_RANK < 5',
    pointToLayer (geojson, latlng) {
      return L.shapeMarkers.diamondMarker(latlng, 5, {
        color: '#0099FF',
        weight: 2
      })
    }
  }).addTo(map);
</script>

</body>
</html>

View solution in original post

10 Replies
RobertScheitlin__GISP
MVP Emeritus

Arnt,

  That Map Service is a tiled layer so you should use tiledMapLayer:

L.esri.tiledMapLayer({
  url: 'https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer'
}).addTo(map);‍‍‍‍

L.esri.TiledMapLayer | Esri Leaflet 

Arnt_OddvarPedersen
New Contributor

Thanks for the reply Robert!

That's actually what I thought and tried at first too, but when it loaded an empty map I thought I'd try the dynamicMapLayer for good measure. I also read John's reply bellow that the map is also cached in a custom projection, could that be one of the culprits to the grey map? (Grey filled, nothing but grey, no landmass definitions.)

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Arnt,

   Absolutely. Use John's the second link to understand how to define your custom projection for the map.

JohnGravois
Frequent Contributor

the easiest way to compare and contrast individual map services is to click the 'ArcGIS JavaScript' link in the top lefthand corner of an individual service metadata page.

https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer

I took a look at a few and it appears that they were designed and cached in a custom projection that is specific to the area surrounding Norway (UTM33 North/ wkid:32633), rather than Google and Leaflet's default Web Mercator which is used worldwide (wkid:3857).

https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer?...

In Leaflet, you'll need to reference the example below and define the properties of the UTM33 North projection explicity in your code.

http://esri.github.io/esri-leaflet/examples/non-mercator-projection.html 

Dealing with custom projections is much less cumbersome in the ArcGIS API for JavaScript, because that API parses the information directly from service metadata.
https://jsbin.com/kasixern/edit?html,output

Arnt_OddvarPedersen
New Contributor

(Sea Sheppard!)

Oh wow, I had no idea about that actually. I am from Norway and the data from Norway though so I guess it makes somewhat sense.

Does it actually matter which of the UMT32/33/WMAS - EUREF89/WGS84 folders I use though? Are some easier to work with than others? The 4 folders are actually pretty confusing, but I suppose I should stick with UTM33-EUREF89? (Having the most maps)

And ffter just skimming the Non-Mercator projection page though I might reconsider using Leaflet with ESRI-Leaflet in favor of the online JS API.  It was just a really convenient solution at the time.

Thanks for the educational links, John, if this gives me a lot of headache I might just switch over.

- A

0 Kudos
RobertScheitlin__GISP
MVP Emeritus

Arnt,

   Here is a working sample with your map service:

<html>
<head>
  <meta charset=utf-8 />
  <title>Non-mercator projection</title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />

  <!-- Load Leaflet from CDN-->
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
  <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet-src.js"></script>

  <!-- Load Esri Leaflet from CDN -->
  <script src="https://unpkg.com/esri-leaflet@2.0.6"></script>

  <style>
    body { margin:0; padding:0; }
    #map { position: absolute; top:0; bottom:0; right:0; left:0; }
  </style>
</head>
<body>

<!-- Include Proj4JS via rawgit.com
in production you'd be better off hosting these libraries yourself -->
<script src="https://rawgit.com/proj4js/proj4js/2.3.12/dist/proj4-src.js"></script>
<script src="https://rawgit.com/kartena/Proj4Leaflet/1.0.0-beta.2/src/proj4leaflet.js"></script>

<!-- Load shapeMarkers from CDN -->
<script src="https://cdn.jsdelivr.net/leaflet.shapemarkers/1.0.4/leaflet-shape-markers.js"></script>

<div id="map"></div>

<script>
  /* create new Proj4Leaflet CRS:
  1. Proj4 and WKT definitions can be found at sites like http://epsg.io, http://spatialreference.org/ or by using gdalsrsinfo http://www.gdal.org/gdalsrsinfo.html
  2. Appropriate values to supply to the resolution and origin constructor options can be found in the ArcGIS Server tile server REST endpoint (ex: https://tiles.arcgis.com/tiles/qHLhLQrcvEnxjtPr/arcgis/rest/services/OS_Open_Background_2/MapServer).
  3. The numeric code within the first parameter (ex: `27700`) will be used to project the dynamic map layer on the fly
  */
  var crs = new L.Proj.CRS('EPSG:32633', '+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs', {
    origin: [-2500000.0, 9045984.0],
    resolutions: [
      21674.7100160867,
      10837.35500804335,
      5418.677504021675,
      2709.3387520108377,
      1354.6693760054188,
      677.3346880027094,
      338.6673440013547,
      169.33367200067735,
      84.66683600033868,
      42.33341800016934,
      21.16670900008467,
      10.583354500042335,
      5.291677250021167,
      2.6458386250105836,
      1.3229193125052918,
      0.6614596562526459,
      0.33072982812632296,
      0.16536491406316148
    ]
  });

  var map = L.map('map', {
    crs: crs
  }).setView([65.90378805867515, 13.79491163036881], 9);

  // The min/maxZoom values provided should match the actual cache thats been published. This information can be retrieved from the service endpoint directly.
  L.esri.tiledMapLayer({
    url: 'https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer'
  }).addTo(map);

  // feature layers will be requested in WGS84 (4326) and reprojected
  var cities = L.esri.featureLayer({
    url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/WorldTimeZones/MapServer/0',
    where: 'POP_RANK < 5',
    pointToLayer (geojson, latlng) {
      return L.shapeMarkers.diamondMarker(latlng, 5, {
        color: '#0099FF',
        weight: 2
      })
    }
  }).addTo(map);
</script>

</body>
</html>
Arnt_OddvarPedersen
New Contributor

Holy friggin crap, Robert Scheitlin, GISP‌.

I was out getting some takeaway for a session of reading more up on spatial references and non-mercator projection.

I have no words to express my gratitude for the help.  Added to: GitHub - SpellCraft/gomap-boilerplate: GoMap Development 

0 Kudos
JohnGravois
Frequent Contributor

the curmudgeon in me really feels like it is more helpful in the long run to give folks a chance to try themselves and learn something new than it is to immediately provide ready to use code.

Arnt_OddvarPedersen
New Contributor

Indeed, but I've learned a lot nonetheless!

After reading through the non-mercator projection page you linked John I already have a lot of the information that Robert already provided in his live example.

The metadata hold almost all the information that I needed to puzzle it together in any case! The spatial reference (32633), Tile info describing the levels of detail for each zoom, or resolution if you will, and near the bottom you find the origin X, Y reference.

The last piece of information comes from the Map Service itself.

https://services.geodataonline.no/arcgis/rest/services/Geocache_UTM33_WGS84/GeocacheBasis/MapServer

0 Kudos