Closed msereda closed 10 years ago
This is a common request from way back in the "old days" of ArcIMS. Typically we would have a drop down list of the layers to choose the "Active" layer for things like identify, select, buffering, etc.
A title pane widget sounds right. I am wondering though if this should be separate new widget. An alternative approach would be to modify the existing identify widget so it can support a type of titlePane
as well as the current invisible
type - one mode has a user interface, the other does not and keeps the current identify all
behavior. I also might suggest you use a drop-down list instead of a grid for the layers and then include an All Layers
option which would be the default until the user selects a different individual layer. thoughts?
Thanks @tmcgee, yes, the app we're replacing is an old ArcIMS app, so they want to retain certain functionality. They had the ability to click any of the layers in the legend and identify on it.
I like the idea of a dropdown though, I think I will explore that. I misspoke in my original post about 'adding' an identify titlepane, I was planning to convert my current one into a 'TitlePane' type, add a template html file and make the necessary changes to my identify.js file.
@msereda Glad to hear another ArcIMS app is biting the dust! I can't even count how many ArcIMS apps I have replaced in my day! ;) When we do this for customers, we take the opportunity to change their paradigm of thinking. In other words, don't just simply try to replace all the existing functionality. If thats the goal, then there is no real reason to replace it. Instead talk to the users about their workflows and what things they would like it to do that it does not do and things that are painful right now. Improve those and create a new app that everyone will love. Remember, you can't please everyone, so don't try. Someone will always complain, thats normal.
As for the widget, I think its a great idea and I would implement it as a TitlePane widget. It would be very simple to take the existing code and refactor it into a widget with a ui. The drop down with a list of layers and an all option makes the most sense. I would leave this as a separate widget however.
I lean towards this being a single widget that can have a UI or doesn't. If this becomes a separate widget as opposed to an evolution of the existing identify widget, I suggest we avoid duplicating the same/similar identify logic in two widgets. That makes the code base harder to maintain.
If a second titlePane version comes into existence, perhaps refactoring the existing widget to use topic publish/subscribe so the invisible identify can work with/without the titlePane UI in a separate widget? I've considered something similar to avoid redundant code for highlighting/selecting/zooming to feature(s).
We wrote an Identify Widget for the Esri Flex Viewer that did this. I don’t think the code will help much (but I can provide it if you want), but maybe you will like the user interface. For point selection you can select as many layers as you want and it will “drill down” through them. For selection by line or polygon, you can only select one layer.
You can double up the selections also. For example, you can select a subdivision, and then select all the parcels in that subdivision.
Hope this helps.
Larry
[cid:image001.jpg@01CFA0F2.BD3D1360]
From: msereda [mailto:notifications@github.com] Sent: Tuesday, July 15, 2014 6:11 PM To: DavidSpriggs/ConfigurableViewerJSAPI Subject: [ConfigurableViewerJSAPI] Selecting a single layer to identify on (#119)
This is probably a good issue for the 'Request for help' category. Anyway:
I have a requirement for users to be able to select a single layer, then when clicking the map to identify, having the identify tool only identify on that layer. They should also be able to unselect the layer and have the identify go back to identifying everything visible.
Anyone ever had to do this before? I'm not eager to crack open the ToC.js file, so I've been thinking about adding an 'Identify' Titlepane object with a grid list of the layers, then allowing the user to select a single layer from the grid and the identify look for a selected grid item. If anyone has any better ideas though, I'd love to hear them!
— Reply to this email directly or view it on GitHubhttps://github.com/DavidSpriggs/ConfigurableViewerJSAPI/issues/119.
Thanks Larry,
I think there was supposed to be an image embedded in your reply. It didn't make it into the comments.
Sorry, There wasn’t an image, but I forgot to paste in the URL. Must be getting old.
Larry
[cid:image001.jpg@01CFA0F4.F4F27AF0]
From: Tim McGee [mailto:notifications@github.com] Sent: Wednesday, July 16, 2014 12:51 PM To: DavidSpriggs/ConfigurableViewerJSAPI Cc: Larry Stout Subject: Re: [ConfigurableViewerJSAPI] Selecting a single layer to identify on (#119)
Thanks Larry,
I think there was supposed to be an image embedded in your reply. It didn't make it into the comments.
— Reply to this email directly or view it on GitHubhttps://github.com/DavidSpriggs/ConfigurableViewerJSAPI/issues/119#issuecomment-49194338.
ah. I see. thanks for the link.
Thanks guys, I'm not sure yet what I'll actually end up building to accomplish the requirement, but all of your comments (and link @LarryStout) help a lot.
@DavidSpriggs We are doing a lot of process improvement with the new app, but the 'identify on single layer' is a must-have for them, so I'll have to do something for it.
@msereda I get it and it's on our list of things to build: https://trello.com/b/TjjipGmV/configurable-viewer
@DavidSpriggs I actually finished my version of it today and sent it out to the users to look at. I considered posting it here but it needs some performance re-work (I'm not great w/ dojo) and some of the code is quite specific to our environment so I'm not sure it'd be all that useful to anyone else anyway.
@msereda please do consider sharing your version. It may not be a candidate for direct contribution to this project because of code specific to your environment. But I see no problem with that or possibly less than optimized dojo code. Your version likely would give others here (like me) a leg up on creating a more generic version. I've worked with many other JavaScript libraries but not so much with dojo and so I'm learning new things every day. If you feel so inclined, you can share the code here. Alternatively, you can send it directly to me. My contact info is on my github profile @tmcgee
@msereda Cool! Post a screen shot so we can see how you implemented it.
Unfortunately I'm literally just leaving on vacation for a week so I won't have access to any of my code until I'm back. I've thrown this on my TODO list though so I'll post or fork something when I'm back.
Sorry guys, this is still coming, just need a spare night to make it happen.
viewer.js
identify: {
include: true,
id: 'identify',
type: 'titlePane',
path: 'gis/dijit/Identify',
title: 'Identify',
open: false,
position: 2,
options: 'config/identify'
},
Identify.html
<div class="gis_IdentifyDijit">
<div class="formContainer">
<div data-dojo-type="dijit.form.Form" data-dojo-attach-point="identifyFormDijit">
Choose a single layer to identify on:
<input type="select" data-dojo-type="dijit.form.FilteringSelect" data-dojo-props="name:'identifyLayer',autoComplete:false,required:false,searchAttr:'name',style:'width:100%;'"
data-dojo-attach-point="identifyLayerDijit" />
- Leave blank to identify on all layers
</div>
</div>
</div>
Identify.js
define([
'dojo/_base/declare',
'dijit/_WidgetBase',
'dijit/_TemplatedMixin',
'dijit/_WidgetsInTemplateMixin',
'dijit/form/Form',
'dijit/form/FilteringSelect',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/store/Memory',
'esri/lang',
'esri/tasks/IdentifyTask',
'esri/tasks/IdentifyParameters',
'esri/dijit/PopupTemplate',
'dojo/on',
'dojo/promise/all',
'dojo/text!./Identify/templates/Identify.html',
'xstyle/css!./Identify/css/Identify.css'
], function (declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Form, FilteringSelect, lang, array, Memory, esriLang, IdentifyTask, IdentifyParameters, PopupTemplate, on, all, IdentifyTemplate, css) {
var Identify = declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
widgetsInTemplate: true,
templateString: IdentifyTemplate,
baseClass: 'gis_IdentifyDijit',
postCreate: function () {
this.inherited(arguments);
this.layers = [];
array.forEach(this.map.layerIds, function (layerId) {
var layer = this.map.getLayer(layerId);
if (layer.declaredClass === 'esri.layers.ArcGISDynamicMapServiceLayer') {
this.layers.push({
ref: layer,
identifyTask: new IdentifyTask(layer.url)
});
}
}, this);
this.map.on('click', lang.hitch(this, function (evt) {
if (this.mapClickMode.current === 'identify'/* && !evt.graphic*/) {
this.executeIdentifyTask(evt);
}
}));
this.createIdentifyLayerList();
this.map.on('zoom-end', lang.hitch(this, function (evt) {
this.createIdentifyLayerList();
}));
},
createIdentifyLayerList: function () {
var identifyItems = [];
array.forEach(this.layers, lang.hitch(this, function (layer) {
array.forEach(layer.ref.layerInfos, lang.hitch(this, function (layerInfo) {
if (array.indexOf(layer.ref.visibleLayers, layerInfo.id) !== -1 && this._layerVisibleAtCurrentScale(layerInfo)) {
identifyItems.push({
name: layerInfo.name,
id: layerInfo.name
});
}
}));
}));
identifyItems.sort(function (a, b) {
return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0);
});
identifyItems.unshift({ name: "", id: "" });
var identify = new Memory({
data: identifyItems
});
this.identifyLayerDijit.set('store', identify);
this.identifyLayerDijit.set('value', identifyItems[0].name);
},
_layerVisibleAtCurrentScale: function (layer) {
var mapScale = this.map.getScale();
return !(((layer.maxScale != 0 && mapScale < layer.maxScale) || (layer.minScale != 0 && mapScale > layer.minScale)));
},
executeIdentifyTask: function (evt) {
this.map.infoWindow.hide();
this.map.infoWindow.clearFeatures();
this.map.infoWindow.setTitle('Identifing...');
this.map.infoWindow.setContent('<img src="images/loading.gif" style="height:20px;width:20px;margin-top:5px"></img>');
this.map.infoWindow.show(evt.mapPoint);
var identifyParams = new IdentifyParameters();
identifyParams.tolerance = this.identifyTolerance;
identifyParams.returnGeometry = true;
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_VISIBLE;
identifyParams.geometry = evt.mapPoint;
identifyParams.mapExtent = this.map.extent;
identifyParams.width = this.map.width;
identifyParams.height = this.map.height;
var identifies = [];
var identifiedlayers = [];
var form = this.identifyFormDijit.get('value');
if (form.identifyLayer.length > 0) {
array.forEach(this.layers, function (layer) {
var params = lang.clone(identifyParams);
array.forEach(layer.ref.layerInfos, function (layerInfo) {
if (layerInfo.name === form.identifyLayer) {
params.layerIds = [];
params.layerIds.push(layerInfo.id);
identifies.push(layer.identifyTask.execute(params));
identifiedlayers.push(layer);
}
});
});
} else {
array.forEach(this.layers, function (layer) {
if (layer.ref.visible && layer.ref.visibleLayers.length !== 0 && layer.ref.visibleLayers[0] !== -1) {
var params = lang.clone(identifyParams);
var nonGroupLayers = array.filter(layer.ref.layerInfos, function (x) {
return x.subLayerIds === null;
});
params.layerIds = [];
array.forEach(nonGroupLayers, function (subLayer) {
if (array.indexOf(layer.ref.visibleLayers, subLayer.id) !== -1) {
params.layerIds.push(subLayer.id);
}
});
identifies.push(layer.identifyTask.execute(params));
identifiedlayers.push(layer);
}
});
}
all(identifies).then(lang.hitch(this, 'identifyCallback', identifiedlayers), function (err) {
console.log('identify tasks error: ', err);
});
},
identifyCallback: function (identifiedlayers, responseArray) {
var fSet = [];
array.forEach(responseArray, function (response, i) {
var layerId = identifiedlayers[i].ref.id;
array.forEach(response, function (result) {
result.feature.geometry.spatialReference = this.map.spatialReference;
// see if we have a Popup config defined for this layer
if (this.identifies.hasOwnProperty(layerId)) {
if (this.identifies[layerId].hasOwnProperty(result.layerId)) {
result.feature.setInfoTemplate(new PopupTemplate(this.identifies[layerId][result.layerId]));
}
}
// if no Popup defined output all attributes
if (result.feature.infoTemplate === undefined) {
var templateString = '';
for (var prop in result.feature.attributes) {
templateString += '<b>' + prop + '</b>: ';
templateString += result.feature.attributes[prop];
templateString += '<br/>';
}
result.feature.setInfoTemplate(new PopupTemplate({
title: result.layerName,
description: templateString
}));
}
fSet.push(result.feature);
}, this);
}, this);
}
});
return Identify;
});
The code above is a fair bit different than what I originally wrote so hopefully it still works - at the very least, it should give a start if anyone in the future asks for something similar.
The code also includes a change I made to bold all property names in the identify results - maybe someone else will find that useful too.
Using the starting point provided by @msereda, this feature is now available in CMV. I added a few refinements and refactored a few things (PR #146) but the core came from @mserda. thank you!
Additional support for feature layers and attachments has been committed to this new branch: feature/add-feature-layers-to-identify-widget
This is probably a good issue for the 'Request for help' category. Anyway:
I have a requirement for users to be able to select a single layer, then when clicking the map to identify, having the identify tool only identify on that layer. They should also be able to unselect the layer and have the identify go back to identifying everything visible.
Anyone ever had to do this before? I'm not eager to crack open the ToC.js file, so I've been thinking about adding an 'Identify' Titlepane object with a grid list of the layers, then allowing the user to select a single layer from the grid and the identify look for a selected grid item. If anyone has any better ideas though, I'd love to hear them!