Code Monkey home page Code Monkey logo

rlayers's Introduction

rlayers - React Components for OpenLayers 6+

logo

License: ISC npm version Node.js CI codecov downloads

© OpenStreetMap contributors Kartendaten: © OpenStreetMap-Mitwirkende, SRTM | Kartendarstellung: © OpenTopoMap (CC-BY-SA)

rlayers is an opinionated set of React components for OpenLayers.

It's design policy is:

  • Fully Typescript-typed
  • Do everything that faces the user the React way and not the OpenLayers way - onClick and onPointerEnter/onPoinerLeave handlers are typical examples
  • If it does not face the user, it does not need to be React way - internally it uses inheritance, following the OpenLayers classes, over composition
  • Simple things should be simple to do, performance optimizations should not get in the way unless needed
  • If taking shortcuts when updating the components, always err on the safe side but do provide an override method that allows to come close to the raw OpenLayers performance
  • Expose all the advanced OpenLayers features
  • Try to be as much SSR-friendly as possible (this feature is currently in POC stage, see below)
  • The current target is OpenLayers 6+
  • Avoid dependencies when built except for React and OpenLayers (the examples have some dependencies) - currently the single one is lru-cache at 8Kbytes

Long term support of this project

The birth of this project is related to a huge extortion in the geography community linked to a sexual harassment affair covered up by the French Judiciary. It is maintained as a free service to the geography community so that it can remain as a remainder to a number of companies - including Camptocamp, ESRI, Mapbox and Makina Corpus - that the most noble way to claim size bragging rights is to produce good software. You can safely use this framework in your projects, be assured that it will be maintained very well and for many years to come. It's companion project on the server-side is gdal-async.

Alternatives

<- Light-Weight --- Feature-Rich ->

pigeon-maps - react-leaflet - rlayers

Among the completely free and open source alternatives for creating maps with React, on a scale going from the most light-weight to the most feature-rich solution, rlayers is the right-most one.

It offers the full power OpenLayers - dynamic reprojections, comprehensive event handlers, a very rich set of supported formats, interfaces and layer types and a very good performance for very complex maps. This comes at the price of a quite significant total bundle size.

Installation

npm --save install rlayers ol react react-dom

Compatibility Matrix

OpenLayers and React are peer dependencies and should be installed separately.

React is supported from version 16.8.0.


rlayers Unit-tested OpenLayers versions Unit-tested React versions
1.0 (obsolete) 6.0 16.8, 16.14, 17.0.2
1.1 (obsolete) 6.6, 6.7, 6.8, 6.9 16.8, 16.14, 17.0.2
1.2 (obsolete) 6.6, 6.7, 6.8, 6.9 16.8, 16.14, 17.0.2
1.3 (obsolete) 6.10, 6.11, 6.12, 6.13, 6.14, 6.14.1 16.8, 16.14, 17.0.2, 18.0.0
1.4 (obsolete) 6.10, 6.11, 6.12, 6.13, 6.14, 6.14.1, 6.15, 6.15.1, 7.0.0, 7.1.0, 7.2.0, 7.2.2, 7.3.0 16.8, 16.14, 17.0.2, 18.0.0, 18.1.0, 18.2.0
1.5 (obsolete) 6.10, 6.11, 6.12, 6.13, 6.14, 6.14.1, 6.15, 6.15.1, 7.0.0, 7.1.0, 7.2.0, 7.2.2, 7.3.0, 7.4.0 16.8, 16.14, 17.0.2, 18.0.0, 18.1.0, 18.2.0
2.0 6.10, 6.11, 6.12, 6.13, 6.14, 6.14.1, 6.15, 6.15.1, 7.0.0, 7.1.0, 7.2.0, 7.2.2, 7.3.0, 7.4.0, 7.5.1 16.8, 16.14, 17.0.2, 18.0.0, 18.1.0, 18.2.0
2.1 (@latest) 6.10, 6.11, 6.12, 6.13, 6.14, 6.14.1, 6.15, 6.15.1, 7.0.0, 7.1.0, 7.2.0, 7.2.2, 7.3.0, 7.4.0, 7.5.1, 8.0.0, 8.1.0 16.8, 16.14, 17.0.2, 18.0.0, 18.1.0, 18.2.0
2.2 (@next) 6.10, 6.11, 6.12, 6.13, 6.14, 6.14.1, 6.15, 6.15.1, 7.0.0, 7.1.0, 7.2.0, 7.2.2, 7.3.0, 7.4.0, 7.5.1, 8.0.0, 8.1.0, 8.2.0, 9.0.0, 9.1.0 16.8, 16.14, 17.0.2, 18.0.0, 18.1.0, 18.2.0

When using dynamic styles with React 18, you may get a warning in the console in debug mode: #40. You can safely ignore it as has no functional consequences - React 18, including the concurrent renderer, is fully supported.

Usage

rlayers is a set of reusable React components that can be nested in various ways to create map applications for the web through React composition in the true spirit of React. The components are based on a simplified model of the OpenLayers classes: for example the layers and the sources abstraction levels have been fused into one single level and the map and the view are also represented by a single component.

In order to avoid confusion between the OpenLayers classes and the rlayers classes which sometimes have the same names - all rlayers classes are prefixed with R. If a class begins with R, it is from rlayers, otherwise it is an OpenLayers class.

The most important element is the <RMap>. Every other element, except <RStyle>, requires a parent to function - an <RLayer> must be part of a map, an <RFeature> must be part of an <RLayerVector>, an <RControl> must also be part of a map.

Simple step-by-step example

