Search code examples
reactjsopenlayersopenlayers-8

OpenLayers: Geometry coordinate change does not work while map is moving


The expected behavior is that the aircraft geometry should continue to change coordinate positions while you move the map (by dragging the mouse while holding down the left mouse button). The actual behavior is that the aircraft geometry does not change coordinate positions while map is moving. Only when you stop moving the map, the geometry coordinate position is updated to the correct coordinate.

codesandbox playground link

Source code:

import React, { useEffect, useRef } from "react";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import Feature from "ol/Feature";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { fromLonLat } from "ol/proj";
import OSM from "ol/source/OSM";
import { Point } from "ol/geom";
import {
  Text as OLText,
  Fill as OLFill,
  Style,
  Stroke,
  Circle as OLCircle
} from "ol/style";

export default () => {
  const mapRef = useRef();
  const trafficLayer = useRef();
  const aircraftPoint = useRef();
  const coordinates = [
    [22.3084, 113.9239],
    [22.3084, 113.927],
    [22.3084, 113.929]
  ];

  const moveAirplane = (counter: number) => {
    console.log("Moving airplane: ", counter);

    const lonlat = fromLonLat([
      coordinates[counter][1],
      coordinates[counter][0]
    ]);
    aircraftPoint.current.getGeometry().setCoordinates(lonlat);
  };

  const labelStyle = new Style({
    text: new OLText({
      font: "12px Calibri,sans-serif",
      overflow: true,
      fill: new OLFill({
        color: "#000"
      }),
      stroke: new Stroke({
        color: "#fff",
        width: 3
      }),
      offsetY: -12
    }),
    fill: new OLFill({
      color: "rgba(255, 255, 255, 0.2)"
    }),
    stroke: new Stroke({
      color: "black",
      width: 2,
      lineDash: [4, 4]
    }),
    image: new OLCircle({
      radius: 5,
      fill: new OLFill({
        color: "rgba(255,255,255,1)"
      })
    })
  });

  const style = [labelStyle];

  useEffect(() => {
    aircraftPoint.current = new Feature({
      name: "Aircraft name",
      geometry: new Point(fromLonLat([113.89076390019189, 22.324364815058356]))
    });

    trafficLayer.current = new VectorLayer({
      source: new VectorSource({
        features: [aircraftPoint.current]
      }),
      style: function (feature) {
        labelStyle.getText().setText(feature.get("name"));
        return style;
      }
    });

    new Map({
      target: mapRef.current,
      layers: [
        new TileLayer({
          source: new OSM()
        }),
        trafficLayer.current
      ],
      view: new View({
        center: fromLonLat([113.91, 22.32]),
        zoom: 14
      })
    });
  });

  useEffect(() => {
    let counter = 0;
    let intervalId = setInterval(() => {
      if (counter + 1 > coordinates.length - 1) {
        counter = 0;
      } else {
        counter = counter + 1;
      }
      moveAirplane(counter);
    }, 1000);
    return () => {
      clearInterval(intervalId);
    };
  }, []);

  return <div className="map" ref={mapRef} />;
};

Thanks!


Solution

  • The solution is to include updateWhileInteraction: true in the VectorLayer options.

    Thanks to Mike for providing the answer.