Adding feature layer to map without a basemap

3705
7
Jump to solution
02-15-2012 10:35 AM
MichaelHayden
New Contributor
Is it possible to add a feature layer wihtout a basemap?
0 Kudos
1 Solution

Accepted Solutions
derekswingley1
Frequent Contributor
Technically, no, you need to have a tiled or dynamic layer in your map first. We're looking at changing this in a future release so that you can use a feature layer (or graphics layer) as the only layer in the map. Until then, you can extend dynamic map service layer to create a custom layer that doesn't do anything. Basically, you override getImageUrl to do nothing like this:

getImageUrl: function(extent, width, height, callback) {   // do nothing...we want an empty layer }


Here's simple example of a map with a custom dynamic layer that doesn't do anything and a feature layer:  http://jsfiddle.net/n7r4D/

Full code sample:
 <!doctype html> <html lang="en">   <head>     <meta 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" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/dojo/dijit/themes/tundra/tundra.css">     <link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/esri/dijit/css/Popup.css">     <style>       html, body { height: 100%; width: 100%; margin: 0; padding: 0; }       #map{ margin: 0; padding: 0; }     </style>     <script>var dojoConfig = { parseOnLoad: true };</script>     <script src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.7"></script>     <script>       dojo.require("dijit.layout.BorderContainer");       dojo.require("dijit.layout.ContentPane");       dojo.require("esri.map");       dojo.require("esri.layers.FeatureLayer");              var map;       function init() {         map = new esri.Map("map",{ "slider": false });                  dojo.connect(map, "onLoad", function() {            dojo.connect(dijit.byId("map"), "resize", map, map.resize);         });          // add an empty layer          var el = new easy.EmptyLayer({ wkid: 102003 });         map.addLayer(el);         dojo.connect(el, "onLoad", function() {           // add a feature layer           addStatesFeatureLayer();         });       }        function addStatesFeatureLayer() {         // sym and renderer         var outline = new esri.symbol.SimpleLineSymbol()               .setColor(dojo.colorFromHex("#fff"));         var sym = new esri.symbol.SimpleFillSymbol()               .setColor(new dojo.Color([52, 67, 83, 0.4]))               .setOutline(outline);         var renderer = new esri.renderer.SimpleRenderer(sym);                  // create and add the actual FL         fl = new esri.layers.FeatureLayer("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5", {           mode: esri.layers.FeatureLayer.MODE_ONDEMAND,           outFields: ["STATE_NAME", "POP2000", "POP2007"],           maxAllowableOffset: (map.extent.getWidth() / map.width)         });         fl.setRenderer(renderer);         map.addLayer(fl);       }        // extend dynamic map service layer to create an empty layer       dojo.declare("easy.EmptyLayer", esri.layers.DynamicMapServiceLayer, {         constructor: function(params) {           this.params = params || {};           this.wkid = this.params.wkid || 102100;           this.spatialReference = new esri.SpatialReference({ wkid: this.wkid });           // extent for contiguous US           var ext = new esri.geometry.Extent({              "xmin":-14325844,             "ymin":2207331,             "xmax":-7121642,             "ymax":6867214,             "spatialReference":{ "wkid": 102100 }           });            if ( this.wkid != ext.spatialReference.wkid ) {             // project extent for contiguous US to the supplied wkid             var gs = new esri.tasks.GeometryService('http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer'),                 that = this;             gs.project([ext], this.spatialReference, function(result) {               // console.log('projected extent: ', result, that);               that.initialExtent = that.fullExtent = result[0];               that.loaded = true;               that.onLoad(that);             });           } else {             // console.log('no need to project');             this.initialExtent = this.fullExtent = ext;             this.loaded = true;             this.onLoad(this);           }         },         getImageUrl: function(extent, width, height, callback) {           // do nothing...we want an empty layer         }       });              dojo.ready(init);     </script>   </head>      <body class="tundra">     <div data-dojo-type="dijit.layout.BorderContainer"           data-dojo-props="design:'headline',gutters:false"           style="width: 100%; height: 100%; margin: 0;">       <div id="map"             data-dojo-type="dijit.layout.ContentPane"             data-dojo-props="region:'center'">        </div>     </div>   </body> </html>

View solution in original post

0 Kudos
7 Replies
derekswingley1
Frequent Contributor
Technically, no, you need to have a tiled or dynamic layer in your map first. We're looking at changing this in a future release so that you can use a feature layer (or graphics layer) as the only layer in the map. Until then, you can extend dynamic map service layer to create a custom layer that doesn't do anything. Basically, you override getImageUrl to do nothing like this:

getImageUrl: function(extent, width, height, callback) {   // do nothing...we want an empty layer }


Here's simple example of a map with a custom dynamic layer that doesn't do anything and a feature layer:  http://jsfiddle.net/n7r4D/

Full code sample:
 <!doctype html> <html lang="en">   <head>     <meta 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" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/dojo/dijit/themes/tundra/tundra.css">     <link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/esri/dijit/css/Popup.css">     <style>       html, body { height: 100%; width: 100%; margin: 0; padding: 0; }       #map{ margin: 0; padding: 0; }     </style>     <script>var dojoConfig = { parseOnLoad: true };</script>     <script src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.7"></script>     <script>       dojo.require("dijit.layout.BorderContainer");       dojo.require("dijit.layout.ContentPane");       dojo.require("esri.map");       dojo.require("esri.layers.FeatureLayer");              var map;       function init() {         map = new esri.Map("map",{ "slider": false });                  dojo.connect(map, "onLoad", function() {            dojo.connect(dijit.byId("map"), "resize", map, map.resize);         });          // add an empty layer          var el = new easy.EmptyLayer({ wkid: 102003 });         map.addLayer(el);         dojo.connect(el, "onLoad", function() {           // add a feature layer           addStatesFeatureLayer();         });       }        function addStatesFeatureLayer() {         // sym and renderer         var outline = new esri.symbol.SimpleLineSymbol()               .setColor(dojo.colorFromHex("#fff"));         var sym = new esri.symbol.SimpleFillSymbol()               .setColor(new dojo.Color([52, 67, 83, 0.4]))               .setOutline(outline);         var renderer = new esri.renderer.SimpleRenderer(sym);                  // create and add the actual FL         fl = new esri.layers.FeatureLayer("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5", {           mode: esri.layers.FeatureLayer.MODE_ONDEMAND,           outFields: ["STATE_NAME", "POP2000", "POP2007"],           maxAllowableOffset: (map.extent.getWidth() / map.width)         });         fl.setRenderer(renderer);         map.addLayer(fl);       }        // extend dynamic map service layer to create an empty layer       dojo.declare("easy.EmptyLayer", esri.layers.DynamicMapServiceLayer, {         constructor: function(params) {           this.params = params || {};           this.wkid = this.params.wkid || 102100;           this.spatialReference = new esri.SpatialReference({ wkid: this.wkid });           // extent for contiguous US           var ext = new esri.geometry.Extent({              "xmin":-14325844,             "ymin":2207331,             "xmax":-7121642,             "ymax":6867214,             "spatialReference":{ "wkid": 102100 }           });            if ( this.wkid != ext.spatialReference.wkid ) {             // project extent for contiguous US to the supplied wkid             var gs = new esri.tasks.GeometryService('http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer'),                 that = this;             gs.project([ext], this.spatialReference, function(result) {               // console.log('projected extent: ', result, that);               that.initialExtent = that.fullExtent = result[0];               that.loaded = true;               that.onLoad(that);             });           } else {             // console.log('no need to project');             this.initialExtent = this.fullExtent = ext;             this.loaded = true;             this.onLoad(this);           }         },         getImageUrl: function(extent, width, height, callback) {           // do nothing...we want an empty layer         }       });              dojo.ready(init);     </script>   </head>      <body class="tundra">     <div data-dojo-type="dijit.layout.BorderContainer"           data-dojo-props="design:'headline',gutters:false"           style="width: 100%; height: 100%; margin: 0;">       <div id="map"             data-dojo-type="dijit.layout.ContentPane"             data-dojo-props="region:'center'">        </div>     </div>   </body> </html>
0 Kudos
MichaelHayden
New Contributor
Thank You Derek,
I like your solution better than my own. I will look at it closer and roll a similar (if not the same) concept into my code.

FYI,
What I did was to add a dynamic tile layer as a base map and set the visibility to false.

The reason I am asking about this at all is that the legacy map data that my client has was created with AutoCad and their projection is: 3437. They have never used a basemap.
Anyway, reading the ESRI JS API, I discovered that although the feature layers projection is different than the base tile layer (I'm currently using: http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer), the feature layer will still show up which it does, but of course, the feature layer doesn't match the roads and such on the base layer.

Any further advise would be greatly appreciated.

Thanks again,
Michael Hayden
0 Kudos
derekswingley1
Frequent Contributor
Feature layers are projected on the fly to match the spatial reference of the map.

In the example I posted, the custom layer is created with a spatial reference of USA_Contiguous_Albers_Equal_Area_Conic (wkid 102003). When the custom layer is added to the map, it sets the SR for the map. When the feature layer is added, it sees the map's spatial ref and tells the server to project features into that spat ref. This way, you can use any spatial reference you like- just specify it in the constructor for the custom layer.
0 Kudos
MichaelHayden
New Contributor
Derek,
TOTALLY!! I get it.
Thanks again.
0 Kudos
derekswingley1
Frequent Contributor
Glad to help! If you want to mark one of my posts as an answer, I'd appreciate it 🙂
0 Kudos
MichaelHayden
New Contributor
Derek,
Your EmptyBaseLayer class works well for me with one exception.
The "onUpdateEnd" map event never fires.

Michael Hayden
0 Kudos
derekswingley1
Frequent Contributor

... EmptyBaseLayer class works well for me with one exception.
The "onUpdateEnd" map event never fires.


Right, that is because getImageUrl never does anything. In a dynamic map service layer, getImageUrl runs, updates the image then calls layer.onUpdateEnd(). You could call onUpdateEnd in the EmptyLayer class's getImageUrl but I'd like to know more about what  you're trying to do.

What are you trying to do?
0 Kudos