This is the simple overlay example - https://mmomtchev.github.io/rlayers/#/overlays

import React from 'react';
import {fromLonLat} from 'ol/proj';
import {Point} from 'ol/geom';
import 'ol/ol.css';

import {RMap, ROSM, RLayerVector, RFeature, ROverlay, RStyle} from 'rlayers';
import locationIcon from './svg/location.svg';

// Create a map, its size is set in the CSS class example-map
<RMap className='example-map' initial={{center: fromLonLat([2.364, 48.82]), zoom: 11}}>
    {/* Use an OpenStreetMap background */}
    <ROSM />
    {/* Create a single layer for holding vector features */}
    <RLayerVector zIndex={10}>
        {/* Create a style for rendering the features */}
        <RStyle.RStyle>
            {/* Consisting of a single icon, that is slightly offset
             * so that its center falls over the center of the feature */}
            <RStyle.RIcon src={locationIcon} anchor={[0.5, 0.8]} />
        </RStyle.RStyle>
        {/* Create a single feature in the vector layer */}
        <RFeature
            {/* Its geometry is a point geometry over the monument */}
            geometry={new Point(fromLonLat([2.295, 48.8737]))}
            {/* Bind an onClick handler */}
            onClick={(e) =>
                {/* e.map is the underlying OpenLayers map - we call getView().fit()
                to pan/zoom the map over the monument with a small animation */}
                e.map.getView().fit(e.target.getGeometry().getExtent(), {
                    duration: 250,
                    maxZoom: 15
                })
            }
        >
            {/* The icon is an SVG image that represents the feature on the map
            while an overlay allows us to add a normal HTML element over the feature */}
            <ROverlay className='example-overlay'>
                Arc de Triomphe
                <br />
                <em>&#11017; click to zoom</em>
            </ROverlay>
        </RFeature>
    </RLayerVector>
</RMap>

Check examples/static_pages.html for a fully self-contained static HTML page using rlayers.

You can also check the GPLed XC-DB for a larger and more complex project entirely implemented using React, Redux and rlayers.

Contexts

Composition works by using React Contexts. Every nested element uses the context of its nearest parent.

The underlying OpenLayers objects can be accessed using the useOL() hook - check the Geolocation example to see how.

Currently useOL() has an RContextType and can contain the following elements:

  • map provided by a map, every other element, except an RStyle must have a map parent
  • layer and source provided by all layers - not required for anything at the moment, but can be used to access the underlying OpenLayers objects
  • vectorlayer and vectorsource provided by vector layers only - required for <RFeature>
  • vectortilelayer provided by vector tile layers only
  • location and feature provided by a map feature - required for <ROverlay> and <RPopup>
  • style provided by a style definition - the only one which can be outside of a map

Additionally, useRLayersComponent() allows retrieving the containing rlayers component.

Accessing the underlying OpenLayers objects and API

The underlying OpenLayers objects can be accessed in a number of different ways:

  • Through the context objects by using React.Context.Consumer
  • In an event handler that is a normal function and not an arrow lambda, this will contain the rlayers component and this.context will contain the context - this is an alternative to using useOL()
  • In all event handlers, OpenLayers will pass the target object in event.target and the map in event.map - the popups example uses this method
  • And finally, accessing arbitrary elements, even outside their contexts, is possible by using React references - React.RefObjects. The high performance example contains an example of this. The underlying OpenLayers objects can be accessed through the ol property of every component. Additionaly, for layer objects, the underlying OpenLayers source can be accessed through source:
    const layerRef = React.createRef() as React.RefObject<RLayerVector>;
    Then after rendering:
    <RLayerVector ref={layerRef} />
    layerRef.current.ol will contain the OpenLayers layer and layerRef.current.source will contain the source. This is the only way of accessing the object outside its context.

Styles

Style definitions can be placed anywhere inside the DOM and can be referenced with a React reference. rlayers includes two special types for dealing with styles:

  • RStyleRef which is an alias to React.RefObject<RStyle> is a React reference to an <RStyle> element. It can be transparently used everywhere where a classical OpenLayers StyleLike is required
  • RStyleLike is the new union type that allows for StyleLike or a RStyleRef

A style placed inside a vector layer will be automatically applied to that vector layer.

A style can either be static or dynamic. A static style depends only on its properties. A dynamic style is a function that takes an OpenLayers Feature object as its input and returns a Style. A dynamic style creates a new object for every rendered feature, so this must be taken into account. A simple caching mechanism is also provided, based on a user-supplied hash function. It can greatly improve performance when the majority of the features use relatively few different styles.

You can refer to

Classical OpenLayers StyleLike objects are supported too, but this is not the React way. Still, if you need every last bit of performance, writing an optimized OpenLayers style function is the best solution.

Performance

React is a wonderful framework that makes it very easy to write complex web applications without having to manually handle all the interdependencies between the various components. This is the reason why it is called React - components automatically React to changes in other components. In the true spirit of React, rlayers prefers to err on the safe side - always updating when there is a chance that the component needs updating - making it easy on the beginner who wants simple interface while still allowing the experienced engineer to achieve the performance he needs.

When high performance is required, particular care must be taken that the component properties do not change without a reason. This is especially true when the pointermove event is used. In these cases one should avoid using anonymous objects, arrays or functions as properties.

Take for example this:

