Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I re-center an Openlayer 6 map after an effect triggered by a React useEffect hook

I am building a React app at the moment and need to move from MapBox to Openlayers as thats what my client uses internally. Really struggling with basic functionality to get openlayers maps to react to events. At the moment, I am trying a simple 'click button, re-centre map' but can not get it to work. Can anybody help? It's got to be something simple I am doing wrong.

I am using Openlayers v 6.0.1 (ol).

import React, { useState, useEffect, useRef } from "react";
import Map from "ol/Map.js";
import View from "ol/View.js";
import Overlay from "ol/Overlay.js";
import LayerTile from "ol/layer/Tile.js";
import SourceOSM from "ol/source/OSM.js";
import * as proj from "ol/proj";

const MapView2 = () => {
  // set state
  const [center, setCenter] = useState(proj.fromLonLat([0, 0])); // set center of map at 0,0
  const [zoom, setZoom] = useState(3); // set aoom
  const posGreenwich = proj.fromLonLat([0, 51.47]);

  // set initial map objects
  const view = new View({
    center: center,
    zoom: zoom
  });

  const map = new Map({
    target: null, // set this in componentDidMount useEffect[]
    layers: [
      new LayerTile({
        source: new SourceOSM()
      })
    ],
    view: view
  });

  const overlayRef = useRef(null);
  const popUpRef = useRef(null);

  // useEffect Hooks
  // [] = component did mount
  // set the initial map targets
  useEffect(() => {
    map.setTarget("map");
    map.on("moveend", () => {
      setCenter(map.getView().getCenter());
      setZoom(map.getView().getZoom());
    });

    // Basic overlay to show where i want the new center to be
    const overlay = new Overlay({
      position: posGreenwich,
      element: overlayRef.current,
      positioning: "center-center",
      stopEvent: false
    });
    map.addOverlay(overlay);

    // clean up upon component unmount
    return () => {
      console.log("will unmount");
      map.setTarget(null);
    };
  }, []);

  // ***** IT DOESNT WORK *******
  useEffect(() => {
    // [center, zoom] this fires after each time the center or zoom state is updated
    // it should animate the view move
    console.log("UseEffect Center & Zoom", center, zoom);
    console.log("View", JSON.stringify(view)); // if you check this, the view correctly has a new center and zoom

    // view has a new center and zoom but will not move to it automatically
    // try to force it to move here
    // DOESN'T WORK - how do I get the map to move???? :(
    view.animate({ zoom: zoom }, { center: center }, { duration: 2000 });
  }, [center, zoom]);

  // helpers
  const btnAction = () => {
    // when button is clicked, recentre map
    // this does not work :(
    setCenter(posGreenwich);
    setZoom(6);
  };

  // render
  return (
    <div>
      <div id="map" style={{ width: "100vw", height: "100vh" }}></div>
      <div
        style={styles.bluecircle}
        ref={overlayRef}
        id="overlay"
        title="overlay"
      />
      <button
        style={{
          position: "absolute",
          right: 10,
          top: 10,
          backgroundColor: "white"
        }}
        onClick={() => {
          btnAction();
        }}
      >
        CLICK
      </button>
    </div>
  );
};

export default MapView2;

const styles = {
  bluecircle: {
    width: 30,
    height: 30,
    border: "1px solid #088",
    bordeRadius: "15",
    backgroundColor: "#0ff",
    opacity: 0.5,
    zIndex: 9999
  }
};

like image 447
TeamBeamo Avatar asked Dec 19 '25 21:12

TeamBeamo


1 Answers

I was having a similar problem and solved it by using useState for the map variable, such as:

const [map] = useState(
  new Map({
    target: null, // set this in componentDidMount useEffect[]
    layers: [
      new LayerTile({
        source: new SourceOSM()
      })
    ],
    view: view
  })
);

Then, inside useEffect:

map.getView.animate({ zoom: zoom }, { center: center }, { duration: 2000 });
like image 131
petermk Avatar answered Dec 21 '25 14:12

petermk