0

I'm trying to code a modified version of this example.

Using vanilla Javascript all is working fine, but now I'm trying to move it to React and the popup doesn't follow the map when I zoom in or zoom out the map. I suppose that the popup is not linked to the map overlay, but it's totally disconnected from it and this should be the problem, but I don't know how to fix it:

The generated html

This is my code:

import 'ol/ol.css';
import React, { Component } from "react";
import ReactDOM from 'react-dom';
import Map from 'ol/Map';
import View from 'ol/View';
import Overlay from 'ol/Overlay';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { OSM, Vector as VectorSource } from 'ol/source';
import { Circle as CircleStyle, Icon, Fill, Stroke, Style, Text } from 'ol/style';
import GeoJSON from 'ol/format/GeoJSON';
import * as olExtent from 'ol/extent';
import $ from 'jquery';
import 'bootstrap';
import markerLogo from './marker.png';


class PublicMap extends Component {
  constructor(props) {
    super(props);

    var shapeDisciplinare = this.props.geoJson;

    var iconStyle = new Style({
      image: new Icon({
        anchor: [0.5, 46],
        anchorXUnits: 'fraction',
        anchorYUnits: 'pixels',
        src: markerLogo
      }),
      text: new Text({
        font: '12px Calibri,sans-serif',
        fill: new Fill({ color: '#000' }),
        stroke: new Stroke({
          color: '#fff', width: 2
        })
      })
    });


    var getStyles = function (feature) {
      var myStyle = {
        'Point': iconStyle,
        'Polygon': new Style({
          stroke: new Stroke({
            color: 'blue',
            width: 3
          }),
          fill: new Fill({
            color: 'rgba(0, 0, 255, 0.1)'
          }),
          text: new Text({
            font: '12px Calibri,sans-serif',
            fill: new Fill({ color: '#000' }),
            stroke: new Stroke({
              color: '#fff', width: 2
            }),
            text: feature.getProperties().denominazione
          })
        })
      };
      return [myStyle[feature.getGeometry().getType()]];

    };

    var raster = new TileLayer({
      source: new OSM()
    });

    var source = new VectorSource();
    var vector = new VectorLayer({
      source: source,
      style: new Style({
        fill: new Fill({
          color: 'rgba(255, 255, 255, 0.2)'
        }),
        stroke: new Stroke({
          color: '#ffcc33',
          width: 2
        }),
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({
            color: '#ffcc33'
          })
        })
      })
    });
    vector.setZIndex(1);

    this.olmap = new Map({
      layers: [raster, vector],
      target: null,
      view: new View({
        center: [-11000000, 4600000],
        zoom: 4
      })
    });

    var reader = new GeoJSON({
      defaultDataProjection: 'EPSG:3857',
      Projection: 'EPSG:3857'
    });

    var projector = {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:3857'
    };

    let shapeDisciplinareJson = JSON.parse(shapeDisciplinare);
    var vectorSource = new VectorSource({
      features: reader.readFeatures(shapeDisciplinareJson, projector)
    });

    var vectorLayer = new VectorLayer({
      source: vectorSource,
      style: getStyles
    });

    this.state = { vs: vectorSource, vl: vectorLayer };
  }

  componentDidMount() {

    this.olmap.setTarget("map");
    var extent = olExtent.createEmpty();
    extent = olExtent.extend(extent, this.state.vs.getExtent());
    this.olmap.addLayer(this.state.vl);
    this.olmap.getView().fit(extent, this.olmap.getSize());
    this.olmap.getView().setZoom(8);

    var element = document.getElementById('popup');
    this.popup = new Overlay({
      element: ReactDOM.findDOMNode(this).querySelector('#popup'),
      positioning: 'bottom-center',
      stopEvent: false,
      offset: [0, -50]
    });

    // display popup on click
    this.olmap.on('click', (evt) => {
      var feature = this.olmap.forEachFeatureAtPixel(evt.pixel,
        (feature) => {
          return feature;
        });
      if (feature) {
        var coordinates = feature.getGeometry().getCoordinates();
        //if lenght is 2, then is a gps location, otherwise a shape
        if (coordinates.length === 2) {
          this.popup.setOffset([0, -50]);
          this.popup.setPosition(coordinates);
        } else {
          this.popup.setOffset([0, 0]);
          this.popup.setPosition(evt.coordinate);
        }
        this.olmap.addOverlay(this.popup);
        $(element).popover({
          'placement': 'top',
          'html': true,
          'content': feature.getProperties().denominazione
        });
        $(element).attr('data-content', feature.getProperties().denominazione);
        $(element).popover('show');
      } else {
        $(element).popover('hide');
      }

    });

    // change mouse cursor when over marker
    this.olmap.on('pointermove', (e) => {
      if (e.dragging) {
        $(element).popover('hide');
        return;
      }
      var pixel = this.olmap.getEventPixel(e.originalEvent);
      var hit = this.olmap.hasFeatureAtPixel(pixel);
      this.olmap.getTargetElement().style.cursor = hit ? 'pointer' : '';
    });


  }

  componentWillUnmount() {
    this.map.setTarget(null);
  }

  render() {
    return (
      <div id="map" style={{ width: "100%", height: "360px" }}>
        <div id="popup"></div>
      </div>
    );
  }
}

export default PublicMap;
Accollativo
  • 1,537
  • 4
  • 32
  • 56
  • This may not be the problem but `(coordinates.length === 2)` is not a reliable test as a linestring with 2 vertices, a polygon with 2 linear rings or a multigeometry with 2 elements would also match. `(feature.getGeometry().getType() === 'Point')` would be more reliable. Also you should call `$(element).popover('hide');` to remove the previous popup before showing a new one (unless as in the OpenLayer example it can only be in one location). – Mike Feb 14 '20 at 17:09
  • Thank you, it's not the solution but a little improve to the code could be useful. – Accollativo Feb 14 '20 at 19:43

0 Answers0