<RFeature
    geometry={new Point(fromLonLat([2.295, 48.858])}
    onClick={(e: MapBrowserEvent) => process(e.target)}
/>

This is a feature that will be re-evaluated at every frame. Its geometry appears to be a constant, but it is in fact an anonymous object that is created at every frame - even if it always holds the same value. Passing a constant is one way around this, but the true React way is using the two tools React provides: React.useMemo and React.useCallback. They memoize the value and take care to always return a reference to the same object unless one of the listed dependencies is modified.

This is a much better performing code that won't rerender the feature component:

<RFeature
    geometry={React.useMemo(new Point(fromLonLat([2.295, 48.858]), [/* no deps */])}
    onClick={React.useCallback((e: MapBrowserEvent) => process(e.target), [/* no deps */])}
/>

Anonymous objects, arrays and especially lambdas in the properties of a component are prime candidates for memoization. Sometimes, you can also memoize whole components or groups of components - for a very significant performance boost.

Generally, if you are binding code to the pointermove event and your performance is not good enough, this is the first thing you should be looking at - which components update at every pointermove and why.

These 3 examples run code on various high-frequency events, take a look at them:

  • Clustering runs the styling function every time the map is panned or zoomed
  • Drop a pin runs code on every pointermove that carefully avoids rerendering
  • Geo data updates components at every pointerenter/pointerleave
  • The high performance example is a complex example that runs lots of code and updates components at every pointermove

Also, when searching for features listening on pointermove/pointerenter/pointerleave events, rlayers 2.0.0 and later, is able to eliminate very early feature layers that do not contain features listenening for those events. If your map contains a large number of features, and only a handful of these use pointermove events - try to group them in a separate layer.

Examples

The examples can be found here: https://mmomtchev.github.io/rlayers/

Next.js

When using with Next.js, you have to install next-transpile-modules:

npm install --save next-transpile-modules

And then create the following next.config.js:

const withTranspile = require('next-transpile-modules')(['ol', 'rlayers']);
module.exports = withTranspile({experimental: {esmExternals: 'loose'}});

It is known to work with Next.js 10 to Next.js 13. You can check rlayers-npm-tests repository for examples for working configurations.

Server-Side Rendering

Server-side rendering of map components is difficult - there is still no comprehensive solution. Besides the obvious complexities of rendering on canvas outside the browser, one of the major issues is that server-side rendering runs before the browser layout flowing - and thus must work independent of layout and resolution.

The best solution is to use a WMS-compatible server (such as Geoserver) and to serve prerendered maps over WMS - eventually replacing the initial image by a canvas.

An intermediate solution, which does not require extensive server-side investment (such as Geoserver), but is limited to static layout(s), is to prerender one (or one per screen size) image to be used as a temporary place-holder until the map is loading. In this case, at least some devices, will get an ugly looking map for the first few seconds.

Pushing the initial tiles is also an option:

  • when combined with a WMS-server it could deliver pixel-perfect maps with on the first HTTP request
  • without a WMS-server it could still avoid doing a large number of HTTP requests on the first load

Currently, server-side rendering of raster layers on fixed map sizes has reached POC status and an online demo is accessible at https://rlayers-ssr.meteo.guru/. The code can be found in the ssr branch of this project. The next.js project can be found at https://github.com/mmomtchev/rlayers-ssr-demo.git. This is still not a user-friendly, install-and-run project. Take a look at pages/index.js if you want see how it is meant to be used.

As of March 2022, SSR support is stale and I am not working on it anymore.

Google Maps API Support

The Google Maps API is not open and although it is now supported out-of-the-box by OpenLayers starting from version 9.0, it requires a paid subscription (with an eventual trial period). Adding Google Maps support is not possible unless someone is willing to sponsor it.

API

You can browse the full documentation at https://mmomtchev.github.io/rlayers/api.

License

ISC

rlayers's People

Contributors

clacladev avatar dependabot[bot] avatar impleri avatar indapublic avatar jeroentjuuh avatar mmomtchev avatar mschilde avatar snyk-bot avatar tarmooo avatar thentech avatar thijsnulle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rlayers's Issues

How to use another tile library like Thunderforest

Hi,
Thanks for rlayers - an extremely promising solution!

I want to use rlayers with Thunderforest tiles. It seems (by looking at the types) that the correct syntax should be:
<ROSM source={ 'https://tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=<key>' } />

But unfortunately that is not correct. Can you tell me what the correct manner is to use another tile library?

Thanks!

Don't work on Next.js with the error "Error [ERR_REQUIRE_ESM]: Must use import to load ES Module..."

Build error occurred
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /.../node_modules/ol/index.js
require() of ES modules is not supported.
require() of /.../node_modules/ol/index.js from /.../node_modules/rlayers/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename /.../node_modules/ol/index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /.../node_modules/ol/package.json.

    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1015:13)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (/workspace/totalscience/nextjs-blog/node_modules/rlayers/index.js:26:12)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14) {
  type: 'NodeError',
  code: 'ERR_REQUIRE_ESM'
}

Using a dynamic `RStyle` in React 18 triggers a warning in the console

When using a dynamic RStyle with a render prop in React 18 in development mode, there is a warning in the console:

Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17.

Direct enumeration of features does not work with clustering

<RMap className='map' initial={{ center: center, zoom: 11 }}>
    <ROSM />
    <RLayerCluster>
        <RStyle.RStyle render={getStyle} />
        {
            (this.state?.features || []).map((f, i) => (
                <RFeature key={i} geometry={f.geometry} properties={f} />
            ))
        }
    </RLayerCluster>
</RMap>

Features are incorrectly added to the parent vector layer

renderBuffer parameter ignored

Hi,

RLayerVector has a renderBuffer prop, but this is not actually passed to the underlying LayerVector. This change in the RLayerVector constructor works for me:

