I have a Feature Layer and a Feature Table in my map view. I would like the Feature Table to only show the records from the Feature Layer that are visible in the current map extent and not all the records or the selected feature records. I have tried to use the MODE_SELECTION with an update query on the Feature Layer, which then only shows the Feature Layer features which intersect with the current map extent, but the Feature Table is still showing all the records. Is it possible and how would you do it?
Solved! Go to Solution.
FC,
Here is a sample that does that:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Using FeatureTable</title> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.16/dijit/themes/claro/claro.css"> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.16/esri/css/esri.css"> <script src="//js.arcgis.com/3.16/"></script> <style> html, body, #map{ width:100%; height:100%; margin:0; padding:0; } </style> <script> var map; require([ "esri/layers/FeatureLayer", "esri/dijit/FeatureTable", "esri/geometry/webMercatorUtils", "esri/map", "dojo/dom-construct", "dojo/dom", "dojo/parser", "dojo/ready", "dojo/on", "dojo/_base/lang", "dijit/registry", "esri/tasks/query", "dijit/form/Button", "dijit/layout/ContentPane", "dijit/layout/BorderContainer", "dijit/form/TextBox" ], function ( FeatureLayer, FeatureTable, webMercatorUtils, Map, domConstruct, dom, parser, ready, on,lang, registry, Query, Button, ContentPane, BorderContainer, TextBox ) { parser.parse(); ready(function(){ var myFeatureLayer; var map = new Map("map",{ basemap: "streets" }); map.on("load", loadTable); function loadTable(){ // Create the feature layer myFeatureLayer = new FeatureLayer("https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Warren_College_Trees/FeatureServer...", { mode: FeatureLayer.MODE_ONDEMAND, visible: true, outFields: ["*"], id: "fLayer" }); //set map extent on(myFeatureLayer, "load", function(evt){ var extent = myFeatureLayer.fullExtent; if (webMercatorUtils.canProject(extent, map)) { map.setExtent( webMercatorUtils.project(extent, map) ); on(map, 'extent-change', lang.hitch(this, function(params){ var oidFld = myFeatureLayer.objectIdField; var query = new Query(); query.geometry = params.extent; query.spatialRelationship = Query.SPATIAL_REL_CONTAINS; myFeatureLayer.queryIds(query, lang.hitch(this, function(objectIds) { myFeatureTable.selectedRowIds = objectIds; myFeatureTable._showSelectedRecords(); })); })); } }); map.addLayer(myFeatureLayer); myFeatureTable = new FeatureTable({ "featureLayer" : myFeatureLayer, "outFields": ["Collected","Crew","Status","Spp_Code", "Height", "Cmn_Name","Sci_Name","Street","Native"], "map" : map, "gridOptions": {} }, 'myTableNode'); myFeatureTable.startup(); } }); }); </script> </head> <body class="claro esri"> <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'" style="width:100%; height:100%;"> <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center', splitter:true" style="height:50%"> <div id="map"></div> </div> <div id="bot" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'bottom', splitter:true" style="height:50%"> <div id="myTableNode"></div> </div> </div> </body> </html>
FC,
Here is a sample that does that:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Using FeatureTable</title> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.16/dijit/themes/claro/claro.css"> <link rel="stylesheet" href="https://community.esri.com//js.arcgis.com/3.16/esri/css/esri.css"> <script src="//js.arcgis.com/3.16/"></script> <style> html, body, #map{ width:100%; height:100%; margin:0; padding:0; } </style> <script> var map; require([ "esri/layers/FeatureLayer", "esri/dijit/FeatureTable", "esri/geometry/webMercatorUtils", "esri/map", "dojo/dom-construct", "dojo/dom", "dojo/parser", "dojo/ready", "dojo/on", "dojo/_base/lang", "dijit/registry", "esri/tasks/query", "dijit/form/Button", "dijit/layout/ContentPane", "dijit/layout/BorderContainer", "dijit/form/TextBox" ], function ( FeatureLayer, FeatureTable, webMercatorUtils, Map, domConstruct, dom, parser, ready, on,lang, registry, Query, Button, ContentPane, BorderContainer, TextBox ) { parser.parse(); ready(function(){ var myFeatureLayer; var map = new Map("map",{ basemap: "streets" }); map.on("load", loadTable); function loadTable(){ // Create the feature layer myFeatureLayer = new FeatureLayer("https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Warren_College_Trees/FeatureServer...", { mode: FeatureLayer.MODE_ONDEMAND, visible: true, outFields: ["*"], id: "fLayer" }); //set map extent on(myFeatureLayer, "load", function(evt){ var extent = myFeatureLayer.fullExtent; if (webMercatorUtils.canProject(extent, map)) { map.setExtent( webMercatorUtils.project(extent, map) ); on(map, 'extent-change', lang.hitch(this, function(params){ var oidFld = myFeatureLayer.objectIdField; var query = new Query(); query.geometry = params.extent; query.spatialRelationship = Query.SPATIAL_REL_CONTAINS; myFeatureLayer.queryIds(query, lang.hitch(this, function(objectIds) { myFeatureTable.selectedRowIds = objectIds; myFeatureTable._showSelectedRecords(); })); })); } }); map.addLayer(myFeatureLayer); myFeatureTable = new FeatureTable({ "featureLayer" : myFeatureLayer, "outFields": ["Collected","Crew","Status","Spp_Code", "Height", "Cmn_Name","Sci_Name","Street","Native"], "map" : map, "gridOptions": {} }, 'myTableNode'); myFeatureTable.startup(); } }); }); </script> </head> <body class="claro esri"> <div data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline'" style="width:100%; height:100%;"> <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center', splitter:true" style="height:50%"> <div id="map"></div> </div> <div id="bot" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'bottom', splitter:true" style="height:50%"> <div id="myTableNode"></div> </div> </div> </body> </html>
Thanks Robert
The queryIds did the trick. In my original code I had a "extent-change" event function with a feature selection on the feature layer, but it did not work:
map.on('extent-change', function(){ query = new Query() query.spatialRelationship = Query.SPATIAL_REL_INTERSECTS; query.geometry = map.extent; myFeatureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW); myFeatureTable._showSelectedRecords(); })
I then used your sample code to modify my code and it is now doing exactly what I want it to.
map.on('extent-change', function(){ query = new Query() query.spatialRelationship = Query.SPATIAL_REL_INTERSECTS; query.geometry = map.extent; myFeatureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW); myFeatureLayer.queryIds(query, lang.hitch(this, function(objectIds) { myFeatureTable.selectedRowIds = objectIds; myFeatureTable._showSelectedRecords(); myFeatureTable._gridTitleNode.innerHTML = myFeatureLayer.name + ' (' + objectIds.length + ' Features)'; })); })
Hi, Robert. I am adopting the code that you posted here, but something is not working correctly. I was wondering if you could provide some insight.
I want to show different layers at different scales. So, when the map loads, I check for the scale and determine which layer to display. For the most part, the code works fine, except that the code/recordsets provided by your code are not persisted. When using the plus/minus icons, the screen briefly shows the correct values, as returned by the query, but then the default values/behavior of the feature table appears -- showing all rows for the feature layer. If I remove the code that fires when the map extent changes, the table updates work perfectly, but the layers are not drawn on the map. Any ideas from looking at the code below? Any help would be greatly appreciated.
var map, grid, fl_url, symbol, polygonSymbol, highlightSymbol, pointSymbol, outlineSymbol, line, renderer, featureLayer, loading, myFeatureTable, idx, title, content, drawingOptions, placeholdertxt, fieldsToDisplay, selectionToolbar, val, renderedField, CI;
var visiblelayers = [],
symbolArray = [],
labelArray = [],
fieldsToSearch = [];
var DataUnavailableTxt = "Data unavailable",
oldExtent = null;
require([
"esri/map", "esri/graphic", "esri/dijit/HomeButton", "esri/dijit/BasemapToggle", "esri/dijit/BasemapGallery", "esri/arcgis/utils", "esri/urlUtils", "esri/geometry/webMercatorUtils", "esri/dijit/Search", "esri/layers/FeatureLayer", "esri/dijit/FeatureTable", "esri/geometry/Extent", "esri/geometry/Polygon",
"esri/symbols/SimpleFillSymbol", "esri/layers/ArcGISDynamicMapServiceLayer", "esri/layers/ImageParameters", "esri/InfoTemplate",
"esri/renderers/ClassBreaksRenderer", "esri/tasks/GenerateRendererParameters", "esri/tasks/GenerateRendererTask",
"esri/tasks/ClassBreaksDefinition", "esri/symbols/SimpleMarkerSymbol", "esri/symbols/SimpleLineSymbol", "esri/renderers/SimpleRenderer", "esri/tasks/AlgorithmicColorRamp", "esri/lang", "dojo/_base/lang", "esri/toolbars/draw", "esri/geometry/Point", "esri/geometry/geometryEngine", "esri/dijit/Scalebar", "esri/dijit/OverviewMap",
"esri/layers/LayerDrawingOptions", "esri/request", "dojo/dom-construct",
"esri/tasks/query", "esri/Color", "dijit/form/Slider", "dgrid/OnDemandGrid", "dojo/dom-style",
"dgrid/Selection",
"dojo/store/Memory",
"dojo/on", "dojo/_base/array", "dojox/gfx", "esri/symbols/jsonUtils",
"dojo/_base/array", "dojo/dom", "dijit/form/Button", "dojo/data/ItemFileReadStore",
"dijit/registry",
"dojo/parser", "dojo/_base/declare",
"dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dijit/form/TextBox", "dojo/domReady!"
], function (
Map, Graphic, HomeButton, BasemapToggle, BasemapGallery, arcgisUtils, urlUtils, webMercatorUtils, Search, FeatureLayer, FeatureTable, Extent, Polygon, SimpleFillSymbol, ArcGISDynamicMapServiceLayer, ImageParameters,
InfoTemplate, ClassBreaksRenderer, GenerateRendererParameters, GenerateRendererTask, ClassBreaksDefinition,
SimpleMarkerSymbol, SimpleLineSymbol, SimpleRenderer, AlgorithmicColorRamp, esriLang, lang, Draw, Point, geometryEngine, Scalebar, OverviewMap, LayerDrawingOptions, esriRequest, domConstruct,
Query, Color, Slider, Grid, domStyle,
Selection,
Memory,
on, arrayUtils, gfx, jsonUtils,
array, dom, Button, ItemFileReadStore,
registry,
parser, declare, BorderContainer, ContentPane, TextBox, ready
)
{
parser.parse();
var DynamicMapServiceURL = 'xxx';
// define symbols
highlightSymbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([91, 91, 91]), 3
),
new Color([125, 125, 125, 0.35])
);
polygonSymbol = new SimpleFillSymbol().setStyle(SimpleFillSymbol.STYLE_SOLID).setOutline(new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1)).setColor(new Color([153, 153, 153]));
pointSymbol = new SimpleMarkerSymbol().setStyle(SimpleMarkerSymbol.STYLE_CIRCLE).setSize(8).setOutline(new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1)).setColor(new Color([153, 153, 153]));
outlineSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([91, 91, 91]), 1);
var initialExtent = new esri.geometry.Extent({
"xmin": -14901092.916080378,
"ymin": 2570827.677759068,
"xmax": -7382135.317726159,
"ymax": 7046980.0541378,
"spatialReference": {
"wkid": 102100
}
});
// instantiate infoTemplate
var infoTemplate = new InfoTemplate();
// define the dynamic map service layer
var imageParameters = new ImageParameters();
imageParameters.format = "png";
var dynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer(DynamicMapServiceURL, {
"opacity": 1.0,
"imageParameters": imageParameters
});
// add a map to the page
map = new Map("map", {
zoom: 4,
basemap: "gray",
extent: initialExtent,
infoTemplate: infoTemplate
});
// the function below displays an error message and hides the div in which the map is drawn
function showErr(err)
{
'use strict;'
console.log("Error Details: " + err);
}
// the function below adds a scalebar
function addScalebar()
{
'use strict;'
var scalebar = new Scalebar({
map: map,
// "dual" displays both miles and kilometers
// "english" is the default, which displays miles
// use "metric" for kilometers
scalebarUnit: "dual",
attachTo: "bottom-left"
});
}
// the function below adds an overview map
function addOverviewMap()
{
'use strict;'
var overviewMapDijit = new OverviewMap({
map: map,
visible: true,
attachTo: "top-right"
});
overviewMapDijit.startup();
}
// the function below adds the home/reset button to the map
function addHomeButton()
{
'use strict;'
//remove homebutton reference, before creating it again
var existingHomeButton = dijit.byId('divHomeButton');
if (existingHomeButton)
{
existingHomeButton.destroyRecursive(true);
}
var home = new HomeButton({
map: map
}, "divHomeButton");
home.startup();
home.on("error", showErr);
}
// the function below controls the transparency of the feature layer
function addTransparencySlider(value)
{
'use strict;'
val = value;
dom.byId("lbltransparencyslider").innerHTML = "Layer transparency:" + (value / 10);
//remove homebutton reference, before creating it again
var existingSlider = dijit.byId('transparencyslider');
if (existingSlider)
{
existingSlider.destroyRecursive(true);
}
var slider = new dijit.form.HorizontalSlider({
name: "transparencyslider",
value: val,
minimum: 0,
maximum: 10,
intermediateChanges: true,
discreteValues: 11,
showButtons: true,
style: "width:200px;",
onChange: function (value)
{
dynamicMapServiceLayer.setOpacity(value / 10);
dom.byId("lbltransparencyslider").innerHTML = "Layer transparency:" + (value / 10);
}
}, "transparencyslider").startup();
}
// the function below adds the drawing toolbar to the map
function addDrawingTools(map)
{
'use strict;'
//var tb = new Draw(map);
//tb.activate(esri.toolbars.Draw.EXTENT);
}
function loadBMG()
{
'use strict;'
//remove basemap gallery reference, before creating it again
var existingBMG = dijit.byId('basemapGallery');
if (existingBMG)
{
existingBMG.destroyRecursive(true);
}
var existingBMGContainer0 = dijit.byId('dijit_layout_ContentPane_0');
if (existingBMGContainer0)
{
existingBMGContainer0.destroyRecursive(true);
}
var existingBMGContainer1 = dijit.byId('dijit_layout_ContentPane_1');
if (existingBMGContainer1)
{
existingBMGContainer1.destroyRecursive(true);
}
var basemapGallery = new BasemapGallery({
showArcGISBasemaps: true,
//basemaps: basemaps,
map: map,
title: "Choose Basemap"
}, "basemapGallery");
basemapGallery.startup();
basemapGallery.on("error", showErr);
// the method below will not work with localization in effect (the title of the maps will be different depending on where
// the application is viewed).
basemapGallery.on("load", function ()
{
for (var i = 0; i < basemapGallery.basemaps.length; i++)
{
if (basemapGallery.basemaps[i].title === "Oceans" || basemapGallery.basemaps[i].title === "OpenStreetMap")
{
basemapGallery.remove(basemapGallery.basemaps[i].id);
}
}
});
}
function AddSearch(loc)
{
'use strict;'
// add search widget
var existingSearch = dijit.byId('search');
if (existingSearch)
{
existingSearch.destroyRecursive(true);
}
var search = new Search({
map: map
}, "search");
search.startup();
search.on("error", showErr);
if (typeof (loc) !== 'undefined' && loc.length > 1)
{
// search using text
search.search(loc).then(function (response)
{
console.log(response);
});
}
}
function AddGrid()
{
'use strict;'
//console.log(featureLayer.fullExtent);
var existingGrid = dijit.byId('grid');
if (existingGrid)
{
existingGrid.destroyRecursive(true);
}
//create new FeatureTable and set its properties
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
if (idx === 4)
{
myFeatureTable = new FeatureTable({
"featureLayer": featureLayer,
"map": map,
"outFields": ["PLACENAME", "field"],
"fieldInfos": [{
"name": 'PLACENAME',
"alias": 'City',
}, {
"name": field,
"alias": 'Value',
}]
}, 'grid');
} else
{
myFeatureTable = new FeatureTable({
"featureLayer": featureLayer,
"map": map,
"outFields": ["NAME", "field"],
"fieldInfos": [{
"name": 'NAME',
"alias": 'City',
},{
"name": field,
"alias": 'Value',
}]
}, 'grid');
}
myFeatureTable.startup();
console.log("feature table loaded");
}
//https://community.esri.com/thread/95520
function getInfoFromAndSetRenderer(renderer)
{
'use strict;'
symbolArray.length = 0;
labelArray.length = 0;
dojo.forEach(renderer.infos, function (itm, i)
{
symbolArray.push(itm.symbol);
var val = (i === 0 ? formatValues2(itm.minValue) + " - " + formatValues2(itm.maxValue) : formatValues2(itm.minValue + 0.1) + " - " + formatValues2(itm.maxValue));
labelArray.push(val);
});
}
function createLegend(selectedDiv)
{
'use strict;'
// destroy/empty any existing Legend item
dojo.empty(selectedDiv);
// create a drawing surface on which a Legend item will be drawn
// depends on the Data Type selected
var ysize = symbolArray.length * 25 + 75;
var xsize = (Math.max.apply(Math, $.map(labelArray, function (el)
{
return el.length
})) * 30) + 10;
var legendSurface = dojox.gfx.createSurface(dom.byId(selectedDiv), xsize, ysize);
var group = legendSurface.createGroup();
var yPos = 20;
var descriptors, legendText;
dojo.forEach(symbolArray, function (itm, idx)
{
descriptors = jsonUtils.getShapeDescriptors(itm);
group.createRect({
x: 10,
y: yPos,
width: 30,
height: 20
}).setFill(descriptors.fill).setStroke(descriptors.stroke);
//labelArray created as part of the generateRendererTask
legendText = group.createText({
x: 45,
y: yPos + 15,
text: labelArray[idx],
align: "start"
}).setFont({
family: "Arial",
size: "10pt",
weight: "normal"
}).setFill("#000000");
yPos = yPos + 25;
});
// symbolize unvailable/uncategorized/unclassified data as Data Not Available
group.createRect({
x: 10,
y: yPos,
width: 30,
height: 20
}).setFill(jsonUtils.getShapeDescriptors(symbol).fill).setStroke(jsonUtils.getShapeDescriptors(symbol).stroke);
legendText = group.createText({
x: 45,
y: yPos + 15,
text: DataUnavailableTxt,
align: "start"
}).setFont({
family: "Arial",
size: "10pt",
weight: "normal"
}).setFill("#0000");
yPos = yPos + 25;
// add classification method text below class breaks info in Legend
dom.byId("divLegendClassificationMethod").innerHTML = $('#islClassifiers option:selected').text();
// make the Legend div draggable
$("#divLegend").draggable();
}
// the 3 functions below are formatting functions, with their origins documented above them
//http://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric?page=1&tab...
var isNumber = function (n)
{
return !isNaN(parseFloat(n)) && isFinite(n);
};
//http://james.padolsey.com/javascript/wordwrap-for-javascript/
function wordwrap(str, width, brk, cut)
{
'use strict;'
brk = brk || '\n';
width = width || 75;
cut = cut || false;
if (!str)
{
return str;
}
var regex = '.{1,' + width + '}(\\s|$)' + (cut ? '|.{' + width + '}|.+$' : '|\\S+?(\\s|$)');
//this line will cause a JSLint error: Missing 'new' prefix when invoking a constructor (this error can be ignored)
return str.match(RegExp(regex, 'g')).join(brk);
}
function formatValues(num)
{
'use strict;'
return number.format(num, {
"places": 1
});
}
function formatValues2(num)
{
'use strict;'
return num = num.toFixed(1);
}
// the functions below dynamically render the data
// the function below applies the renderer generated by the createRenderer function above to the featureLayer and adds labels.
function applyRenderer(renderer)
{
'use strict;'
renderer.defaultLabel = "Data unavailable";
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
switch (idx)
{
case 0:
renderer.defaultSymbol = pointSymbol;
dynamicMapServiceLayer.setVisibleLayers([1, idx]);
break;
case 3:
renderer.defaultSymbol = polygonSymbol;
dynamicMapServiceLayer.setVisibleLayers([1, idx]);
break;
case 4:
renderer.defaultSymbol = polygonSymbol;
dynamicMapServiceLayer.setVisibleLayers([1, 2, idx]);
break;
default:
renderer.defaultSymbol = outlineSymbol;
dynamicMapServiceLayer.setVisibleLayers([1]);
break;
}
var optionsArray = [];
drawingOptions = new LayerDrawingOptions();
drawingOptions.renderer = renderer;
optionsArray[idx] = drawingOptions;
dynamicMapServiceLayer.setLayerDrawingOptions(optionsArray);
dynamicMapServiceLayer.setOpacity(val);
featureLayer.setRenderer(renderer);
map.addLayers([dynamicMapServiceLayer, featureLayer]);
// get info from the renderer, which is used to create the custom Legend in the HTML element passed to the createLegend function below
getInfoFromAndSetRenderer(renderer);
// show Legend
$('#divLegend').show();
// create the Legend for the data
createLegend("divLegendDetails");
}
function createRenderer(field)
{
'use strict;'
var classDef = new ClassBreaksDefinition();
classDef.classificationField = field;
classDef.classificationMethod = $('#islClassifiers').val() ? $('#islClassifiers').val() : "natural-breaks";
classDef.breakCount = $('#islClassifiersCount').val() ? $('#islClassifiersCount').val() : 7;
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
switch (idx)
{
case 0:
classDef.baseSymbol = pointSymbol;
break;
case 3:
classDef.baseSymbol = polygonSymbol;
break;
case 4:
classDef.baseSymbol = polygonSymbol;
break;
default:
classDef.baseSymbol = outlineSymbol;
break;
}
var colorRamp = new AlgorithmicColorRamp();
switch ($('#islColorScheme').val())
{
case 'Blue':
// original that we used
colorRamp.fromColor = new Color.fromHex("#F0F9E8");
colorRamp.toColor = new Color.fromHex("#2b8cbe");
break;
case 'Orange':
// another option -- orange-ish
colorRamp.fromColor = new Color.fromHex("#ffffe5");
colorRamp.toColor = new Color.fromHex("#662506");
break;
default:
// another option -- blue-ish
colorRamp.fromColor = new Color.fromHex("#ffffd9");
colorRamp.toColor = new Color.fromHex("#081d58");
break;
}
colorRamp.algorithm = "hsv";
classDef.colorRamp = colorRamp;
var params = new GenerateRendererParameters();
params.classificationDefinition = classDef;
var generateRenderer = new GenerateRendererTask(fl_url);
generateRenderer.execute(params, applyRenderer, showErr);
}
// set title and content of infowindow
function setIWTitleAndContent()
{
'use strict;'
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
//content = "Data Value: ${" + renderedField + "}<br />Low CI: ${" + lowCI + "}<br />High CI: ${" + highCI + "}";
content = "Data Value: ${" + renderedField + "}<br />CI: ${" + CI.replace('(', '').replace(')', '').replace(',', ' - ') + "}";
infoTemplate.setContent(content);
switch (idx)
{
case 1:
//infoTemplate.setTitle("${NAME}");
title = "${NAME}";
content = "";
infoTemplate.setContent(content);
break;
case 4:
//infoTemplate.setTitle("${PLACENAME} (${plc_tract2010}");
title = "${PLACENAME} (${plc_tract2010})";
break;
default:
//infoTemplate.setTitle("${NAME}, ${ST}");
title = "${NAME}, ${ST}";
break;
}
infoTemplate.setTitle(title);
infoTemplate.setContent(content);
}
// adds a feature layer to the map, based on the layer to show and based on the field on which to classify the data
function addFeatureLayer(layerid, fieldRendered)
{
fl_url = DynamicMapServiceURL + "/" + layerid;
setIWTitleAndContent();
featureLayer = new FeatureLayer(fl_url, {
mode: FeatureLayer.MODE_ONDEMAND,
outFields: ["*"],
infoTemplate: infoTemplate,
id: "operationallayer"
});
featureLayer.on("mouse-over", function (evt)
{
map.graphics.clear(); //use the maps graphics layer as the highlight layer
var graphic = evt.graphic;
map.infoWindow.setContent(graphic.getContent().replace('(', '').replace(')', '').replace(',', ' - '));
map.infoWindow.setTitle(graphic.getTitle());
if (graphic.geometry.type === 'point')
{
var highlightGraphic = new Graphic(graphic.geometry, pointSymbol);
} else
{
var highlightGraphic = new Graphic(graphic.geometry, highlightSymbol);
}
map.graphics.add(highlightGraphic);
map.infoWindow.show(evt.screenPoint, map.getInfoWindowAnchor(evt.screenPoint));
});
// limit the feature table to the records of the feature layer in the current map extent
featureLayer.on("load", function ()
{
var extent = featureLayer.fullExtent;
if (webMercatorUtils.canProject(extent, map))
{
map.on("extent-change", lang.hitch(this, function (params)
{
// taken from https://community.esri.com/thread/173929
var oidFld = featureLayer.objectIdField;
var query = new Query();
query.geometry = params.extent;
query.spatialRelationship = Query.SPATIAL_REL_INTERSECTS;
featureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW);
featureLayer.queryIds(query, lang.hitch(this, function (objectIds)
{
myFeatureTable.selectedRowIds = objectIds;
myFeatureTable._showSelectedRecords();
//myFeatureTable._gridTitleNode.innerHTML = featureLayer.name + ' (' + (objectIds.length != 'undefined' ? (objectIds.length > 1 ? objectIds.length + ' Features)' : 1 + ' Feature)') : "");
$(".esri-feature-table-title").text(featureLayer.name + ' (' +(objectIds.length != 'undefined' ? (objectIds.length > 1 ? objectIds.length + ' Features)': 1 + ' Feature)'): ""));
}));
}))
}
// add feature table
AddGrid();
});
console.log("feature layer loaded");
featureLayer.on("error", showErr);
switch (layerid)
{
// city point data...does not show when zoomed in beyond 1:36978595
// show State boundaries with city point data
case 0:
// set transparency/opacity value
val = 10;
//createRenderer(fieldRendered);
map.addLayers([featureLayer]);
// add search widget...layer added will be from city point layer
//AddSearch();
// add feature table
//AddGrid();
// add transparency slider
//addTransparencySlider(val);
//map.addLayers([featureLayer]);
break;
// State outlines (no operational data)...shows at all zoom levels
case 1:
// set the visibility level (turn on State and city boundaries)
//visiblelayers.push(2);
//dynamicMapServiceLayer.setVisibleLayers(visiblelayers);
//map.addLayers([dynamicMapServiceLayer]);
//dynamicMapServiceLayer.setVisibleLayers([1,2]);
// don't show Legend
$('#divLegend').hide();
// don't show the feature table
$('#divGrid').hide();
// define base symbol and renderer...
// set the feature layer render
// add the feature layer to the map
symbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1);
renderer = new SimpleRenderer(symbol);
var optionsArray = [];
drawingOptions = new LayerDrawingOptions();
drawingOptions.renderer = renderer;
featureLayer.setRenderer(renderer);
//idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
optionsArray[1] = drawingOptions;
dynamicMapServiceLayer.setLayerDrawingOptions(optionsArray);
dynamicMapServiceLayer.setVisibleLayers([1]);
//featureLayer.setRenderer(renderer);
map.addLayers([dynamicMapServiceLayer]);
break;
// city boundaries/outlines (no operational data)...
// does not show when zoomed out beyond 1:36978595
// show State boundaries too
case 2:
// don't show Legend
$('#divLegend').hide();
// don't show the feature table
$('#divGrid').hide();
// define base symbol and renderer...
// set the feature layer render
// set dynamic map service layer drawing options
// add the dynamic map service layer and feature layer to the map
symbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1);
//symbol = new SimpleFillSymbol().setOutline(new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1)).setColor(new Color([153, 153, 153]));
var cityoutlinerenderer = new SimpleRenderer(symbol);
var optionsArray = [];
drawingOptions = new LayerDrawingOptions();
drawingOptions.renderer = cityoutlinerenderer;
//idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
optionsArray[2] = drawingOptions;
dynamicMapServiceLayer.setLayerDrawingOptions(optionsArray);
dynamicMapServiceLayer.setVisibleLayers([2]);
map.addLayers([dynamicMapServiceLayer]);
break;
// city boundaries with operational data
// does not show when zoomed out beyond 1:6000000
// show State boundaries too
case 3:
// set transparency/opacity value
val = 3;
//createRenderer(fieldRendered);
map.addLayers([featureLayer]);
// add search widget...layer added will be from city polygon layer
//AddSearch();
// add feature table
$('#divGrid').show();
//AddGrid();
// add transparency slider
//addTransparencySlider(val);
break;
// census tract boundaries with operational data
// does not show when zoomed out beyond 1:2311162
// show State boundaries and city boundaries too
case 4:
// set transparency/opacity value
val = 3;
//createRenderer(fieldRendered);
map.addLayers([featureLayer]);
// add search widget...layer added will be from census tracts layer
//AddSearch();
// add feature table
$('#divGrid').show();
//AddGrid();
// add transparency slider
//addTransparencySlider(val);
break;
default:
// don't show Legend
$('#divLegend').hide();
// define base symbol and renderer...
// set the feature layer render
// set dynamic map service layer drawing options
// add the dynamic map service layer
symbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1);
var cityoutlinerenderer = new SimpleRenderer(symbol);
var optionsArray = [];
drawingOptions = new LayerDrawingOptions();
drawingOptions.renderer = cityoutlinerenderer;
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
optionsArray[idx] = drawingOptions;
dynamicMapServiceLayer.setLayerDrawingOptions(optionsArray);
dynamicMapServiceLayer.setVisibleLayers([idx]);
map.addLayers([dynamicMapServiceLayer]);
break;
}
}
function addLayerToMap()
{
'use strict';
renderedField = "field";
switch (true)
{
case (map.getScale() >= 36978595):
addFeatureLayer(0, renderedField);
break;
case (map.getScale() < 36978595 && map.getScale() >= 6000000):
addFeatureLayer(2, renderedField);
break;
case (map.getScale() < 6000000 && map.getScale() > 2311162):
addFeatureLayer(3, renderedField);
break;
case (map.getScale() <= 2311162):
addFeatureLayer(4, renderedField);
break;
default:
addFeatureLayer(1, renderedField);
break;
}
}
map.on("load", function ()
{
// add a check mark image to the default measure
DefaultFilterCheck();
// add transparency slider
val = 3;
addTransparencySlider();
// add search box
AddSearch();
// add a scalbar
addScalebar();
// add an overview map
addOverviewMap();
// add a refresh/home button
addHomeButton();
// add basemap gallery
loadBMG();
// add drawing toolbox
addDrawingTools(map);
// add appropriate layer to the map
addLayerToMap();
});
map.on("extent-change", function (evt)
{
console.log("Map extent changed");
console.log(map.extent);
//if (map.loaded)
//{
// console.log("map already loaded...inside map extent change");
// var isEqual = false;
// if (oldExtent != null && oldExtent !== 'undefined')
// {
// isEqual = geometryEngine.equals(oldExtent, evt.extent);
// }
// if (isEqual)
// {
// //console.log('EXTENT IS THE SAME');
// } else
// {
// //console.log('EXTENT IS DIFFERENT');
// addLayerToMap();
// }
// //SET OLD EXTENT
// oldExtent = evt.extent;
//}
addLayerToMap();
}, showErr);
});
Thanks...Chris
Chris,
Looking at your code I am really confused why you would ever want to add a featureLayer object each and every time the map zooms... Especially when I do not see anywhere in your code that the layer is removed before adding another.
This whole workflow seems expensive and overkill. Why are you not just adding all 5 of your layers at the start with thier min and max scales set?
Inexperience! I will give that approach a try.
I appreciate the feedback. Thanks...Chris
Will do. Thanks!
Robert, I really appreciate your help.
OK...let me describe the entire workflow.
There is a map service with 5 layers, which are scale dependent. The service was published with the scales set in the map document, so the different layers dis/appear naturally when a user zooms in/out. This would be similar to adding the feature layers with min and max scales, as you suggested, I assume? There is some symbology associated with each layer, but for 3 of the 5 layers that have actual non-spatial data associated with them, I would like to change this symbology...more on that below.
On the UI, a user is able to select a variable (a column in the layers of the map service) that they would like to see mapped. The ClassBreaksRenderer and the generateRendererTask are used to classify that data and present it as a choropleth map or a data with points, colored for different classes. The user is also able to change the classification method and number of classes used to present the data in the UI.
I tried adding all layers, with their renderers defined, on map load, as you suggested, but I must not be doing something correctly, as I do not see all of the layers. It seems as though I can only add one feature layer at a time. I know that there is the ability to add multiple layers at a time, but I cannot seem to find the issue (see the code below).
var map, grid, fl_url, symbol, polygonSymbol, highlightSymbol, pointSymbol, outlineSymbol, line, renderer, featureLayer, loading, myFeatureTable, idx, title, content, drawingOptions, placeholdertxt, fieldsToDisplay, selectionToolbar, val, renderedField, CI, citypointlayer, citypolylayer, censuspolylayer;
var visiblelayers = [],
symbolArray = [],
labelArray = [],
fieldsToSearch = [];
var DataUnavailableTxt = "Data unavailable",
oldExtent = null;
require([
"esri/map", "esri/graphic", "esri/dijit/HomeButton", "esri/dijit/BasemapToggle", "esri/dijit/BasemapGallery", "esri/arcgis/utils", "esri/urlUtils", "esri/geometry/webMercatorUtils", "esri/dijit/Search", "esri/layers/FeatureLayer", "esri/dijit/FeatureTable", "esri/geometry/Extent", "esri/geometry/Polygon",
"esri/symbols/SimpleFillSymbol", "esri/layers/ArcGISDynamicMapServiceLayer", "esri/layers/ImageParameters", "esri/InfoTemplate",
"esri/renderers/ClassBreaksRenderer", "esri/tasks/GenerateRendererParameters", "esri/tasks/GenerateRendererTask",
"esri/tasks/ClassBreaksDefinition", "esri/symbols/SimpleMarkerSymbol", "esri/symbols/SimpleLineSymbol", "esri/renderers/SimpleRenderer", "esri/tasks/AlgorithmicColorRamp", "esri/lang", "dojo/_base/lang", "esri/toolbars/draw", "esri/geometry/Point", "esri/geometry/geometryEngine", "esri/dijit/Scalebar", "esri/dijit/OverviewMap",
"esri/layers/LayerDrawingOptions", "esri/request", "dojo/dom-construct",
"esri/tasks/query", "esri/Color", "dijit/form/Slider", "dgrid/OnDemandGrid", "dojo/dom-style",
"dgrid/Selection",
"dojo/store/Memory",
"dojo/on", "dojo/_base/array", "dojox/gfx", "esri/symbols/jsonUtils",
"dojo/_base/array", "dojo/dom", "dijit/form/Button", "dojo/data/ItemFileReadStore",
"dijit/registry",
"dojo/parser", "dojo/_base/declare",
"dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dijit/form/TextBox", "dojo/domReady!"
], function (
Map, Graphic, HomeButton, BasemapToggle, BasemapGallery, arcgisUtils, urlUtils, webMercatorUtils, Search, FeatureLayer, FeatureTable, Extent, Polygon, SimpleFillSymbol, ArcGISDynamicMapServiceLayer, ImageParameters,
InfoTemplate, ClassBreaksRenderer, GenerateRendererParameters, GenerateRendererTask, ClassBreaksDefinition,
SimpleMarkerSymbol, SimpleLineSymbol, SimpleRenderer, AlgorithmicColorRamp, esriLang, lang, Draw, Point, geometryEngine, Scalebar, OverviewMap, LayerDrawingOptions, esriRequest, domConstruct,
Query, Color, Slider, Grid, domStyle,
Selection,
Memory,
on, arrayUtils, gfx, jsonUtils,
array, dom, Button, ItemFileReadStore,
registry,
parser, declare, BorderContainer, ContentPane, TextBox, ready
)
{
parser.parse();
var DynamicMapServiceURL = "xxx"
// define symbols
highlightSymbol = new SimpleFillSymbol(
SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(
SimpleLineSymbol.STYLE_SOLID,
new Color([91, 91, 91]), 3
),
new Color([125, 125, 125, 0.35])
);
polygonSymbol = new SimpleFillSymbol().setStyle(SimpleFillSymbol.STYLE_SOLID).setOutline(new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1)).setColor(new Color([153, 153, 153]));
pointSymbol = new SimpleMarkerSymbol().setStyle(SimpleMarkerSymbol.STYLE_CIRCLE).setSize(8).setOutline(new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([85, 85, 85]), 1)).setColor(new Color([153, 153, 153]));
outlineSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([91, 91, 91]), 1);
var initialExtent = new esri.geometry.Extent({
"xmin": -14901092.916080378,
"ymin": 2570827.677759068,
"xmax": -7382135.317726159,
"ymax": 7046980.0541378,
"spatialReference": {
"wkid": 102100
}
});
// instantiate infoTemplate
var infoTemplate = new InfoTemplate();
// define the dynamic map service layer
//var imageParameters = new ImageParameters();
//imageParameters.format = "png";
//var dynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer(DynamicMapServiceURL, {
// "opacity": 1.0,
// "imageParameters": imageParameters
//});
map = new Map("divMapContainer", {
basemap: "gray", extent: initialExtent, zoom: 4
});
//map.addLayer(dynamicMapServiceLayer);
map.on("load", loadTable);
// the function below displays an error message and hides the div in which the map is drawn
function showErr(err)
{
'use strict;'
console.log("Error Details: " + err);
}
// the functions below dynamically render the data
// the function below applies the renderer generated by the createRenderer function above to the featureLayer and adds labels.
function applyRenderer(renderer)
{
'use strict;'
renderer.defaultLabel = DataUnavailableTxt;
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
switch (idx)
{
case 0:
renderer.defaultSymbol = pointSymbol;
featureLayer.setRenderer(renderer);
citypointlayer = featureLayer;
//dynamicMapServiceLayer.setVisibleLayers([1, idx]);
break;
case 3:
renderer.defaultSymbol = polygonSymbol;
featureLayer.setRenderer(renderer);
citypolylayer = featureLayer;
//dynamicMapServiceLayer.setVisibleLayers([1, idx]);
break;
case 4:
renderer.defaultSymbol = polygonSymbol;
featureLayer.setRenderer(renderer);
censuspolylayer = featureLayer;
// dynamicMapServiceLayer.setVisibleLayers([1, 2, idx]);
break;
default:
renderer.defaultSymbol = outlineSymbol;
// dynamicMapServiceLayer.setVisibleLayers([1]);
break;
}
//var optionsArray = [];
//drawingOptions = new LayerDrawingOptions();
//drawingOptions.renderer = renderer;
//optionsArray[idx] = drawingOptions;
//dynamicMapServiceLayer.setLayerDrawingOptions(optionsArray);
//dynamicMapServiceLayer.setOpacity(val);
//featureLayer.setRenderer(renderer);
//map.addLayer(featureLayer);
}
function createRenderer(field)
{
'use strict;'
var classDef = new ClassBreaksDefinition();
classDef.classificationField = field;
classDef.classificationMethod = "natural-breaks";
classDef.breakCount = 7;
idx = parseInt(fl_url.split(DynamicMapServiceURL + "/")[1]);
switch (idx)
{
case 0:
classDef.baseSymbol = pointSymbol;
break;
case 3:
classDef.baseSymbol = polygonSymbol;
break;
case 4:
classDef.baseSymbol = polygonSymbol;
break;
default:
classDef.baseSymbol = outlineSymbol;
break;
}
var colorRamp = new AlgorithmicColorRamp();
colorRamp.fromColor = new Color.fromHex("#F0F9E8");
colorRamp.toColor = new Color.fromHex("#2b8cbe");
colorRamp.algorithm = "hsv";
classDef.colorRamp = colorRamp;
var params = new GenerateRendererParameters();
params.classificationDefinition = classDef;
var generateRenderer = new GenerateRendererTask(fl_url);
generateRenderer.execute(params, applyRenderer, showErr);
}
function loadTable()
{
// city point layer
fl_url = DynamicMapServiceURL + "/0";
featureLayer = new FeatureLayer(fl_url, {
mode: FeatureLayer.MODE_ONDEMAND,
visible: true,
outFields: ["*"],
id: "fLayer"
});
createRenderer(fieldtoclassify);
// city polygon layer, with data
fl_url = DynamicMapServiceURL + "/3";
featureLayer = new FeatureLayer(fl_url, {
mode: FeatureLayer.MODE_ONDEMAND,
visible: true,
outFields: ["*"],
id: "fLayer"
});
createRenderer(fieldtoclassify);
// census tract polygon layer, with data
fl_url = DynamicMapServiceURL + "/4";
featureLayer = new FeatureLayer(fl_url, {
mode: FeatureLayer.MODE_ONDEMAND,
visible: true,
outFields: ["*"],
id: "fLayer"
});
createRenderer(fieldtoclassify);
//set map extent
on(featureLayer, "load", function (evt)
{
var extent = featureLayer.fullExtent;
if (webMercatorUtils.canProject(extent, map))
{
map.setExtent(webMercatorUtils.project(extent, map));
on(map, 'extent-change', lang.hitch(this, function (params)
{
var oidFld = featureLayer.objectIdField;
var query = new Query();
query.geometry = params.extent;
query.spatialRelationship = Query.SPATIAL_REL_CONTAINS;
featureLayer.selectFeatures(query, FeatureLayer.SELECTION_NEW);
featureLayer.queryIds(query, lang.hitch(this, function (objectIds)
{
myFeatureTable.selectedRowIds = objectIds;
myFeatureTable._showSelectedRecords();
myFeatureTable._gridTitleNode.innerHTML = featureLayer.name + ' (' + objectIds.length + ' Features)';
}));
}));
}
});
map.addLayers([citypointlayer, citypolylayer, censuspolylayer]);
myFeatureTable = new FeatureTable({
"featureLayer": featureLayer,
"outFields": ["*"],
"map": map,
"gridOptions": {}
}, 'grid');
//myFeatureTable.startup();
}
});
Any more ideas with this code or the previous one that I sent?
Again, thanks for time, guidance and patience.
- Chris
Chris,
I am struggling to make sense of your code. It would be better for you to start a new thread and attach your complete code.