npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-ol-fiber

v3.0.2

Published

A React renderer for OpenLayers

Downloads

90

Readme

react-ol-fiber

Version Downloads Test

react-ol-fiber is a React renderer for OpenLayers.

Build your maps declaratively with re-usable, self-contained components that react to state, are readily interactive and can participate in React's ecosystem.

npm install ol react-ol-fiber

Being a renderer and not a wrapper it's not tied to a specific version of OpenLayers, and allows easy extensibility.

Quick Start Code

Edit react-ol-fiber-qs

import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import { MapComponent } from 'react-ol-fiber';
import 'ol/ol.css';

function Shapes() {
  const [active, setActive] = useState(false);
  useEffect(() => {
    const interval = setInterval(() => setActive(a => !a), 500);
    return () => clearInterval(interval);
  }, []);

  return (
    <vectorLayer>
      <styleStyle>
        <fillStyle arg={{ color: active ? 'blue' : 'yellow' }} />
        <strokeStyle arg={{ color: 'red' }} />
      </styleStyle>

      <vectorSource>
        {new Array(32 * 32).fill(0).map((_, i) => (
          <feature>
            <circleGeometry args={[[(i % 32) * 100000, Math.floor(i / 32) * 100000], 30000]} />
          </feature>
        ))}
      </vectorSource>
    </vectorLayer>
  );
}

function App() {
  return (
    <MapComponent>
      <tileLayer>
        <oSMSource />
      </tileLayer>

      <Shapes />

      <dragPanInteraction />
      <mouseWheelZoomInteraction />
    </MapComponent>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

Docs

The MapComponent component

The most important component in react-ol-fiber is <MapComponent /> it instantiate an OpenLayer Map object and mounts it in a full-width and full-height div. As children you can provide OpenLayer elements that can be mounted inside the map, such as layers, controls and interactions.

function App() {
  return (
    <MapComponent
      view={{
        center: fromLonLat([37.41, 8.82]),
        zoom: 4,
      }}
    >
      <tileLayer>
        <oSMSource />
      </tileLayer>
    </MapComponent>
  );
}

Using OpenLayers classes

To create instances of OpenLayers classes in react-ol-fiber you can use JSX primitives. As component name, use the original class name with the first letter in lower case, followed by its category.

To provide arguments to the class constructor use the args prop, or arg if the constructor has a single parameter. To attach the children to the parent you can use the attach and attachAdd props (even though they are inferred automatically whenever possible by the reconciler).

Some examples:

function Component() {
  return (
    <>
      <feature /> {/* ol/Feature */}
      <tileLayer /> {/* ol/layers/Tile */}
      <vectorLayer /> {/* ol/layers/Vector */}
      <circleGeometry args={[[0, 0], 10]} /> {/* ol/geom/Circle */}
      <pointGeometry arg={[0, 0]} /> {/* ol/geom/Point */}
      <dragPanInteraction /> {/* ol/geom/Point */}
      <styleStyle /> {/* ol/style/Style */}
      <strokeStyle arg={{ color: 'red', width: 2 }} /> {/* ol/style/Stroke */}
    </>
  );
}

Props

The props are applied using the setters found in the target object. The reconciler is optimized to call only the setters of the modified values.

function Component() {
  // This will call setOpacity in the VectorLayer
  return <vectorLayer opacity={0.75} />;
}

Event handlers

All the events described in the OpenLayers documentation are capitalized and prefixed with "on".

function Component() {
  // This will set the 'select' event
  return <selectInteraction onSelect={e => console.log(e)} />;

  // This will set the 'change' event
  return <vectorSource onChange={e => console.log(e)} />;

  // It also works on the map component!
  return <MapComponent onPointermove={e => console.log(e.coordinate)} />;
}

Hooks

Whenever you need to access the underlying OpenLayers map instance, you can use the useOL() hook. Remember that this can work only inside a component that is child of a MapComponent. :warning:

function Inner() {
  const { map } = useOL();
  function centerOnFeatures(extent: number[]) {
    const view = map.getView();
    view.fit(extent);
  }

  return (
    <vectorLayer>
      <vectorSource onChange={e => centerOnFeatures(e.target.getExtent())}>
        <feature>
          <circleGeometry args={[[0, 0], 30000]} />
        </feature>
      </vectorSource>
    </vectorLayer>
  );
}

function Parent() {
  // WARNING: you can't use useOL() here
  return (
    <MapComponent>
      <Inner />
    </MapComponent>
  );
}

Spring Animation

Provisional react-spring support is available! You can use the spring api to animate your maps, using the a. components. See this example to see how.

Using primitives

If you want to use your own already instanced objects, you can use the olPrimitive wrapper and set a custom attach:

function Component() {
  const features = myLoadFeatures();
  return (
    <vectorSource>
      {features.map((feature, i) => (
        <olPrimitive object={feature} key={i} attachAdd='feature' />
      ))}
    </vectorSource>
  );
}

:warning: Using the <olPrimitive /> instrinsic the props will not be checked. To have a generic primitive component, based on the object prop type, use the <OLPrimitive /> wrapper instead.

Using functions

Sometimes in OpenLayers it's convenient to use a function for some objects, such as style functions, to avoid creating too many objects.

function Component() {
  return (
    <vectorLayer>
      <olFn fn={feature => new Style({ fill: new Fill({ color: feature.get('color') }) })} attach='style' />

      {/* OR */}

      <olFn
        fn={feature => (
          <styleStyle>
            <fillStyle arg={{ color: feature.get('color') }} />
          </styleStyle>
        )}
        attach='style'
      />

      <vectorSource>
        <feature color='red'>
          <circleGeometry args={[[0, 0], 20000]} />
        </feature>
      </vectorSource>
    </vectorLayer>
  );
}

:warning: Please note that the second option, using JSX, does NOT use React to render the elements, it manually creates instances reading the JSX. Please use it with caution and DON'T use components in there.

Extending the catalogue

To extend the available components reachable by react-ol-fiber, you can use the extend() command. You can even implement your own props application logic using setters!

import BaseLayer from 'ol/layer/Base';
class MyLayer extends BaseLayer {
  constructor(args: { ctorArg: boolean }) {
    super({});
  }

  setMyNumber(value: number) {
    console.log(value);
  }
}

import { extend, MapComponent, TypeOLCustomClass } from 'react-ol-fiber';
extend({ MyLayer: MyLayer as any });
declare global {
  namespace JSX {
    interface IntrinsicElements {
      myLayer: TypeOLCustomClass<typeof MyLayer>;
    }
  }
}

function Test() {
  return (
    <MapComponent>
      <myLayer arg={{ ctorArg: false }} myNumber={42} />
    </MapComponent>
  );
}

FAQ

I'm not seeing my map and the entire page is blank

You need to add make your parent DOM elements full-height:

html,
body,
#root {
  width: 100%;
  height: 100%;
  margin: 0;
}

Credits

This library was strongly inspired by react-three-fiber and the technical details given by this amazing article by Cody Bennet.