this.ol = new LayerVector({
    style: RStyle.getStyle(this.props.style),
    source: this.source,
    renderBuffer: this.props.renderBuffer
});

For background info, I'm having problems with mouse events not working properly with large images (the events are only delivered if the cursor is within 100 pixels of the centre of the feature), which I can fix/work around by extending the render buffer size.

Thanks.

Use Rlayers with QGIS Server

Hello,

first of: Thank you for this project. I am currently looking through the docs and the examples and it is brilliant.

I have a question regarding if it is already support or how you would go about using WMS layers served by a qgis server? I am currently writing my own react web app to consume a qgis server.

Best regards,
dmeStudent

RCircle style not showing when together with RIcon

So I have a RLayerCluster with a dynamic RStyle that should render a style with a circle and an icon.

But as soon I add the RIcon to the style the RCircle disappears

<RLayerCluster features={feats} ref={layerRef} key={'trackable-features-layer'} zIndex={50}>
	<RStyle render={useCallback((feature, resolution) => {
		const size = feature.get("features").length;

		// This is the size (number of features) of the cluster
		if (size > 1) {
			// Render a blob with a number
			return (
				<>
					<RCircle radius={16}>
						<RFill color="#05164d" />
					</RCircle>
					<RText scale={1.5} text={size.toString()}>
						<RFill color="#fff" />
					</RText>
				</>
			);
		}

		// We have a single feature cluster
		const unclusteredFeature = feature.get("features")[0];

		const svg = '<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="640" height="512" enable-background="new 0 0 30 30" xml:space="preserve"><path fill="#00FFFF" d="M143.25 220.81l-12.42 46.37c-3.01 11.25-3.63 22.89-2.41 34.39l-35.2 28.98c-6.57 5.41-16.31-.43-14.62-8.77l15.44-76.68c1.06-5.26-2.66-10.28-8-10.79l-77.86-7.55c-8.47-.82-11.23-11.83-4.14-16.54l65.15-43.3c4.46-2.97 5.38-9.15 1.98-13.29L21.46 93.22c-5.41-6.57.43-16.3 8.78-14.62l76.68 15.44c5.26 1.06 10.28-2.66 10.8-8l7.55-77.86c.82-8.48 11.83-11.23 16.55-4.14l43.3 65.14c2.97 4.46 9.15 5.38 13.29 1.98l60.4-49.71c6.57-5.41 16.3.43 14.62 8.77L262.1 86.38c-2.71 3.05-5.43 6.09-7.91 9.4l-32.15 42.97-10.71 14.32c-32.73 8.76-59.18 34.53-68.08 67.74zm494.57 132.51l-12.42 46.36c-3.13 11.68-9.38 21.61-17.55 29.36a66.876 66.876 0 0 1-8.76 7l-13.99 52.23c-1.14 4.27-3.1 8.1-5.65 11.38-7.67 9.84-20.74 14.68-33.54 11.25L515 502.62c-17.07-4.57-27.2-22.12-22.63-39.19l8.28-30.91-247.28-66.26-8.28 30.91c-4.57 17.07-22.12 27.2-39.19 22.63l-30.91-8.28c-12.8-3.43-21.7-14.16-23.42-26.51-.57-4.12-.35-8.42.79-12.68l13.99-52.23a66.62 66.62 0 0 1-4.09-10.45c-3.2-10.79-3.65-22.52-.52-34.2l12.42-46.37c5.31-19.8 19.36-34.83 36.89-42.21a64.336 64.336 0 0 1 18.49-4.72l18.13-24.23 32.15-42.97c3.45-4.61 7.19-8.9 11.2-12.84 8-7.89 17.03-14.44 26.74-19.51 4.86-2.54 9.89-4.71 15.05-6.49 10.33-3.58 21.19-5.63 32.24-6.04 11.05-.41 22.31.82 33.43 3.8l122.68 32.87c11.12 2.98 21.48 7.54 30.85 13.43a111.11 111.11 0 0 1 34.69 34.5c8.82 13.88 14.64 29.84 16.68 46.99l6.36 53.29 3.59 30.05a64.49 64.49 0 0 1 22.74 29.93c4.39 11.88 5.29 25.19 1.75 38.39zM255.58 234.34c-18.55-4.97-34.21 4.04-39.17 22.53-4.96 18.49 4.11 34.12 22.65 39.09 18.55 4.97 45.54 15.51 50.49-2.98 4.96-18.49-15.43-53.67-33.97-58.64zm290.61 28.17l-6.36-53.29c-.58-4.87-1.89-9.53-3.82-13.86-5.8-12.99-17.2-23.01-31.42-26.82l-122.68-32.87a48.008 48.008 0 0 0-50.86 17.61l-32.15 42.97 172 46.08 75.29 20.18zm18.49 54.65c-18.55-4.97-53.8 15.31-58.75 33.79-4.95 18.49 23.69 22.86 42.24 27.83 18.55 4.97 34.21-4.04 39.17-22.53 4.95-18.48-4.11-34.12-22.66-39.09z"/></svg>'

		// Render a star
		return <>
			<RCircle radius={16}>
				<RFill color="#05164d" />
			</RCircle>
			<RIcon
				scale={16 / icon[1]}
				src={'data:image/svg+xml,' + encodeURIComponent(svg)} >
			</RIcon>
			</>
	}, [])}>
	</RStyle>
</RLayerCluster>

Source mapping points to incorrect path (still/again)

Hi, thanks so much for publishing this package, it really helps a lot with using openlayers in React!

When I use rlayers (v1.3.1) with create-react-app, I get a lot of warnings like:

