UNPKG

rlayers

Version:

React Components for OpenLayers

180 lines 8.38 kB
import React from 'react'; import { MapBrowserEvent } from 'ol'; import { Feature } from 'ol'; import BaseEvent from 'ol/events/Event'; import { getCenter } from 'ol/extent'; import { RContext } from './context'; import { RlayersBase, handlersSymbol } from './REvent'; import { featureHandlersSymbol } from './layer/RLayerBaseVector'; import RStyle from './style/RStyle'; import debug from './debug'; export class RFeatureUIEvent extends MapBrowserEvent { } export class RFeatureBaseEvent extends BaseEvent { } /** * Component for a single vector feature * * Vector features can be either * * * implicit, when loaded from a file as props of a `RLayerVector` * * explicit, when declared as JSX with this component * * Requires a vector layer context * * Provides a location context * * [Example for explicit RFeatures](https://mmomtchev.github.io/rlayers/#/overlays) * * [Example for implicit RFeatures](https://mmomtchev.github.io/rlayers/#/RFeatures) * */ export default class RFeature extends RlayersBase { constructor(props, context) { var _a, _b; super(props, context); if (!((_a = this === null || this === void 0 ? void 0 : this.context) === null || _a === void 0 ? void 0 : _a.vectorlayer)) throw new Error('An RFeature must be part of a vector layer'); if (props.feature) this.ol = props.feature; else this.ol = new Feature(Object.assign(Object.assign({}, ((_b = props.properties) !== null && _b !== void 0 ? _b : {})), { geometry: props.geometry, style: RStyle.getStyle(props.style) })); RFeature.initEventRelay(this.context.map); this.onchange = () => this.forceUpdate(); } static initEventRelay(map) { // These are reinstalled at every new feature // but since eventRelay is static this doesn't grow the listeners array for (const ev of RFeature.pointerEvents) map.on(ev, RFeature.eventRelay); } incrementHandlers(ev) { var _a; const featureHandlers = RlayersBase.getOLObject(featureHandlersSymbol, this.context.vectorlayer); featureHandlers[ev] = ((_a = featureHandlers[ev]) !== null && _a !== void 0 ? _a : 0) + 1; } decrementHandlers(ev) { const featureHandlers = RlayersBase.getOLObject(featureHandlersSymbol, this.context.vectorlayer); featureHandlers[ev]--; } static dispatchEvent(fr, event) { var _a; if (!fr.feature) return true; if (fr.feature.dispatchEvent) { const stop = fr.feature.dispatchEvent(event); if (stop) return stop; } if (!event.target) event.target = fr.feature; const layerHandler = (_a = fr.layer) === null || _a === void 0 ? void 0 : _a.get(handlersSymbol)[event.type]; if (layerHandler) { return layerHandler.call(null, event); } return true; } static eventRelay(e) { const triggered = []; e.map.forEachFeatureAtPixel(e.pixel, (f, l) => triggered.push({ feature: f, layer: l }) && false, { hitTolerance: RFeature.hitTolerance, layerFilter: (layer) => { var _a, _b, _c, _d, _e; const handlers = RlayersBase.getOLObject(featureHandlersSymbol, layer); switch (e.type) { case 'click': return handlers['click'] > 0; case 'dblclick': return handlers['dblclick'] > 0; case 'singleclick': return handlers['singleclick'] > 0; case 'pointermove': return (((_a = handlers['pointermove']) !== null && _a !== void 0 ? _a : 0) + ((_b = handlers['pointerenter']) !== null && _b !== void 0 ? _b : 0) + ((_c = handlers['pointerleave']) !== null && _c !== void 0 ? _c : 0) > 0); case 'pointerdrag': return (((_d = handlers['pointerdrag']) !== null && _d !== void 0 ? _d : 0) + ((_e = handlers['pointerdragend']) !== null && _e !== void 0 ? _e : 0) > 0); } return Object.keys(handlers).reduce((a, x) => a + handlers[x], 0) > 0; } }); if (e.dragging) { if (!RFeature.lastFeaturesDragged.length) RFeature.lastFeaturesDragged = [...triggered]; for (const fr of RFeature.lastFeaturesDragged) if (!triggered.find((f) => f.feature === fr.feature)) triggered.push(fr); } else { for (const fr of RFeature.lastFeaturesDragged) RFeature.dispatchEvent(fr, new RFeatureUIEvent('pointerdragend', e.map, e.originalEvent)); RFeature.lastFeaturesDragged = []; } if (e.type === 'pointermove') { // For all features previously entered, check if the pointer is still over them // Send pointerleave and then remove those that are not under the pointer anymore for (const fr of RFeature.lastFeaturesEntered) if (!triggered.find((f) => f.feature === fr.feature)) { RFeature.dispatchEvent(fr, new RFeatureUIEvent('pointerleave', e.map, e.originalEvent)); fr.feature = null; fr.layer = null; } RFeature.lastFeaturesEntered = RFeature.lastFeaturesEntered.filter((fr) => fr.feature); // For all features triggered on this cycle, check if they were previous entered // Send pointerenter and then register all the new feature for (const fr of triggered) { if (!RFeature.lastFeaturesEntered.find((f) => f.feature === fr.feature)) { RFeature.dispatchEvent(fr, new RFeatureUIEvent('pointerenter', e.map, e.originalEvent)); RFeature.lastFeaturesEntered.push(fr); } } } // Normal re-dispatch for everything else // Stop on false for (const fr of triggered) if (RFeature.dispatchEvent(fr, new RFeatureUIEvent(e.type, e.map, e.originalEvent)) === false) return false; return true; } refresh(prevProps) { super.refresh(prevProps); if (this.props.feature !== undefined && this.props.feature !== this.ol) { debug('replacing bound feature', this.ol); this.componentWillUnmount(); this.ol = this.props.feature; this.componentDidMount(); } if (this.props.properties !== (prevProps === null || prevProps === void 0 ? void 0 : prevProps.properties)) this.ol.setProperties(this.props.properties); if (this.props.geometry !== (prevProps === null || prevProps === void 0 ? void 0 : prevProps.geometry)) this.ol.setGeometry(this.props.geometry); if (this.props.style !== (prevProps === null || prevProps === void 0 ? void 0 : prevProps.style)) this.ol.setStyle(RStyle.getStyle(this.props.style)); } componentDidMount() { debug('didMount', this.ol); super.componentDidMount(); this.ol.on('change', this.onchange); this.context.vectorsource.addFeature(this.ol); } componentWillUnmount() { super.componentWillUnmount(); this.ol.un('change', this.onchange); this.context.vectorsource.removeFeature(this.ol); } render() { var _a, _b; const extent = (_b = (_a = this.ol) === null || _a === void 0 ? void 0 : _a.getGeometry()) === null || _b === void 0 ? void 0 : _b.getExtent(); const center = extent && getCenter(extent); return (React.createElement("div", { className: '_rlayers_RFeature' }, React.createElement(RContext.Provider, { value: Object.assign(Object.assign({}, this.context), { feature: this.ol, rFeature: this, location: center }) }, this.props.children))); } } RFeature.pointerEvents = ['click', 'pointerdrag', 'pointermove', 'singleclick', 'dblclick']; RFeature.lastFeaturesEntered = []; RFeature.lastFeaturesDragged = []; RFeature.hitTolerance = 3; //# sourceMappingURL=RFeature.js.map