rlayers
Version:
React Components for OpenLayers
180 lines • 8.38 kB
JavaScript
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