2

I'm working on an OpenLayers map that uses React as a wrapper for all the other UI stuff. As such, I'm also trying to component-ize some of the features, in this case the drawing.

Below is an attempt to recreate the example found in the OpenLayers documentation. What happens is that I get the draw surface, it does the drawing, but then once the drawing has been completed, nothing shows on the map.

I also have a living example of the behavior in a codesandbox.

MapComponent

import React, { Component, createRef } from "react";
import ReactDOM from "react-dom";
import Map from "ol/Map";
import View from "ol/View";
import OSM from "ol/source/OSM";
import TileLayer from "ol/layer/Tile";
import DrawingComponent from "./DrawingComponent";

class MapComponent extends Component {
  mapDomRef;
  map;

  constructor(...args) {
    super(...args);
    this.mapDomRef = createRef();
    this.map = new Map();
  }

  componentDidMount() {
    const view = new View({
      center: [-11000000, 4600000],
      zoom: 4
    });

    const rasterLayer = new TileLayer({
      source: new OSM()
    });

    this.map.addLayer(rasterLayer);
    this.map.setTarget(this.mapDomRef.current);
    this.map.setView(view);
  }

  render() {
    return (
      <div className="App">
        <div ref={this.mapDomRef} />

        <DrawingComponent map={this.map} />
      </div>
    );
  }
}

DrawingComponent

import React, { Component } from "react";
import ReactDOM from "react-dom";
import Draw from "ol/interaction/Draw";
import { Vector as VectorSource } from "ol/source";
import { Vector as VectorLayer } from "ol/layer";

class DrawingComponent extends Component {
  state = {
    geomType: "None"
  };

  constructor(...args) {
    super(...args);
    this.source = new VectorSource({ wrapX: false });
    this.layer = new VectorLayer({ source: this.source });
  }

  handleGeomChange = event => {
    const geomType = event.target.value;
    this.setState(({ draw }) => {
      if (draw) {
        this.props.map.removeInteraction(draw);
      }

      return { geomType, draw: this.addInteraction(geomType) };
    });
  };

  addInteraction(geomType) {
    if (geomType !== "None") {
      const draw = new Draw({
        source: this.source,
        type: geomType
      });

      this.props.map.addInteraction(draw);
      return draw;
    }
  }

  render() {
    return (
      <form class="form-inline">
        <label>Geometry type &nbsp;</label>
        <select
          id="type"
          value={this.state.geomType}
          onChange={this.handleGeomChange}
        >
          <option value="Point">Point</option>
          <option value="LineString">LineString</option>
          <option value="Polygon">Polygon</option>
          <option value="Circle">Circle</option>
          <option value="None">None</option>
        </select>
      </form>
    );
  }
}

export default DrawingComponent;

EDIT: Applied suggestion to use the same source that's on the map, which meant, to also add the layer, which I wasn't doing before.

jktravis
  • 1,427
  • 4
  • 20
  • 36

1 Answers1

0

Check if you have added the vector layer before the raster layer. If you add the vector layer first, the raster layer will render over top of the vectors.

David Buck
  • 3,752
  • 35
  • 31
  • 35
  • 1
    The only thing that has ever seemed to work is passing the map through the React's context API. Props just don't seem to do it. – jktravis Mar 25 '20 at 21:31