widgets/IdentifyPanel.js
define([
'dojo/_base/declare',
'dijit/_WidgetBase',
'dijit/_TemplatedMixin',
'dijit/_WidgetsInTemplateMixin',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/on',
'dojo/aspect',
'dojo/topic',
'dojo/number',
'dojo/dom-style',
'dijit/registry',
'esri/graphic',
'esri/tasks/FeatureSet',
'esri/dijit/Popup',
'dijit/form/Button',
//template
'dojo/text!./IdentifyPanel/templates/IdentifyPanel.html',
//i18n
'dojo/i18n!./IdentifyPanel/nls/IdentifyPanel',
// css
'xstyle/css!./IdentifyPanel/css/IdentifyPanel.css',
'dijit/layout/ContentPane'
], function (
declare,
_WidgetBase,
_TemplatedMixin,
_WidgetsInTemplateMixin,
lang,
array,
on,
aspect,
topic,
num,
domStyle,
registry,
Graphic,
FeatureSet,
Popup,
Button,
template,
i18n
) {
return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
widgetsInTemplate: true,
templateString: template,
i18n: i18n,
baseClass: 'cmvIdentifyPanelWidget',
map: null,
buttons: [],
defaultButtons: [
{
id: 'identifypanel-button-zoom',
label: i18n.Buttons.zoomToFeature.label,
iconClass: 'fas fa-fw fa-search',
className: 'identifypanel-button-zoom',
showLabel: false,
onClick: 'zoomToFeature'
},
{
id: 'identifypanel-button-export',
label: i18n.Buttons.exportFeature.label,
iconClass: 'fas fa-fw fa-download',
className: 'identifypanel-button-export',
showLabel: false,
onClick: 'exportFeature'
}
],
includeDefaultButtons: true,
showNavigationButtons: true,
noInfoTimeout: 5000,
standaloneInfoWindow: false,
infoWindowOptions: {},
defaultInfoWindowOptions: {
highlight: true,
keepHighlightOnHide: true,
popupWindow: false,
hideDelay: 10,
visibleWhenEmpty: false,
anchor: 'right',
offsetX: -99999,
offsetY: -99999
},
exportOptions: {},
defaultExportOptions: {
excel: true,
csv: true,
xlsExcel: false,
geojson: true,
kml: true,
kmz: true,
shapefile: true,
topojson: true,
wkt: true,
defaultExportType: 'shapefile',
// this option can be a string or a function that returns
// a string.
//
// filename: 'my_results'
filename: function () {
var date = new Date();
return 'identified_feature_' + date.toLocaleDateString();
},
geojsonOptions: {
simplestyle: true // mapbox styles
},
kmlOptions: {
name: null,
description: null,
documentName: 'Identified Feature',
documentDescription: 'Identified Feature',
simplestyle: true, // mapbox styles converted to KML Styles
extendedData: true
},
shapefileOptions: {
folder: 'layers',
types: {
point: 'points',
polygon: 'polygons',
polyline: 'polylines'
}
}
},
featureCount: 0,
featureIndex: 0,
postCreate: function () {
this.inherited(arguments);
this.initParentWidget();
this.initInfoWindow();
this.initButtons();
this.exportOptions = this.mixinDeep(this.defaultExportOptions, this.exportOptions);
this.own(topic.subscribe('identify/execute', lang.hitch(this, 'onIdentifyExecute')));
this.own(topic.subscribe('identify/results', lang.hitch(this, 'onIdentifyResults')));
this.own(topic.subscribe('identify/error', lang.hitch(this, 'onIdentifyError')));
},
initParentWidget: function () {
if (typeof this.parentWidget === 'string') {
this.parentWidget = registry.byId(this.parentWidget);
}
if (this.parentWidget && this.parentWidget.toggleable) {
this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, 'toggleIdentifyPanel')));
}
},
initInfoWindow: function () {
this.defaultInfoWindowOptions.map = this.map;
var options = this.mixinDeep(this.defaultInfoWindowOptions, this.infoWindowOptions);
this.infoWindow = new Popup(options, document.createElement('div'));
if (options.highlight) {
this.infoWindow.enableHighlight(this.map);
}
// when the selection changes update the side panel to display the popup info for the
// currently selected feature.
this.infoWindow.on('selection-change', lang.hitch(this, 'onSelectionChanged'));
// When features are associated with the map's info window update the panel with the new content.
this.infoWindow.on('set-features', lang.hitch(this, 'onSetFeatures'));
if (this.standaloneInfoWindow) {
// make sure the map's info window is always out of the way.
this.map.infoWindow.set('highlight', false);
this.map.infoWindow.set('anchor', 'right');
this.map.infoWindow.set('offsetX', -99999);
this.map.infoWindow.set('offsetY', -99999);
} else {
this.map.setInfoWindow(this.infoWindow);
}
},
initButtons: function () {
var btns = this.buttons;
if (this.includeDefaultButtons) {
btns = this.defaultButtons.concat(btns);
}
this.buttons = [];
array.forEach(btns, lang.hitch(this, function (btn) {
this.buttons.push(this.addActionButton(btn));
}));
if (!this.showNavigationButtons) {
domStyle.set(this.navigationButtonsNode, 'display', 'none');
}
if (this.buttons.length <= 0 && !this.showNavigationButtons) {
domStyle.set(this.actionsPaneNode, 'display', 'none');
}
var btnActions = ['add', 'remove', 'show', 'hide', 'enable', 'disable', 'hideAll', 'showAll'];
array.forEach(btnActions, lang.hitch(this, function (action) {
this.own(topic.subscribe('identifyPanel/' + action + 'ActionButton', lang.hitch(this, action + 'ActionButton')));
}));
},
displayPopupContent: function (feature) {
if (!this.allowPopup) {
this.infoWindow.hide();
}
this.popupContentNode.set('content', null);
if (feature) {
var content = feature.getContent();
this.popupContentNode.set('content', content);
domStyle.set(this.instructionsNode, 'display', 'none');
domStyle.set(this.popupNode, 'display', 'block');
domStyle.set(this.loadingNode, 'display', 'none');
this.featureIndex = this.infoWindow.selectedIndex;
this.checkNavigationButtons();
this.setTitle();
if (this.parentWidget && this.parentWidget.set) {
this.parentWidget.set('open', true);
}
} else {
domStyle.set(this.instructionsNode, 'display', 'block');
domStyle.set(this.popupNode, 'display', 'none');
}
},
selectFirstFeature: function () {
this.selectFeature(0);
},
selectPreviousFeature: function () {
this.selectFeature(this.featureIndex - 1);
},
selectNextFeature: function () {
this.selectFeature(this.featureIndex + 1);
},
selectLastFeature: function () {
this.selectFeature(this.featureCount - 1);
},
selectFeature: function (idx) {
this.featureIndex = idx || 0;
if (this.featureIndex < 0) {
this.featureIndex = 0;
} else if (this.featureIndex >= this.featureCount) {
this.featureIndex = this.featureCount - 1;
}
if (this.featureCount < 1) {
domStyle.set(this.noInfoNode, 'display', 'block');
}
domStyle.set(this.loadingNode, 'display', 'none');
this.infoWindow.select(this.featureIndex);
this.infoWindow.showHighlight();
if (this.standaloneInfoWindow) {
this.map.infoWindow.hideHighlight();
}
this.checkNavigationButtons();
},
setFeatures: function (features) {
if (features && features.length) {
this.infoWindow.setFeatures(features);
} else {
this.infoWindow.clearFeatures();
}
topic.publish('identifyPanel/update', features);
},
clearFeatures: function () {
domStyle.set(this.instructionsNode, 'display', 'block');
domStyle.set(this.loadingNode, 'display', 'none');
domStyle.set(this.noInfoNode, 'display', 'none');
domStyle.set(this.titleNode, 'display', 'none');
domStyle.set(this.popupNode, 'display', 'none');
this.setFeatures(null);
this.popupContentNode.set('content', null);
},
toggleIdentifyPanel: function () {
if (this.parentWidget) {
if (this.parentWidget.get('open') && this.infoWindow.features && this.infoWindow.features.length > 0) {
this.infoWindow.showHighlight();
topic.publish('identifyPanel/show');
} else {
this.infoWindow.hideHighlight();
topic.publish('identifyPanel/hide');
}
}
},
onIdentifyExecute: function (args) {
this.clearFeatures();
window.clearTimeout(this.hideTimeout);
if (args.identifies && args.identifies.length > 0) {
domStyle.set(this.instructionsNode, 'display', 'none');
domStyle.set(this.loadingNode, 'display', 'block');
} else if (args.event && args.event.graphic) {
this.setFeatures([args.event.graphic]);
}
if (this.parentWidget && this.parentWidget.set) {
this.parentWidget.set('open', true);
}
},
onIdentifyResults: function (args) {
var features = args.features;
if (features && features.length > 0) {
this.setFeatures(features);
} else {
this.showNoResults();
}
},
onIdentifyError: function (/* args */) {
this.showNoResults();
},
onSelectionChanged: function () {
this.displayPopupContent(this.infoWindow.getSelectedFeature());
},
onSetFeatures: function () {
this.featureCount = this.infoWindow.features ? this.infoWindow.features.length : 0;
this.selectFeature(0);
},
showNoResults: function () {
this.clearFeatures();
domStyle.set(this.instructionsNode, 'display', 'none');
domStyle.set(this.loadingNode, 'display', 'none');
domStyle.set(this.noInfoNode, 'display', 'block');
window.clearTimeout(this.hideTimeout);
this.hideTimeout = window.setTimeout(lang.hitch(this, 'clearFeatures'), this.noInfoTimeout);
},
setTitle: function () {
var html = i18n.Labels.feature + ' ' + num.format(this.featureIndex + 1) + ' of ' + num.format(this.featureCount);
this.featureNode.innerHTML = html;
domStyle.set(this.titleNode, 'display', 'block');
},
checkNavigationButtons: function () {
this.btnFirstFeature.set('disabled', this.featureIndex === 0);
this.btnPreviousFeature.set('disabled', this.featureIndex === 0);
this.btnNextFeature.set('disabled', (this.featureIndex >= (this.featureCount - 1)));
this.btnLastFeature.set('disabled', (this.featureIndex >= (this.featureCount - 1)));
},
addActionButton: function (options) {
options.className = (options.className ? options.className : '') + ' identifypanel-button';
if (typeof options.onClick === 'string') {
options.onClick = lang.hitch(this, options.onClick);
}
var btn = new Button(options);
btn.placeAt(this.actionButtonsNode);
btn.startup();
return btn;
},
removeActionButton: function (btn) {
if (typeof btn === 'string') {
btn = registry.byId(btn);
}
if (btn && btn.destroy) {
btn.destroy();
}
},
showActionButton: function (btn) {
if (typeof btn === 'string') {
btn = registry.byId(btn);
}
if (btn && btn.domNode) {
domStyle.set(btn.domNode, 'display', 'inline-block');
}
},
hideActionButton: function (btn) {
if (typeof btn === 'string') {
btn = registry.byId(btn);
}
if (btn && btn.domNode) {
domStyle.set(btn.domNode, 'display', 'none');
}
},
enableActionButton: function (btn) {
if (typeof btn === 'string') {
btn = registry.byId(btn);
}
if (btn && btn.set) {
btn.set('disabled', false);
}
},
disableActionButton: function (btn) {
if (typeof btn === 'string') {
btn = registry.byId(btn);
}
if (btn && btn.set) {
btn.set('disabled', true);
}
},
showAllActionButton: function () {
array.forEach(this.buttons, function (btn) {
if (btn && btn.domNode) {
var isDefault = btn.get('defaultButton');
if (isDefault !== false) {
domStyle.set(btn.domNode, 'display', 'inline-block');
}
}
});
},
hideAllActionButton: function () {
array.forEach(this.buttons, function (btn) {
if (btn && btn.domNode) {
var isDefault = btn.get('defaultButton');
if (isDefault !== false) {
domStyle.set(btn.domNode, 'display', 'none');
}
}
});
},
zoomToFeature: function (evt) {
this.infoWindow._zoomToFeature(evt);
},
exportFeature: function () {
var feature = this.infoWindow.getSelectedFeature();
if (feature) {
var featureSet = new FeatureSet();
featureSet.features = [];
var geometry = lang.clone(feature.geometry);
var attributes = lang.clone(feature.attributes);
featureSet.features.push(new Graphic(geometry, null, attributes));
var exportOpts = this.exportOptions;
exportOpts.featureSet = featureSet;
exportOpts.show = true; // must be true
topic.publish('exportWidget/openDialog', exportOpts);
}
},
mixinDeep: function (dest, source) {
//Recursively mix the properties of two objects
var empty = {};
for (var name in source) {
if (!(name in dest) || (dest[name] !== source[name] && (!(name in empty) || empty[name] !== source[name]))) {
try {
if (source[name].constructor === Object) {
dest[name] = this.mixinDeep(dest[name], source[name]);
} else {
dest[name] = source[name];
}
} catch (e) {
// Property in destination object not set. Create it and set its value.
dest[name] = source[name];
}
}
}
return dest;
}
});
});