WARNING in ./node_modules/rlayers/control/RAttribution.js
Module Warning (from ./node_modules/source-map-loader/dist/cjs.js):
Failed to parse source map from '$PROJECT_DIR/node_modules/rlayers/control/src/control/RAttribution.tsx' file: Error: ENOENT: no such file or directory, open '$PROJECT_DIR/node_modules/rlayers/control/src/control/RAttribution.tsx'
 @ ./node_modules/rlayers/control/index.js 23:21-46
 @ ./node_modules/rlayers/index.js 249:32-52
 @ ./src/OlTest.tsx 6:0-71 16:35-39 23:38-42 27:37-49 29:39-47 35:41-49
 @ ./src/App.tsx 13:0-34 34:41-47
 @ ./src/index.tsx 7:0-24 11:33-36

The warning is correct: the .tsx files aren't located in node_modules/rlayers/control/src/control, they're in node_modules/rlayers/src/control (the source mapping references src/ but should instead reference ../src/ when it's in a subdirectory.

It would be great if you could fix this.

(This is related to #25 but seems to be a new issue resulting from its fix.)

Removing features from ol map on RLayerVector component unmount

Hi,

When unmounting a RLayerVector (the layer is removed from the app on user action), the features of the layer stay visible on the map. Is it done on purpose ? Should not RLayerVector implement a componentWIllUnmount function where this.source.clear() is called ?

Thanks for your answer !

Using a dynamic `RStyle` with the new React renderer triggers a warning in the console

Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.

Alas, unlike #40, this warning is about a very real problem and there is no workaround for it except to not use the render property of <RStyle> and to replace it with an openlayers style function.

This is due to performance optimizations while lazy rendering components. rlayers renders the styles in a virtual off-screen component and this rendering cannot run in parallel with the main rendering.

Cluster component fail - [email protected]

Dependencies installed:
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
"@testing-library/user-event": "^12.8.3",
"@types/jest": "^26.0.24",
"@types/node": "^12.20.16",
"@types/ol": "^6.5.3",
"@types/react": "^17.0.14",
"@types/react-dom": "^17.0.9",
"ol": "^6.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"rlayers": "^1.0.4",
"typescript": "^4.3.5",
"web-vitals": "^1.1.2"

Cluster component fails on load feojson file:
Line 20 - import earthquakes from "!!file-loader!./data/earthquakes.geojson";
Error:
src\Cluster.tsx
Line 20:1: Unexpected '!' in '!!file-loader!./data/earthquakes.geojson'. Do not use import syntax to configure webpack loaders import/no-webpack-loader-syntax

ask for feature: add option to RControl.RLayers to make it non-collapsable. or is it already possible?

Hello

First: thank you for this great library. Very useful...

I would like to have the RControl.RLayers control expanded all the time.
is it already possible with the current code( or with css change)?
If not does it make sense to make a modif to pass some option like 'collapsable: true/false'?

Then as I some time I struggle a lot to find how to do use some component(and then maybe I use it in not the best way), is it possible to contact you directly (without abusing of your time of course). Or is there some discussion group or equivalent somewhere?

Thanks

best regards

Gilles ([email protected])

react native app use it running at web is perfect,but running at phone is error:can't find variable:document

ReferenceError: Can't find variable: document

This error is located at:
in RMap (at ol.js:39)
in RCTView (at View.js:34)
in View (at ol.js:38)
in MyOpenLayers (at map.js:377)
in RCTView (at View.js:34)
in View (at map.js:375)
in RCTView (at View.js:34)
in View (at map.js:371)
in RCTView (at View.js:34)
in View (at map.js:319)
in MapComponent (at SceneView.tsx:126)
in StaticContainer
in StaticContainer (at SceneView.tsx:119)
in EnsureSingleNavigator (at SceneView.tsx:118)
in SceneView (at useDescriptors.tsx:209)
in RCTView (at View.js:34)
in View (at DebugContainer.native.tsx:27)
in DebugContainer (at NativeStackView.native.tsx:71)
in MaybeNestedStack (at NativeStackView.native.tsx:228)
in MaybeFreeze (at src/index.native.tsx:229)
in RNSScreen (at createAnimatedComponent.js:165)
in AnimatedComponent (at createAnimatedComponent.js:215)
in ForwardRef(AnimatedComponentWrapper) (at src/index.native.tsx:208)
in Screen (at NativeStackView.native.tsx:175)
in SceneView (at NativeStackView.native.tsx:276)
in RNSScreenStack (at src/index.native.tsx:160)
in ScreenStack (at NativeStackView.native.tsx:267)
in NativeStackViewInner (at NativeStackView.native.tsx:321)
in RNCSafeAreaProvider (at SafeAreaContext.tsx:76)
in SafeAreaProvider (at SafeAreaProviderCompat.tsx:38)
in SafeAreaProviderCompat (at NativeStackView.native.tsx:320)
in NativeStackView (at createNativeStackNavigator.tsx:67)
in NativeStackNavigator (at App.js:34)
in EnsureSingleNavigator (at BaseNavigationContainer.tsx:429)
in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:132)
in ThemeProvider (at NavigationContainer.tsx:131)
in ForwardRef(NavigationContainerInner) (at App.js:33)
in App (created by ExpoRoot)
in ExpoRoot (at renderApplication.js:45)
in RCTView (at View.js:34)
in View (at AppContainer.js:106)
in DevAppContainer (at AppContainer.js:121)
in RCTView (at View.js:34)
in View (at AppContainer.js:132)
in AppContainer (at renderApplication.js:39)
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:104:6 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:171:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:12:21 in ErrorUtils.setGlobalHandler$argument_0

Missing documentation for RIcon

Hi, I would like to use RIcon in my code. However, the only place I can find how to use it is in one of the examples. If you can add documentation for RIcon, that would be great.

Unable to extend with IIIF Layer

I might be going about this the wrong way, but I'm not having any success extending Rlayers to view an IIIF image. Using the example from Open Layers https://openlayers.org/en/latest/examples/iiif.html this is my class:

export interface RLayerIIIFProps extends RLayerRasterProps {
    url: string
    iiifManifest: string | ImageInformationResponse
}


class RLayerIIIF extends RLayer<RLayerIIIFProps> {
    ol: LayerTile<IIIF>
    source: IIIF

    constructor(
        props: Readonly<RLayerIIIFProps>,
        context: React.Context<RContextType>
    ) {
        super(props, context)
        this.createSource()
        this.ol = new LayerTile({ source: this.source })
        this.eventSources = [this.ol, this.source]
    }

    createSource(): void {
        const options = new IIIFInfo(this.props.iiifManifest).getTileSourceOptions()
        if (options === undefined || options.version === undefined) {
            throw new Error('manifest is not valid IIIF configuration')
        }
        this.source = new IIIF({ ...options, zDirection: -1 })
        this.eventSources = [this.ol, this.source]
    }

    refresh(prevProps?: RLayerIIIFProps): void {
        super.refresh(prevProps)
        if (prevProps?.url !== this.props.url) this.createSource()
    }
}

Is this the right approach?

rlayers draw and getFeatureInfo onClick

Is there inbuilt ways to use rlayers to draw on map and already created component to get getFeatureInfo from clicked layer. If no I would like to see it in new versions :)

