/** * @module nyc/ol/MapLocator */ import OlFormatGeoJson from 'ol/format/GeoJSON' import OlStyleStyle from 'ol/style/Style' import OlStyleIcon from 'ol/style/Icon' import OlSourceVector from 'ol/source/Vector' import OlLayerVector from 'ol/layer/Vector' import OlFeature from 'ol/Feature' import OlGeomPoint from 'ol/geom/Point' import NycMapLocator from 'nyc/MapLocator' import FeatureTip from 'nyc/ol/FeatureTip' /** * @desc A class for managing map location * @public * @class * @extends module:nyc/MapLocator~MapLocator */ class MapLocator extends NycMapLocator { /** * @desc Create an instance of MapLocator * @public * @constructor * @param {module:nyc/ol/MapLocator~MapLocator.Options} options Constructor options */ constructor(options) { super() /** * @desc The layer on which to render locations * @public * @member {ol.layer.Vector} */ this.layer = null /** * @private * @member {ol.source.Vector} */ this.source = null /** * @private * @member {ol.Map} */ this.map = options.map /** * @private * @member {ol.View} */ this.view = this.map.getView() /** * @private * @member {number} */ this.zoom = options.zoom !== undefined ? options.zoom : NycMapLocator.ZOOM_LEVEL /** * @private * @member {ol.format.GeoJSON} */ this.format = new OlFormatGeoJson() /** * @private * @member {module:nyc/ol/FeatureTip~FeatureTip} */ this.tip = null this.createLayer(options.style) } /** * @desc Zoom to the provided location then optionally invoke a callback function * @public * @override * @method * @param {module:nyc/Locator~Locator.Result} data The location to which the map will be oriented * @param {module:nyc/MapLocator~MapLocator#zoomLocationCallback=} callback The function to call after the locator has zoomed to the location */ zoomLocation(data, callback) { const map = this.map const view = this.view const source = this.source const feature = this.feature(data) const geom = feature.getGeometry() source.clear() source.addFeature(feature) if (callback) { map.once('moveend', callback) } if (geom.getType() === 'Point') { view.animate({center: data.coordinate, zoom: this.zoom}) } else { view.fit(geom.getExtent(), {size: map.getSize(), duration: 500}) } } /** * @desc Set the location to the provided location without moving the map * @public * @override * @method * @param {module:nyc/Locator~Locator.Result} data The location to which the map will be oriented */ setLocation(data) { this.source.clear() this.source.addFeature(this.feature(data)) } /** * @desc Get the projection of the map * @public * @override * @method * @returns {string} The map projection */ getProjection() { return this.view.getProjection().getCode() } /** * @private * @method * @param {module:nyc/Locator~Locator.Result} location Location * @return {ol.Feature} The OpenLayers feature */ feature(location) { const geoJson = location.geometry const feature = new OlFeature({name: location.name, isFeature: location.isFeature}) if (geoJson) { feature.setGeometry(this.format.readGeometry(geoJson)) } else { feature.setGeometry(new OlGeomPoint(location.coordinate)) } return feature } /** * @private * @method * @param {ol.style.Style|Array<ol.style.Style>|ol.StyleFunction=} style Style */ createLayer(style) { this.source = new OlSourceVector() this.layer = new OlLayerVector({ source: this.source, style: style || MapLocator.LOCATION_STYLE, zIndex: 10000 }) this.map.addLayer(this.layer) this.tip = new FeatureTip({ map: this.map, tips: [{ layer: this.layer, label: feature => { return {css: 'nyc-user-location', html: feature.get('name')} } }] }) } } /** * @desc Object type to hold constructor options for {@link module:nyc/ol/MapLocator~MapLocator} * @public * @typedef {Object} * @property {ol.Map} map The map on which location will be managed * @property {ol.style.Style=} style The style for the layer on which user-specified locations will be displayed * @property {number} [zoom={@link NycMapLocator.ZOOM_LEVEL}] The zoom level used when locating coordinate */ MapLocator.Options /** * @desc The marker icon style for user location * @public * @const {ol.style.Style} */ MapLocator.LOCATION_STYLE = new OlStyleStyle({ image: new OlStyleIcon({ scale: 48 / 512, imgSize: [1024, 1024], src: 'data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%221024%22%20height%3D%221024%22%3E%3Cfilter%20id%3D%22filter%22%20style%3D%22color-interpolation-filters%3AsRGB%22%20x%3D%22-0.035750399%22%20width%3D%221.0715008%22%20y%3D%22-0.03625311%22%20%20height%3D%221.0725062%22%3E%3CfeGaussianBlur%20stdDeviation%3D%226.0015266%22%2F%3E%3C%2Ffilter%3E%3Cpath%20style%3D%22opacity%3A0.1%3Bfill%3A%23000000%3Bfill-opacity%3A1%3Bstroke%3A%23000000%3Bstroke-width%3A10%3Bstroke-opacity%3A1%3Bfilter%3Aurl(%23filter)%22%20d%3D%22M%20868.91078%2C141.10492%20C%20806.53392%2C79.855774%20695.84806%2C89.539532%20621.70905%2C162.73227%20547.57005%2C235.92501%20492.08486%2C476.05139%20510.9101%2C494.53629%20529.73535%2C513.02119%20773.473%2C457.74384%20847.612%2C384.5511%20921.751%2C311.35836%20931.28764%2C202.35407%20868.91078%2C141.10492%20Z%20M%20645.16036%2C361.99953%20c%20-41.52967%2C-40.77885%20-35.13918%2C-113.58881%2014.19918%2C-162.29746%2049.33837%2C-48.70864%20123.27149%2C-55.19708%20164.80115%2C-14.41823%2041.52967%2C40.77885%2035.13918%2C113.58881%20-14.19918%2C162.29745%20-49.33837%2C48.70864%20-123.27149%2C55.19709%20-164.80115%2C14.41824%20z%22%2F%3E%3Cpath%20style%3D%22fill%3A%23000%3Bstroke%3A%23fff%3Bstroke-width%3A20%22%20d%3D%22m%20512%2C25.6%20c%20-95.4279%2C0%20-172.8%2C77.3721%20-172.8%2C172.8%200%2C95.4279%20144%2C288%20172.8%2C288%2028.8%2C0%20172.8%2C-192.5721%20172.8%2C-288%20C%20684.8%2C102.9721%20607.4279%2C25.6%20512%2C25.6%20Z%20m%200%2C288%20c%20-63.5346%2C0%20-115.2%2C-51.6942%20-115.2%2C-115.2%200%2C-63.5058%2051.6654%2C-115.2%20115.2%2C-115.2%2063.5346%2C0%20115.2%2C51.6942%20115.2%2C115.2%200%2C63.5058%20-51.6654%2C115.2%20-115.2%2C115.2%20z%22%2F%3E%3C%2Fsvg%3E' }) }) export default MapLocator