IdentifyTask Returning Scale-Dependent Layers When Outside of Scale Range

4598
12
10-11-2012 06:54 AM
AndrewBrown1
Occasional Contributor II
Hello,

I'm working on my second web mapping application, and I am implementing an identifyTask on a couple point layers that are scale-dependent. At first, the layers are disabled until the user zooms closer to the points. Eventually, the points are re-enabled because the current scale meets the scale criteria. If I turn on one of the n layers and attempt to identify an area around the point, my identifyTask will identify the layer that's turned on and the layers that are turned off. I believe this is a bug of some sort. My code is below:

identifyParams = new esri.tasks.IdentifyParameters();
            identifyParams.tolerance = 3;
            identifyParams.returnGeometry = true;
            identifyParams.layerIds = [1,2,3,4,5,6,7,9];
            identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_VISIBLE;
            identifyParams.geometry = geometry;
            identifyParams.mapExtent = map.extent;
            identifyParams.width = map.width;
            identifyParams.height = map.height;
            identifyTask.execute(identifyParams, function (identifyResults) {


If I were to output identifyResults to the console, it would contain the visible and non-visible layers. As you can see, I specified LAYER_OPTION_VISIBLE, so it should only be identifying layers that are turned on, not the ones that are enabled due to scale dependency! I'm using 3.2compact as my API.

Thanks,
Andrew
0 Kudos
12 Replies
JohnGravois
Frequent Contributor
hi andrew,

LAYER_OPTION_VISIBLE means checked on in the map document used to create the map service, whether or not they show up at a particular scale.

if you take JavaScript out of the equation and attempt to identify a feature directly in REST, you will notice that you pass in geometry to help you search, but you don't pass in any information about a particular scale.

see the following thread for more information.
0 Kudos
AndrewBrown1
Occasional Contributor II
I guess I'll just nix the scale-dependent layers then... makes my life easier. Thanks!
0 Kudos
AndrewBrown1
Occasional Contributor II
Actually, I just thought of something. My layers are scale-dependent, but they're also initially turned off in the MXD. I can still identify the points when they're enabled but turned off in the mapping application. It shouldn't do this. See my attached screenshot. The circles represent a "selected" point. The "other" layer is turned on and it's properly selected. The other layers are off yet they're "selected" as indicated by the circles.

If I open the MXD in ArcMap and zoom to meet the layer dependency, I cannot identify the points using "Visible Layers" under my Identify tool.
0 Kudos
JohnGravois
Frequent Contributor
i did some more testing this morning and i made a mistake yesterday in stating that the identify operation doesn't take scale into account.  while a scale value is not explicitly supplied, it is necessary to pass in a map extent when identifying.  in my tests, rightfully, the values returned given a specific tolerance were different depending on the extent.

identifyParams.layerIds = [1,2,3,4,5,6,7,9];

i took a look at the REST documentation and it confirms your expectation that using visible in conjunction with explicitly declared layers should only return results if a returned item is included in one of layers requested AND and would be visible in the map service at the current extent.

http://resources.arcgis.com/en/help/rest/apiref/identify.html

i put together a sample application which seems to demonstrate that this is not the case, as a layer index will be returned (even if it has a default visibility of FALSE in the map service)

http://jsfiddle.net/jagravois/nPpp9/1/

all in all, it seems that you should be able to get the results you want by not asking for a specific layer if you don't want it to be included in the result, whether you are using VISIBLE or ALL as your layerOption parameter.

i hope this information helps.
0 Kudos
AdrianMarsden
Occasional Contributor III
For info, the LAYER_OPTION_VISIBLE doesn't work, it is a know bug (see post in http://forums.arcgis.com/threads/68803-BUG-.visibleLayers-returns-group-layeys?p=239911#post239911)

I had the same issue as you did today - or rather the exact opposite, ID not working when I could see the features, and it was like John says, all tied up in the map extent, although I passed it the current extent I hadn't also passed the height and width.  Doing this sorted my issue.
0 Kudos
DouglasHall
New Contributor III
Been dealing with this myself -- and it's different between jsapi 2.x and 3.x. Only what's showing on map will be identified on. Note the checking of subLayerIds for null, scale checking, etc

Solution is for jaspi 3.x

var referenceLayer = new esri.layers.ArcGISDynamicMapServiceLayer(referenceMapServiceName, {
* * id: 'referenceLayer'
});

var layersInScale;
if (referenceLayer.visible === true && !(referenceLayer.visibleLayers.length === 0 || referenceLayer.visibleLayers[0] === -1)) {
            layersInScale = [];
            dojo.foreach(referenceLayer.createDynamicLayerInfosFromLayerInfos(), function (v) {
                if (v.subLayerIds === null &&
                        (v.minScale === undefined || v.minScale === 0 || currentScale <= v.minScale) &&
                        (v.maxScale === undefined || v.maxScale === 0 || currentScale >= v.maxScale)) {
                    layersInScale.push(v.id);
                }
});

var identifyParams = new esri.tasks.IdentifyParameters(),
    identifyTask = new esri.tasks.IdentifyTask(referenceLayer.url);
identifyParams.geometry = geom;
identifyParams.mapExtent = map.extent;
identifyParams.tolerance = 3;
identifyParams.returnGeometry = true;
identifyParams.layerIds = aLayerIds;
//only refers to default visible layers as defined on the server
identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = map.width;
identifyParams.height = map.height;
return identifyTask.execute(identifyParams);


Bonus: Identifies on multiple services at once and return as one array using dojo.DeferredList
(using some jQuery loops just change to for or dojo.foreach)

dojo.require("dojo.DeferredList");

referenceLayer = new esri.layers.ArcGISDynamicMapServiceLayer(referenceMapServiceName, {
    id: 'referenceLayer'
});

//Operational layers
operationalLayer = new esri.layers.ArcGISDynamicMapServiceLayer(operationalMapServiceName, {
    id: 'operationalLayer'
});

function executeIdentify(geom, serviceName, aLayerIds) {
    var identifyParams = new esri.tasks.IdentifyParameters(),
        identifyTask = new esri.tasks.IdentifyTask(serviceName);
    identifyParams.geometry = geom;
    identifyParams.mapExtent = map.extent;
    identifyParams.tolerance = 3;
    identifyParams.returnGeometry = true;
    identifyParams.layerIds = aLayerIds;
    //only refers to default visible layers as defined on the server
    identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;
    identifyParams.width = map.width;
    identifyParams.height = map.height;
    return identifyTask.execute(identifyParams);
}

function doIdentify(evt) {
    var geom = evt.mapPoint,
        layersInScale,
        aDeferreds = [],
        defList,
        currentScale = map.getScale(),
        layersToIdentify = [referenceLayer, operationalLayer];

    map.graphics.clear();
    identifyLayerKeyPrevious = undefined;

    $.each(layersToIdentify, function (key, value) {
        if (value.visible === true && !(value.visibleLayers.length === 0 || value.visibleLayers[0] === -1)) {
            layersInScale = [];
            $.each(value.createDynamicLayerInfosFromLayerInfos(), function (k, v) {
                if (v.subLayerIds === null &&
                        (v.minScale === undefined || v.minScale === 0 || currentScale <= v.minScale) &&
                        (v.maxScale === undefined || v.maxScale === 0 || currentScale >= v.maxScale)) {
                    layersInScale.push(v.id);
                }
            });
            if (layersInScale.length > 0) {
                aDeferreds.push(executeIdentify(evt.mapPoint, value.url, layersInScale));
            }
        }
    });

    // create a deferred list to aggregate the state for all identify queries
    defList = new dojo.DeferredList(aDeferreds);
    defList.then(function (res) {
        // "res" is 2D array of results
        // array[0] indicates success or failure
        // array[1] is the array of identity results returned
        formatIdentifyResults(res);
    });
}
0 Kudos
AndrewBrown1
Occasional Contributor II
Thank you for your help! I'll definitely implement this into my application.

Been dealing with this myself -- and it's different between jsapi 2.x and 3.x. Only what's showing on map will be identified on. Note the checking of subLayerIds for null, scale checking, etc

Solution is for jaspi 3.x

var referenceLayer = new esri.layers.ArcGISDynamicMapServiceLayer(referenceMapServiceName, {
* * id: 'referenceLayer'
});

var layersInScale;
if (referenceLayer.visible === true && !(referenceLayer.visibleLayers.length === 0 || referenceLayer.visibleLayers[0] === -1)) {
            layersInScale = [];
            dojo.foreach(referenceLayer.createDynamicLayerInfosFromLayerInfos(), function (v) {
                if (v.subLayerIds === null &&
                        (v.minScale === undefined || v.minScale === 0 || currentScale <= v.minScale) &&
                        (v.maxScale === undefined || v.maxScale === 0 || currentScale >= v.maxScale)) {
                    layersInScale.push(v.id);
                }
});

var identifyParams = new esri.tasks.IdentifyParameters(),
    identifyTask = new esri.tasks.IdentifyTask(referenceLayer.url);
identifyParams.geometry = geom;
identifyParams.mapExtent = map.extent;
identifyParams.tolerance = 3;
identifyParams.returnGeometry = true;
identifyParams.layerIds = aLayerIds;
//only refers to default visible layers as defined on the server
identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = map.width;
identifyParams.height = map.height;
return identifyTask.execute(identifyParams);


Bonus: Identifies on multiple services at once and return as one array using dojo.DeferredList
(using some jQuery loops just change to for or dojo.foreach)

dojo.require("dojo.DeferredList");

referenceLayer = new esri.layers.ArcGISDynamicMapServiceLayer(referenceMapServiceName, {
    id: 'referenceLayer'
});

//Operational layers
operationalLayer = new esri.layers.ArcGISDynamicMapServiceLayer(operationalMapServiceName, {
    id: 'operationalLayer'
});

function executeIdentify(geom, serviceName, aLayerIds) {
    var identifyParams = new esri.tasks.IdentifyParameters(),
        identifyTask = new esri.tasks.IdentifyTask(serviceName);
    identifyParams.geometry = geom;
    identifyParams.mapExtent = map.extent;
    identifyParams.tolerance = 3;
    identifyParams.returnGeometry = true;
    identifyParams.layerIds = aLayerIds;
    //only refers to default visible layers as defined on the server
    identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;
    identifyParams.width = map.width;
    identifyParams.height = map.height;
    return identifyTask.execute(identifyParams);
}

function doIdentify(evt) {
    var geom = evt.mapPoint,
        layersInScale,
        aDeferreds = [],
        defList,
        currentScale = map.getScale(),
        layersToIdentify = [referenceLayer, operationalLayer];

    map.graphics.clear();
    identifyLayerKeyPrevious = undefined;

    $.each(layersToIdentify, function (key, value) {
        if (value.visible === true && !(value.visibleLayers.length === 0 || value.visibleLayers[0] === -1)) {
            layersInScale = [];
            $.each(value.createDynamicLayerInfosFromLayerInfos(), function (k, v) {
                if (v.subLayerIds === null &&
                        (v.minScale === undefined || v.minScale === 0 || currentScale <= v.minScale) &&
                        (v.maxScale === undefined || v.maxScale === 0 || currentScale >= v.maxScale)) {
                    layersInScale.push(v.id);
                }
            });
            if (layersInScale.length > 0) {
                aDeferreds.push(executeIdentify(evt.mapPoint, value.url, layersInScale));
            }
        }
    });

    // create a deferred list to aggregate the state for all identify queries
    defList = new dojo.DeferredList(aDeferreds);
    defList.then(function (res) {
        // "res" is 2D array of results
        // array[0] indicates success or failure
        // array[1] is the array of identity results returned
        formatIdentifyResults(res);
    });
}
0 Kudos
AndrewBrown1
Occasional Contributor II
Will the LAYER_OPTION_VISIBLE bug be fixed in the next version of the API?

i did some more testing this morning and i made a mistake yesterday in stating that the identify operation doesn't take scale into account.  while a scale value is not explicitly supplied, it is necessary to pass in a map extent when identifying.  in my tests, rightfully, the values returned given a specific tolerance were different depending on the extent.

identifyParams.layerIds = [1,2,3,4,5,6,7,9];

i took a look at the REST documentation and it confirms your expectation that using visible in conjunction with explicitly declared layers should only return results if a returned item is included in one of layers requested AND and would be visible in the map service at the current extent.

http://resources.arcgis.com/en/help/rest/apiref/identify.html

i put together a sample application which seems to demonstrate that this is not the case, as a layer index will be returned (even if it has a default visibility of FALSE in the map service)

http://jsfiddle.net/jagravois/nPpp9/1/

all in all, it seems that you should be able to get the results you want by not asking for a specific layer if you don't want it to be included in the result, whether you are using VISIBLE or ALL as your layerOption parameter.

i hope this information helps.
0 Kudos
AdrianMarsden
Occasional Contributor III
It's been open for three years, so I wouldn't hold your breath.
0 Kudos