Love rlayers amazing work!

RLayerVectorTile

Does the RLayerVectorTile support popup ? I have two layers one layers is a vector layer which I am now able to provide a popup for each point. I also have a VectorTileLayer which contains multiple polygons from local pg_tileserver but when I try to add the pop to provide details of each polygon on click i get an error saying the "RFeature must be part of a vector layer" Which I am assuming to mean it is not supported in VectortileLayers unless i am missing somthing.

Thank You

Cannot get the Simple map example to work

Hi,
I was trying to get the Simple map example to work from https://mmomtchev.github.io/rlayers/#/simple,
but all I get is the following error on build:
image
I made sure to use React version 16.8.0.
My dependencies from the package.json:

"dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "@types/jest": "^26.0.15",
    "@types/node": "^12.0.0",
    "@types/react": "^16.14.8",
    "@types/react-dom": "^16.9.13",
    "ol": "^6.5.0",
    "react": "^16.8.0",
    "react-dom": "^16.8.0",
    "react-scripts": "4.0.3",
    "rlayers": "^1.0.2",
    "typescript": "^4.1.2",
    "web-vitals": "^1.0.1"
  },
  "devDependencies": {
    "@types/ol": "^6.5.1"
  }

Am I doing something wrong?

rlayers adds a large number of empty `<div>` tags in the map element

rlayers adds a large number of empty <div> tags in the map element

<div class="map" style="cursor: pointer;">
    <div class="ol-viewport" style="position: relative; overflow: hidden; width: 100%; height: 100%;">
        <div class="ol-unselectable ol-layers" style="position: absolute; width: 100%; height: 100%; z-index: 0;">
            <div class="ol-layer" style="position: absolute; width: 100%; height: 100%;"><canvas width="833" height="748"
                    style="position: absolute; left: 0px; transform-origin: left top; transform: matrix(1, 0, 0, 1, 0, 0);"></canvas></div>
        </div>
        <div class="ol-overlaycontainer" style="position: absolute; z-index: 0; width: 100%; height: 100%; pointer-events: none;"></div>
        <div class="ol-overlaycontainer-stopevent" style="position: absolute; z-index: 0; width: 100%; height: 100%; pointer-events: none;">
            <div class="ol-zoom ol-unselectable ol-control" style="pointer-events: auto;"><button class="ol-zoom-in" type="button" title="Zoom in">+</button><button class="ol-zoom-out" type="button"
                    title="Zoom out"></button></div>
            <div class="ol-rotate ol-unselectable ol-control ol-hidden" style="pointer-events: auto;"><button class="ol-rotate-reset" type="button" title="Reset rotation"><span class="ol-compass"
                        style="transform: rotate(0rad);"></span></button></div>
            <div class="ol-attribution ol-unselectable ol-control ol-uncollapsible" style="pointer-events: auto;"><button type="button" aria-expanded="true" title="Attributions"><span
                        class="ol-attribution-collapse"></span></button>
                <ul>
                    <li>© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors.</li>
                </ul>
            </div>
        </div>
    </div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>

RFeature properties

Hi,

I see in the API that RFeature can have a "properties" value : <Record, unknown>. Is there an example on how to use it ?

What i would like :

<RFeature 
  key={record.fields.id}  
  geometry={new Point(fromLonLat([record.geometry.coordinates[0], record.geometry.coordinates[1]]))}
  properties={{'prop1':value1}, {'prop2':value2}} 
  onClick={featureClickHandler}
>                            
</RFeature> 

And im my featureClickHandler function :

const prop1 = e.properties.prop1

Thx,

Fred.

Popups only appear after hot reload

I'm attempting to upgrade from 1.1.1 to 1.3.1 and hitting a rather weird issue.

Each feature should have a linked popup. The popups don't display on hover after an initial load of the page. However if I change the code of the popup and it hot reloads, then the popups display. They again do not display after a full reload of the page.

