'use strict';
// TODO hilight layer would be a good candidate for a custom class which internally proxies to ESRI's GraphicsLayer.
const defaultSymbols = require('./defaultHilightSymbols.json');
// contains functions to support the hilight layer.
function cloneBuilder(esriBundle) {
/**
* Clone a graphic from a map-bound layer.
* @method cloneLayerGraphic
* @param {Graphic} graphic an ESRI graphic that resides in a map layer.
* @return {Object} an unbound copy of the graphic
*/
return graphic => {
const clone = new esriBundle.Graphic({
geometry: graphic.geometry
});
clone.symbol = graphic.getLayer().renderer.getSymbol(graphic);
return clone;
};
}
function graphicBuilder(esriBundle) {
/**
* Generating a graphic from server geometry.
* @method geomToGraphic
* @param {Object} geometry feature geometry conforming to ESRI Geometry standard
* @param {Object} symbol esri symbol in server format
* @return {Object} an ESRI GraphicsLayer
*/
return (geometry, symbol) => {
const graphic = new esriBundle.Graphic({
geometry
});
graphic.symbol = esriBundle.symbolJsonUtils.fromJson(symbol);
return graphic;
};
}
function getGraphicsBuilder(esriBundle, geoApi) {
// TODO once document sites are up and running, figure out a way to hyperlink the graphicBundles parameter to the class documentation page in the viewer site
/**
* Generating a graphic from server geometry.
* @method getUnboundGraphics
* @param {Array} graphicBundles set of graphic bundles with properties .graphic, .source, .layerFC
* @param {Object} spatialReference the projection the unbound graphics should be in
* @return {Array} a set of promises that resolve with an unbound graphic, one for each graphic bundle provided
*/
return (graphicBundles, spatialReference) => {
// generate detached graphics to give to the hilight layer.
// promises because server layers renderer is inside a promise
return graphicBundles.map(bundle => {
if (bundle.source === 'server') {
let geom = bundle.graphic.geometry;
// check projection
if (!geoApi.proj.isSpatialRefEqual(geom.spatialReference, spatialReference)) {
geom = geoApi.proj.localProjectGeometry(spatialReference, geom);
}
// determine symbol for this server graphic
return bundle.layerFC.getLayerData().then(layerData => {
const symb = geoApi.symbology.getGraphicSymbol(bundle.graphic.attributes, layerData.renderer);
return geoApi.hilight.geomToGraphic(geom, symb);
});
} else {
// local graphic. clone and hilight
return Promise.resolve(geoApi.hilight.cloneLayerGraphic(bundle.graphic));
}
});
};
}
function hilightBuilder(esriBundle) {
/**
* Generate a graphic layer to handle feature hilighting.
* @method makeHilightLayer
* @param {Object} options optional settings for the hilight layer
* layerId - id to use for the hilight layer. defaults to rv_hilight
* markerSymbol - esri symbol in server json format to symbolize the click marker. defaults to a red pin
* @return {Object} an ESRI GraphicsLayer
*/
return options => {
// set options
let id = 'rv_hilight';
let markerSymbol = defaultSymbols.markerSymbol;
if (options) {
if (options.layerId) {
id = options.layerId;
}
if (options.markerSymbol) {
markerSymbol = options.markerSymbol;
}
}
const hgl = new esriBundle.GraphicsLayer({ id, visible: true });
/**
* Add a graphic to indicate where user clicked.
* @method addPin
* @param {Point} point an ESRI point object to use as the graphic location
* @param {Boolean} clearLayer indicates any previous graphics in the hilight layer should be removed. defaults to false
*/
hgl.addMarker = (point, clearLayer = false) => {
if (clearLayer) {
hgl.clear();
}
const marker = new esriBundle.Graphic({ symbol: markerSymbol });
marker.setGeometry(point);
hgl.add(marker);
};
/**
* Add a graphic or array of graphics to the highlight layer. Remove any previous graphics.
* @method addHilight
* @param {Graphic|Array} graphic an ESRI graphic, or array of ESRI graphics. Should be in map spatialReference, and not bound to a layer
* @param {Boolean} clearLayer indicates any previous graphics in the hilight layer should be removed. defaults to false
*/
hgl.addHilight = (graphic, clearLayer = false) => {
if (clearLayer) {
hgl.clear();
}
const graphics = Array.isArray(graphic) ? graphic : [graphic];
// add new hilight graphics
graphics.forEach(g => hgl.add(g));
};
/**
* Remove hilight from map
* @method clearHilight
*/
hgl.clearHilight = () => {
hgl.clear();
};
return hgl;
};
}
module.exports = (esriBundle, geoApi) => ({
makeHilightLayer: hilightBuilder(esriBundle),
geomToGraphic: graphicBuilder(esriBundle),
cloneLayerGraphic: cloneBuilder(esriBundle),
getUnboundGraphics: getGraphicsBuilder(esriBundle, geoApi)
});