JavaScript API: Layering of Tile layers between Feature layers?

4535
7
Jump to solution
05-12-2015 02:22 PM
BryanVan_Meter
New Contributor II

Hi all,

I'm new to the GIS world and am building a map viewer for displaying land parcels among other things. We have to port our Flex API based applications to the JavaScript API, and it was looking good until I had to place a Tile layer between two Feature layers. The problem is that all feature layers get put into one SVG element called the "Graphics Layer". To be more specific, we have a transparent tile layer(s) of Streets, Lakes, etc that need to be placed above the parcel lines, yet below marker icons, etc. Should be no big deal, right?

According to the documentation, the Graphics Layer is: "A layer that contains one or more Graphic features. Each map contains a GraphicsLayer by default, accessible using the Map.graphics property. You can create your own graphics layers and add them to the map. Graphics layers can be reordered within the group of graphics layers. However, the graphics layer in Map.graphics is always on top. Also, all graphics layers are always on top of TiledMapServiceLayers and DynamicMapServiceLayers."

Capture.PNG

For the record, I'm not a GIS guy. I'm a web developer working for a GIS company. So one thing I've noticed in terms of the HTML that is generated is that when I  add multiple tile layers, they are created inside their own DIV containers which makes for easy reordering of Tile Layers. Feature layers on the other hand all get lumped into one SVG object. This makes it IMPOSSIBLE to shuffle a tile layer between two feature layers as you can't exactly put a 'div' element between two 'g' elements within the SVG element.

So, am I just missing something? Does anyone know of a work around for this? If I could have more than one "Graphics layer" container, and by that I mean more than one SVG container to assign feature layers to, I would at least have some way to set classes, add z-indexes, or preferably use the API methods for reordering layers. To me this seems like a pretty basic idea, which makes me thing that I MUST be missing something.

Thanks in advance to anyone who points me in the right direction or at least determines that there is no direction at all.

0 Kudos
1 Solution

Accepted Solutions
BryanVan_Meter
New Contributor II

Well, since there doesn't appear to be a way to do what I need from the API, so I just decided to hijack the layer I wanted out of the DOM. I use jQuery all the time, so that is what this is written in. Basically, I made an empty copy of the '#map_gc' SVG element container and placed it before the layer I wanted to put it under. I then copied it's attributes (overflow, hight, width, and style). Finally, I used the append command (similar to appendChild) to remove the graphics layer(which was the feature layer of parcels) I wanted and add it to the new SVG container. Not included in this example but on my TO-DO list is to set an event handler to re-copy the attributes when the map resizes.

Note that this is written to only run once. I think I will have to put some of this code into a function if the feature layer is to be removed from and added back to the map.

var reordered = false;

midlandParcelsLayer.on('update-end', function(){

     if(reordered == false){

          $('#map_midlandStreetsLayer' ).before( '<svg id="map_gc_parcels"></svg>' );

          $('#map_gc_parcels').attr('overflow', $('#map_gc').attr('overflow'));

          $('#map_gc_parcels').attr('width', $('#map_gc').attr('width'));

          $('#map_gc_parcels').attr('height', $('#map_gc').attr('height'));

          $('#map_gc_parcels').attr('style', $('#map_gc').attr('style'));

          $('#map_gc_parcels' ).append( $('#midlandParcelsLayer_layer') );

          reordered = true;

     }

});

This appears to be working. I can pan, zoom, click on parcels to open popups and everything acts as one would hope. Hopefully this helps others

Capture.PNG

View solution in original post

0 Kudos
7 Replies
TimWitt2
MVP Alum

Hey Bryan,

Maybe we can tackle the problem but first looking at what you are trying to achieve.

So you want parcel lines -> below a transparent tiled layer -> below a marker layer.

What is the reason for having it in this order? Maybe we can move away from having them in a specific order?

Tim

0 Kudos
BryanVan_Meter
New Contributor II

"...So you want parcel lines -> below a transparent tiled layer -> below a marker layer." <-- Correct

Thanks for the interest in my little dilemma.

This layer order was easy to achieve with the Flex API (or so my boss tells me). Layers could just be ordered regardless of type. One would think that's how the JS API should be as well?

Let me get you a "few" screen shots

This first screen shot is of an implementation I put together in Leaflet. Everything is working as it should in this screen shot. (For the record, I had to 'hack' at this a bit to make it work like this, but it works great)

Capture2.PNG

Another screen shot of the Leaflet implementation, zoomed out one more level where the park has a transparent green overlay:

Capture3.PNG

Now I'll show the screen shots of the esri JS API version. This first one is how the layers stack normally.Capture4.PNG

And zoomed out one more level so you can see the park overlay that appears (more on this later):

Capture6.PNG

So, to get around this, the only thing I could think of was to set z-indexes of layers in CSS and assign 'pointer-events: none;' to the transparent tile layer so users can click through it. While this worked for me in Leaflet, it is obviously not how ESRI intended things to be (and by that I mean having to hack things to work correctly). Notice the buildings are on top of some of the markers. This is less than ideal.

Capture5.PNG

Zoom out one more level, and the park overlay makes things even uglier:

Capture7.PNG

Currently, this is the only set of marker icons we have on any our maps, so the idea of redrawing all of those layers (streets, buildings, overlays, etc in multiple counties in our state) as a Feature layer makes my employer cringe in terms of time and effort.

0 Kudos
RickeyFight
MVP Regular Contributor

Bryan,

Are all the layers published in one service?

0 Kudos
BryanVan_Meter
New Contributor II

Most come from ArcGIS online. Features are from services3.arcgis.com, and tiles are from tiles.arcgis.com.

0 Kudos
TimWitt2
MVP Alum

Did you publish those to ArcGIS Online? Or are they from somebody else outside of your organization?

0 Kudos
BryanVan_Meter
New Contributor II

Our guys publish them, but not me personally. I'm the Web UI developer.

0 Kudos
BryanVan_Meter
New Contributor II

Well, since there doesn't appear to be a way to do what I need from the API, so I just decided to hijack the layer I wanted out of the DOM. I use jQuery all the time, so that is what this is written in. Basically, I made an empty copy of the '#map_gc' SVG element container and placed it before the layer I wanted to put it under. I then copied it's attributes (overflow, hight, width, and style). Finally, I used the append command (similar to appendChild) to remove the graphics layer(which was the feature layer of parcels) I wanted and add it to the new SVG container. Not included in this example but on my TO-DO list is to set an event handler to re-copy the attributes when the map resizes.

Note that this is written to only run once. I think I will have to put some of this code into a function if the feature layer is to be removed from and added back to the map.

var reordered = false;

midlandParcelsLayer.on('update-end', function(){

     if(reordered == false){

          $('#map_midlandStreetsLayer' ).before( '<svg id="map_gc_parcels"></svg>' );

          $('#map_gc_parcels').attr('overflow', $('#map_gc').attr('overflow'));

          $('#map_gc_parcels').attr('width', $('#map_gc').attr('width'));

          $('#map_gc_parcels').attr('height', $('#map_gc').attr('height'));

          $('#map_gc_parcels').attr('style', $('#map_gc').attr('style'));

          $('#map_gc_parcels' ).append( $('#midlandParcelsLayer_layer') );

          reordered = true;

     }

});

This appears to be working. I can pan, zoom, click on parcels to open popups and everything acts as one would hope. Hopefully this helps others

Capture.PNG

0 Kudos