I'm not exactly sure where to start debugging this one. I tried updating to 1.2.1 instead, but then hit onClick not firing on features which appeared to be fixed in 84bfd72.

RLayer.1.3.1.Popup.mov

Here is the branch of my project that I'm working on that's having this issue: gulfofmaine/Neracoos-1-Buoy-App#1766

Error when compiling the layers control with TypeScript 4.8

src/control/RLayers.tsx:111:59 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type '{ visible: boolean; }' is not assignable to parameter of type 'Partial<unknown> & Attributes'.
      Object literal may only specify known properties, and 'visible' does not exist in type 'Partial<unknown> & Attributes'.

111                         return React.cloneElement(child, {visible: visible[i]});
                                                              ~~~~~~~~~~~~~~~~~~~

  node_modules/@types/react/index.d.ts:320:14
    320     function cloneElement<P>(
                     ~~~~~~~~~~~~
    The last overload is declared here.


Found 1 error in src/control/RLayers.tsx:111

Styling for Feature on Line and Polygon

I was using styling for Feature data using default Openlayers because RLayer in some reason not work or showing what must to be,
I'm using "rlayers": "^1.4.0", for react I'm using "react": "^18.0.0", and Openlayers "ol": "^6.14.1", .

here when I using point and it's work well but not when I'm using RStyle.

<RLayerVector
	properties={{ label: "Demand From Fetching" }}
	zIndex={5}
	style={
		new Style({
			image: new CircleStyle({
				radius: 2,
				fill: new Fill({
					color: "purple",
				}),
				stroke: new Stroke({
					color: "#212529",
					width: 1,
				}),
			}),
		})
	}>
	{featuresDemand.map((f) => (
		<RFeature key={f.get("id")} feature={f}>
			<ROverlay
				position={[f.get("longitude"), f.get("latitude")]}
				offset={[-10, -10]}
				element={
					<div
						style={{
							backgroundColor: "#212529",
							color: "#ffffff",
							padding: "5px",
							fontSize: "12px",
							fontWeight: "bold",
							textAlign: "center",
						}}>
						{f.get("status")}
					</div>
				}>
				<RPopup
					trigger={"hover"}
					className="example-overlay"
					delay={{ show: 1, hide: 5 }}
					onClose={() => {
						setSelected(false);
					}}></RPopup>
			</ROverlay>
		</RFeature>
	))}
	<RInteraction.RModify
		condition={selectedLayer === altKeyOnly}
		deleteCondition={React.useCallback(
			(e) => altKeyOnly(e) && doubleClick(e),
			[],
		)}
	/>
</RLayerVector>

for Line and polygon with same customization it's not work, and also with using RStyle, like so

<RStyle.RStyle>
	<RStyle.RStroke color="#ffff" width={3} lineJoin="round" />
</RStyle.RStyle>

any guide for me?

Interest in Hooks?

Hi, I've started working on creating hooks for the controls to provide an easy way for creating the controls UI in React (e.g. useZoom, useFullscreen) that copy the functionality from OL. Is there any interest in adding them to rlayers directly? I may even have a few examples.

Custom loader for RLayerTile

Hi, I try to load tile from a server, and i recieve error, because my request is without correct token. How can i provide axios or token to request?
tile
error

Cannot get the map to work

Hi,

The Typescript compilers complains when running the Simple map example :

'RMap' cannot be used as a JSX component.
  Its instance type 'RMap' is not a valid JSX element.
    Types of property 'componentDidUpdate' are incompatible.
      Type '(prevProps: RMapProps, prev: null, snap: unknown) => void' is not assignable to type '(prevProps: Readonly<any>, prevState: Readonly<{}>, snapshot?: any) => void'.
        Types of parameters 'prev' and 'prevState' are incompatible.
          Type 'Readonly<{}>' is not assignable to type 'null'.

I'm using React 17.0.1 and the strict Typescript mode is enabled (I saw the similar #2 issue).
Am I missing something?

measurement tools and export features

Thank you for your works ,this seems great, can you please add documentation that how we can add controls for calcuation and export maps.

How can i access map object inside other component.

Draw a route of 10 points on the way

An excellent library with excellent documentation!
The only thing missing is an example of how to build a route between N points. As a logistician, I want to build a route for the day that passes through 10 points. I could not find the implementation of this functionality in the examples. Can anyone help?

`RLayerVectorTile` is not compatible with inline styles

This is not possible:

<RLayerVectorTile
    format={reader}
    url={`someUrl/{z}/{y}/{x}`}
>
    <RStyle.RStyle>
        <RStyle.RCircle radius={10}>
            <RStyle.RStroke color='red' width={3} />
        </RStyle.RCircle>
    </RStyle.RStyle>
</RLayerVectorTile>

WFS Feature Layer Popup with attributes on click

How would I go about producing a pop from a wfs layer ? I am able to successfully pull the layer in and log the location attribute to the console with the code below. This pulls from a local pg_featureserv instance displaying cctv locations as a point. All the examples of popups seem to create a popup that is wrapped in a feature. But Im not sure how to go about this if I am already pulling the features into the layer. Sorry for the noob questions but I mostly work on the backend and I am trying to learn more frontend.

Thanks

<RLayerVector
properties={{ label: "CCTV" }}
zIndex={1}
format={new GeoJSON({ featureProjection: "EPSG:4326" })}
url="http://localhost:9000/collections/public.cctv/items.json?limit=500"
onClick={React.useCallback(
(e) => console.log(e.target.get("location")),
[]
)}
>

Crash when removing <RFeature> from <RLayerVector>

Hello,

I have a data array that is mapped to <RFeature> components inside an RLayerVector component.

Everything is working perfectly until I remove objects from my data array. At this point the application crashes and I get the following error message: Uncaught DOMException: Node.removeChild: The node to be removed is not a child of this node

From what I can tell, this has to do with DOM manipulation from either rlayers or ol. Any advice on how to solve the problem?

Edit: GitHub removes HTML-tag like strings when they are not in a code block

Can't add onClick to RLayerCluster

I recieve a compile error when trying to add a onClick handler to my RLayerCluster:

function onClickHandler (this: RLayerBaseVector<RLayerBaseVectorProps>, e: RFeatureUIEvent) {}

return <RLayerCluster onClick={onClickHandler} {...featureAdditional}}>...</RLayerCluster>

