rlayers
Version:
React Components for OpenLayers
154 lines • 6.56 kB
JavaScript
import React from 'react';
import { createRoot } from 'react-dom/client';
import { LRUCache } from 'lru-cache';
import Style from 'ol/style/Style';
import { RContext } from '../context';
import debug from '../debug';
import { flushSync } from 'react-dom';
export const useRStyle = () => React.useRef(undefined);
export const createRStyle = () => React.createRef();
/**
* A style, all other style components must be descendants of `RStyle`
*
* It can be used with a React reference - `RStyleRef` which is a shortcut for
* `React.RefObject<RStyle>` and a subtype of `RStyleLike`
*
* Or it can also be nested inside a vector layer to be
* automatically assigned as the default style of that layer
*
* This is the only component that does not have to be part of an `RMap`
*
* It provides the special `RStyle` context
*/
class RStyle extends React.PureComponent {
constructor(props) {
super(props);
this.style = (f, r) => {
if (this.ol !== this.style)
return this.ol;
let hash;
if (this.cache) {
hash = this.props.cacheId(f, r);
const style = this.cache.get(hash);
if (style)
return style;
}
const style = new Style({ zIndex: this.props.zIndex });
const reactElement = (React.createElement(RContext.Provider, { value: Object.assign(Object.assign({}, this.context), { style }) }, this.props.render(f, r)));
const root = createRoot(document.createElement('div'));
// React 18 renders asynchronously while OpenLayers does not
// support an asynchronous StyleFunction
flushSync(() => {
root.render(reactElement);
});
if (this.cache)
this.cache.set(hash, style);
return style;
};
if (props.render)
this.ol = this.style;
else
this.ol = new Style({ zIndex: props.zIndex });
if (props.render && props.cacheSize && props.cacheId)
this.cache = new LRUCache({ max: props.cacheSize });
}
componentDidMount() {
this.refresh();
}
componentDidUpdate(prevProps, prev, snap) {
if (this.props !== prevProps) {
debug('willRefresh', this, prevProps, this.props);
this.refresh(prevProps);
}
}
refresh(prevProps) {
var _a, _b, _c, _d, _e, _f, _g;
if (!prevProps || (prevProps === null || prevProps === void 0 ? void 0 : prevProps.render) !== this.props.render) {
if ((_a = this.context) === null || _a === void 0 ? void 0 : _a.styleArray) {
if (this.ol === this.style)
throw new Error('An RStyleArray must contain only static RStyles');
if (!this.context.styleArray.includes(this.ol))
this.context.styleArray.push(this.ol);
}
else if ((_c = (_b = this.context) === null || _b === void 0 ? void 0 : _b.feature) === null || _c === void 0 ? void 0 : _c.setStyle) {
this.context.feature.setStyle(this.ol);
}
else if ((_e = (_d = this.context) === null || _d === void 0 ? void 0 : _d.vectorlayer) === null || _e === void 0 ? void 0 : _e.setStyle) {
this.context.vectorlayer.setStyle(this.ol);
}
else if ((_g = (_f = this.context) === null || _f === void 0 ? void 0 : _f.vectortilelayer) === null || _g === void 0 ? void 0 : _g.setStyle) {
this.context.vectortilelayer.setStyle(this.ol);
}
if (this.cache)
this.cache.clear();
}
if (this.ol instanceof Style && (!prevProps || prevProps.zIndex !== this.props.zIndex))
this.ol.setZIndex(this.props.zIndex);
}
render() {
if (this.props.render)
return null;
return (React.createElement("div", { className: '_rlayers_RStyle' },
React.createElement(RContext.Provider, { value: Object.assign(Object.assign({}, this.context), { style: this.ol }) }, this.props.children)));
}
/** This is a static function that will return an
* OpenLayers-compatible `StyleLike` from an `RStyleLike`.
*
* @param {RStyleLike} style
* @public
*/
static getStyle(style) {
// style is undefined or null
if (style === null || style === undefined)
return style;
// style is RStyle or RStyleArray
if (typeof style.style === 'function')
return (f, r) => style.style(f, r);
// style is a React.RefObject
// React.RefObjects are just plain JS objects after JS transpilation */
if (Object.keys(style).includes('current'))
return (f, r) => style.current.style(f, r);
// style is an OpenLayers StyleLike
return style;
}
/** This is a static function that will return an
* OpenLayers-compatible `Style` from a static `RStyleLike`.
* This discards the reference and the returned style won't
* be updated if the referenced `<RStyle>` is updated.
*
* It throws if the reference is a dynamic style.
*
* @param {RStyleLike} style
* @public
*/
static getStyleStatic(style) {
// style is undefined or null
if (style === null || style === undefined)
return style;
let asRStyle;
// style is RStyle or RStyleArray
if (typeof style.style === 'function')
asRStyle = style;
// style is a React.RefObject
// React.RefObjects are just plain JS objects after JS transpilation
if (Object.keys(style).includes('current')) {
asRStyle = style.current;
if (asRStyle === undefined || asRStyle === null)
return undefined;
}
if (asRStyle) {
// style is a static RStyle or RStyleArray or reference
if (asRStyle.ol !== undefined && typeof asRStyle.ol !== 'function')
return asRStyle.ol;
// style is a dynamic RStyle or RStyleArray or reference
throw new TypeError('RStyle is dynamic and cannot be converted to Style');
}
// style is an OpenLayers StyleLike
if (typeof style === 'function')
throw new TypeError('StyleLike is dynamic and cannot be converted to Style');
return style;
}
}
RStyle.contextType = RContext;
export default RStyle;
//# sourceMappingURL=RStyle.js.map