..\..\..\..\src\Hud.Affht\Hud.Affht.Web\app\Tools\AffhtMap.js File
define([
'dojo/Deferred',
'dojo/dom-style',
'esri/tasks/query',
'esri/tasks/QueryTask',
'esri/graphic',
'esri/layers/GraphicsLayer',
'esri/symbols/SimpleFillSymbol',
'esri/symbols/SimpleLineSymbol',
'esri/Color',
'esri/renderers/DotDensityRenderer',
'esri/layers/FeatureLayer',
'Hud.Common/Viewport/EsriMapController',
'Hud.Common/MapLegend/MapLegendController'
],
function (
Deferred,
domStyle,
Query,
QueryTask,
Graphic,
GraphicsLayer,
SimpleFillSymbol,
SimpleLineSymbol,
Color,
DotDensityRenderer,
FeatureLayer,
EsriMap,
MapLegend) {
var thisMap = null, //live map
legend = null,
config = null,
graphicsLayer = new GraphicsLayer({ id: 'affht-graphics-layer' }),
selectedAffhtMap = null,
selectedJurisdiction = null,
selectedRegion = null;
return {
/**
* Sets the module config to the input.
* @method setConfig
*/
setConfig: function (inputConfig) {
config = inputConfig;
},
/**
* Loads an Esri JS API map from a JSON definiton object. Returns a deferred that resolves when the map is loaded.
* @method loadMap
*
* @param {String} dotValue
* @param {Array} fields
*
* @return {Deferred} def
*/
loadMap: function (mapDefinition, mapElementId) {
var def = new Deferred();
//build options for custom map class
var options = {
config: mapDefinition,
mapElementId: mapElementId
};
//instantiate custom map class and create a map
var eMap = new EsriMap(options);
var d = eMap.initializeMap();
d.then(function (map) {
//set local reference
thisMap = map;
//add the graphics layer
map.addLayer(graphicsLayer);
//resolve the deferred returned by loadMap()
def.resolve(map);
});
//TODO: Handle deferred error (failed map load)
//return deferred - resolved on map load
return def;
},
/**
* Returns the object that represents the currently selected AFFHT map.
* @method getSelectedAffhtMap
* @return {Object}
*/
getSelectedAffhtMap: function () {
return selectedAffhtMap;
},
/**
* Sets the local property to an object that represents the currently selected AFFHT map.
* @method getSelectedAffhtMap
* @return {Object}
*/
setSelectedAffhtMap: function (affthMap) {
selectedAffhtMap = affthMap;
},
/**
* Returns the graphics layer used by the custom affht components.
* @method getGraphicsLayer
* @return {GraphicsLayer}
*/
getGraphicsLayer: function () {
return graphicsLayer;
},
/**
* Returns an Esri JS API feature object representing the selected AFFHT grantee.
* @method getSelectedJurisdiction
* @return {Object}
*/
getSelectedJurisdiction: function () {
return selectedJurisdiction;
},
/**
* Sets the local property to an Esri JS API feature object representing the selected AFFHT grantee.
* @method setSelectedJurisdiction
*/
setSelectedJurisdiction: function (feature) {
selectedJurisdiction = feature;
},
/**
* Returns an Esri JS API feature object representing the selected AFFHT CBSA.
* @method getSelectedRegion
* @return {Object}
*/
getSelectedRegion: function () {
return selectedRegion;
},
/**
* Sets the local property to an Esri JS API feature object representing the selected AFFHT CBSA.
* @method setSelectedRegion
*/
setSelectedRegion: function (feature) {
selectedRegion = feature;
},
/**
* Queries the ArcGIS Server rest endpoint for a list of AFFHT grantees within the specified state.
* @method queryJurisdictionsByState
*
* @param {String} stateAbbr
*
* @return {Deferred} d
*/
queryJurisdictionsByState: function (stateAbbr) {
var d = new Deferred();
//query task
var qt = new QueryTask(config.url + "/" + config.jurisdictionLayerId);
//query parameters
var qp = new Query();
qp.returnGeometry = false;
qp.where = "STUSAB = '" + stateAbbr + "'";
qp.outFields = config.outFields;
qp.orderByFields = ["NAME"];
//async query
var q = qt.execute(qp);
q.then(function (results) {
d.resolve(results);
});
return d;
},
/**
* Queries the ArcGIS Server rest endpoint for a grantee feature with the matching ID.
* @method queryJurisdictionById
*
* @param {String} jurisdictionId
*
* @return {Deferred} d
*/
queryJurisdictionById: function (jurisdictionId, uogid) {
var d = new Deferred();
var queryField = (uogid ? "UOGID" : "OBJECTID");
//query object
var qt = new QueryTask(config.url + "/" + config.jurisdictionLayerId);
//query parameters
var qp = new Query();
qp.returnGeometry = true;
qp.where = queryField + " = '" + jurisdictionId + "'";
qp.outFields = ["*"];
//async query
var q = qt.execute(qp);
q.then(function (results) {
d.resolve(results);
});
//TODO: handler error result
return d;
},
/**
* Queries the ArcGIS Server rest endpoint for a CBSA feature with the matching ID.
* @method queryRegionById
*
* @param {String} regionId
*
* @return {Deferred} d
*/
queryRegionById: function (regionID) {
var d = new Deferred();
//query object
var qt = new QueryTask(config.url + "/" + config.regionLayerId);
//query parameters
var qp = new Query();
qp.returnGeometry = true;
qp.where = "CBSAID = '" + regionID + "'";
qp.outFields = ["*"];
//async query
var q = qt.execute(qp);
q.then(function (results) {
d.resolve(results);
});
//TODO: handle error result
return d;
},
/**
* Zooms the live map to the extent of the currently selected AFFHT grantee.
* @method zoomToJurisdiction
*
* @return {Deferred}
*/
zoomToJurisdiction: function () {
var extent = selectedJurisdiction.geometry.getExtent().expand(1.5);
return thisMap.setExtent(extent);
},
/**
* Zooms the live map to the extent of the currently selected AFFHT CBSA.
* @method zoomToRegion
*
* @return {Deferred}
*/
zoomToRegion: function () {
var extent = null;
for (var i = 0, length = selectedRegion.length; i < length; i++) {
var feature = selectedRegion[i];
if (extent == null) { extent = feature.geometry.getExtent(); }
else { extent = extent.union(feature.geometry.getExtent()); }
}
return thisMap.setExtent(extent);
},
/**
* Draws the currently selected AFFHT grantee boundary on the live map.
* @method drawJurisdiction
*/
drawJurisdiction: function () {
//remove existing jurisdiction graphics if they exist
for (var i = 0, length = graphicsLayer.graphics.length; i < length; i++) {
var graphic = graphicsLayer.graphics[i];
try {
if (graphic.attributes.groupId && graphic.attributes.groupId == "cdbg") { graphicsLayer.remove(graphic); }
}
catch (e) { }
}
var sfs = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NULL,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
new Color("#660000"), 1.5), new Color([120, 120, 120, 0.9])
);
graphicsLayer.add(new Graphic(selectedJurisdiction.geometry, sfs, { groupId: "cdbg" }));
},
/**
* Draws the currently selected AFFHT CBSA boundary on the live map.
* @method drawRegion
*/
drawRegion: function () {
//remove existing region/cbsa graphics if they exist
for (var i = 0, length = graphicsLayer.graphics.length; i < length; i++) {
try {
var graphic = graphicsLayer.graphics[i];
if (graphic.attributes.groupId && graphic.attributes.groupId == "cbsa") { graphicsLayer.remove(graphic); }
}
catch (e) { }
}
//add new region/cbsa features
var extent = null;
for (var i = 0, length = selectedRegion.length; i < length; i++) {
var feature = selectedRegion[i];
var sfs = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NULL,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
new Color("#000000"), 1.5), new Color([120, 120, 120, 0.9])
);
graphicsLayer.add(new Graphic(feature.geometry, sfs, { groupId: "cbsa" }));
}
},
/**
* A utitility method to update all dot density layers in the map with the input dot density ratio value.
* @method updateDotDensity
* @param {String} dotDensity
*/
updateDotDensity: function (dotDensity) {
var layerIds = thisMap.layerIds;
for (var i = 0, length = layerIds.length; i < length; i++) {
var layer = thisMap.getLayer(layerIds[i]);
if (layer.id.indexOf("dot-density") > -1) {
var fields = layer.renderer.fields;
var dotSize = layer.renderer.dotSize;
var dotShape = layer.renderer.dotShape;
layer.setRenderer(this.createDotDensityRenderer(dotDensity, fields, dotSize, dotShape));
layer.redraw();
this.renderLegend();
}
}
},
/**
* A utility method that builds and returns an Esri JS API DotDensityRenderer object.
* @method createDotDensityRenderer
*
* @param {Number} dotValue
* @param {Array} fields
* @param {Number} dotSize
* @param {String} dotShape
* @param {string} valueUnit (optional)
*
* @return {DotDensityRenderer}
*/
createDotDensityRenderer: function (dotValue, fields, dotSize, dotShape, valueUnit) {
//validate the valueUnit param
if (!valueUnit || valueUnit === '') { valueUnit = 'People'; }
return new DotDensityRenderer({
fields: fields,
dotValue: dotValue,
dotSize: dotSize,
dotShape: dotShape,
legendOptions: {
valueUnit: valueUnit
}
});
},
/**
* Creates an AFFHT map legend and injects the HTML into the DOM. An AFFHT map legend has enhanced features to show custom dot density renderer fields based on configuration.
* @method renderLegend
* @return {Deferred} d
*/
renderLegend: function (aoi) {
var self = this;
var d = new Deferred();
var mapDefinition = JSON.parse(selectedAffhtMap.attributes.MAP_DEF);
//clear the legend
if (legend) {
try {
legend.destroy();
}
catch (e) { }
}
//hide legend while it is updated
domStyle.set("affht-sidebar-legend", "display", "none");
if (mapDefinition.options && mapDefinition.options.legendLabels && mapDefinition.options.legendLabels.length > 0) {
//query ArcGIS Server for the custom dot density legend labels
var len = mapDefinition.options.legendLabels.length;
for (var x = 0; x < len; x++) {
var layer = thisMap.getLayer(mapDefinition.options.legendLabels[x].id),
legendInfo = mapDefinition.options.legendLabels[x];
if (layer) {
//build query parameters
var labelQuery = new Query();
if (aoi == "jurisdiction") {
labelQuery.where = "CDBGUOGID = '" + selectedJurisdiction.attributes.UOGID + "'";
}
else {
labelQuery.where = "CBSAID = '" + selectedRegion[0].attributes.CBSAID + "'";
}
labelQuery.outFields = ["*"];
//execute query
var labelQT = new QueryTask(layer.url);
var ld = labelQT.execute(labelQuery);
ld.then(function (results) {
//create dummy layer for the legend layerinfos using query results
var feature = results.features[0];
//get the real dot density layer
var dotLayer;
for (var i = 0, length = thisMap.layerIds.length; i < length; i++) {
if (thisMap.layerIds[i].indexOf("dot-density") > -1) {
dotLayer = thisMap.getLayer(thisMap.layerIds[i]);
break;
}
}
//create dummy layer (never added to the map)
var fl = new FeatureLayer(dotLayer.url, { id: "legend-dummy" });
//build new fields object and set renderer
var fields = [];
for (var m = 0, _fl = dotLayer.renderer.fields.length; m < _fl; m++) {
for (var j = 0, l = legendInfo.labels.length; j < l; j++) {
if (dotLayer.renderer.fields[m].name == legendInfo.labels[j][0]) {
fields.push({ name: feature.attributes[legendInfo.labels[j][1]], color: dotLayer.renderer.fields[m].color });
break;
}
}
}
//dummy layer needs real dot density renderer
fl.setRenderer(self.createDotDensityRenderer(dotLayer.renderer.dotValue, fields, dotLayer.renderer.dotSize, dotLayer.renderer.dotShape));
fl.redraw();
//set the legend fields to a layer property to be used by the legend class
dotLayer._dotDensityTocFields = fields;
//render legend (legend will look for special property on the layer)
legend = new MapLegend({
layerOverride: { layer: fl, id: dotLayer.id },
config: {
containerId: "affht-sidebar-legend",
enableGui: false
},
map: thisMap
});
domStyle.set("affht-sidebar-legend", "display", "block");
//resolve deferred
d.resolve("Legend loaded");
});
}
}
}
else {
legend = new MapLegend({
config: {
containerId: "affht-sidebar-legend",
enableGui: false
},
map: thisMap
});
domStyle.set("affht-sidebar-legend", "display", "block");
//resolve deferred
d.resolve("Legend loaded");
}
return d;
},
};
});