throws this error:

semantic error TS2322: Type '((this: RLayerBaseVector<RLayerBaseVectorProps>, e: RFeatureUIEvent) => void) | ((this: RFeature, e: RFeatureUIEvent) => boolean | void)' is not assignable to type '(this: RLayerBaseVector<RLayerBaseVectorProps>, e: RFeatureUIEvent) => boolean | void'.
  Type '(this: RFeature, e: RFeatureUIEvent) => boolean | void' is not assignable to type '(this: RLayerBaseVector<RLayerBaseVectorProps>, e: RFeatureUIEvent) => boolean | void'.
    The 'this' types of each signature are incompatible.
      Property 'onchange' is missing in type 'RLayerBaseVector<RLayerBaseVectorProps>' but required in type 'RFeature'.

RVectorLayer - change url and refresh layer

Hi,

I have been trying to plot an area using the RVectorLayer. I can get this to work nicely if the when the map loads for the first time but even after changing the url I am unable to get the refresh to work. So far I have the following working.

Given a coordinate I can load the map
Given a valid url to the wms service layer I can get the RVectorLayer to display
Given the coordinate changes I can get the RMap to reload at the new coordinate using [view, setView]
I can use a ref to the RVectorLayer to clear the existing source
What I haven't managed to work out is what I need to do to trigger the load with the new URL in place. The refresh method on the RVectorLayer is not working for me.

Any help would be much appreciated.

Example visualization. Geolocation

Cannot use namespace 'GeometryType' as a type. TS2709

62 | 
63 |                     <RInteraction.RDraw

64 | type={"Polygon" as GeometryType}
| ^
65 | condition={shiftKeyOnly}
66 | freehandCondition={altShiftKeysOnly}
67 | />

TileWMS component property "projection" is not added to query options

Hello,

first of all thank you for adding basic TileWMS support it helps me very much to avoid my hacky workarounds :)

While switching to your implementation in 1.1rc I noticed that you are able to pass "projection" as a propterty to the component, but it is not added to the request itself because on line 27 in https://github.com/mmomtchev/rlayers/blob/master/src/layer/RLayerTileWMS.tsx it is not added to the options object.

Therefore openlayers will always build the query using the crs/projection configured in the view.

Best regards,
dmeStudent

onTranslateEnd

I can't get onTranslateEnd to fire when filtering different layers, am I just being dumb?
If I remove the filter it fires as it should - I just don't need every layer to be moveable

<RInteraction.RTranslate filter={(feature) => { return feature.getProperties().type === 'moveable'; }} onTranslateEnd={(e) => { console.log(e); }} />

Generating RLayerVector objects outside of RMap

Hello,
I am using this library in a React app where I am required to create components outside of my the RMap object. Is there any way, using RContext maybe, to generate RLayerVector objects outside of RMap and pass them in as children using the spread operator?

high call rate `style` function on `RLayerVectorTile`, hits performance badly

Hi!

I set up a RLayerVectorTile in my RMap that uses MVT format, and pull pbf files from my server. That layer has a lot of features... this leads the function passed to the style prop to be called thousands of times, over 10-20 seconds. This causes the render to freeze at times.
Is there a way to manage the performance on client side to address this scenario? or should my team look into providing more tilesets with less features each?

Thanks!

Some `RMap` properties cannot be dynamically updated

I've noticed many other properties are not updating dynamically like on the RMap component: noDefaultControls, noDefaultInteractions, maxZoom.

The docs only state a few specific props that don't update, but the above examples don't...

I see this is because the RMap constructor creates a new Map, and never reinitializes it after props change:

this.ol = new Map({

Originally posted by @TrySpace in #85 (comment)

Source mapping points to incorrect path

Fresh project / install via npm. [email protected].

Source maps for most (if not all) files, are pointing to $PROJ/node_modules/src/..., rather than $PROJ/node_modules/rlayers/src/...

Example:
Failed to parse source map from '/DATA/workspace/ol_proj/frontend/node_modules/src/style/index.ts' file: Error: ENOENT: no such file or directory, open '/DATA/workspace/oj_proj/frontend/node_modules/src/style/index.ts' @ ./node_modules/rlayers/index.js 224:30-48 @ ./src/App.tsx 6:0-37 12:32-36 18:37-41 @ ./src/index.tsx 7:0-24 11:33-36

No real functional issue, but incredibly annoying since it floods my console.

Vector Tiles Example component error

tsconfig.json -> strict: false

Generic type 'Feature' requires 1 type argument(s). TS2314

43 |             <RStyle
44 |                 ref={styles.towns}

45 | render={useCallback((feature: Feature) => {
| ^
46 | /* This is a the towns style
47 | *
48 | * This is a dynamic style that creates a new object

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.