Closed BjoernRave closed 5 years ago
@BjoernRave at first you need import leaflet.pm files at root file of your project
import 'leaflet.pm/dist/leaflet.pm.css';
import 'leaflet.pm';
Then you need add ref to yours map component
<Map ref={(c) => { this.map = c }} ...
after this you can access map object in componentDidMount() and add toolbar and listeners to pm actions
componentDidMount() {
if (typeof L !== 'undefined') {
const map = this.map.leafletElement;
map.pm.addControls({
position: 'topleft',
drawCircle: false,
});
layer.on('pm:create', e => {
let newFeature = e.layer.toGeoJSON();
dispatch({type: 'NEW_LAYER', payload: newFeature});
layer.removeLayer(e.layer); // Remove temporary layer
...
@TPABHuKOB first of all thanks alot for helping me, but when I try to import leaflet.pm I get the error ReferenceError: Element is not defined
. I am using next.js by the way. I'm not sure what its refering to though and searching it was not very helpful...
@BjoernRave I'm using leaflet.pm with nuxtJS, which is the next.js equivalent in the vue.js world.
But I don't use react-leaflet
nor vue-leaflet
.
What's important is that leaflet and leaflet.pm are only initiated when the context of your application is the browser. In next.js, I assume your import of leaflet.pm is executed on the serverside. That might be handled by react-leaflet
automatically for you.
Import leaflet.pm in the browser context only and it should work fine. Let me know how it goes.
(Will close the issue as it's not a problem to fix here but we can keep the discussion going to help you)
I'm trying to integrate to react too, but I get TypeError: L.PM is undefined
. Any idea ?
In case someone still has this issue. Here is an example of how I integrated with react-leaflet
(using TypeScript) by creating a custom component. The component adds circle drawing that I use for filtering in another component.
import React from 'react';
import { Map, MapProps } from 'react-leaflet';
import L from 'leaflet';
import '@geoman-io/leaflet-geoman-free';
import '@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css';
type PMDrawCircleEvent = { layer: L.Circle & { pm: { enable: () => void } } };
type PMEditCircleEvent = { target: L.Circle };
interface Props extends MapProps {
onSelectionCircleAdded: (latLang: L.LatLng, radius: number) => void;
onSelectionCircleMoved: (latLang: L.LatLng, radius: number) => void;
onSelectionCircleRemoved: () => void;
}
const MapWithGeoman: React.FC<Props> = (props) => {
const {
children,
onSelectionCircleAdded: onCircleAdded,
onSelectionCircleMoved: onCircleMoved,
onSelectionCircleRemoved: onCircleRemoved,
...mapProps
} = props;
const leafletMapRef = React.useRef<Map>(null);
const filtersLayerRef = React.useRef<L.LayerGroup<L.Circle>>();
React.useEffect(() => {
if (leafletMapRef.current) {
const mapElement = leafletMapRef.current.leafletElement;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(mapElement as any).pm.addControls({
drawMarker: false,
drawCircleMarker: false,
drawPolyline: false,
drawRectangle: false,
drawPolygon: false,
editMode: false,
dragMode: false,
cutPolygon: false,
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(mapElement as any).pm.setGlobalOptions({ pmIgnore: false });
filtersLayerRef.current = L.layerGroup().addTo(mapElement);
mapElement.on('pm:create', (e) => {
// only show one selection circle
filtersLayerRef.current?.clearLayers();
if (
e.layer &&
e.layer.pm &&
filtersLayerRef.current?.getLayers.length === 0
) {
const circle = (e as unknown) as PMDrawCircleEvent;
// enable editing of circle
circle.layer.pm.enable();
filtersLayerRef.current?.addLayer(circle.layer);
onCircleAdded(circle.layer.getLatLng(), circle.layer.getRadius());
circle.layer.on('pm:edit', (e) => {
const event = (e as unknown) as PMEditCircleEvent;
onCircleMoved(event.target.getLatLng(), event.target.getRadius());
});
}
});
mapElement.on('pm:remove', () => {
onCircleRemoved();
});
}
});
return (
<Map ref={leafletMapRef} {...mapProps}>
{children}
</Map>
);
};
export default MapWithGeoman;
@jeppe-style is there codesandbox available for playing with it. !!
@ddprajapati I created a code sandbox here. Note that it at the moment it only works with v2.5. Filed a separate issue about that #640.
Hi this react geoman code is not working properly and i need an arc layer
import React, { Component } from "react";
import { Map, Marker, Popup, FeatureGroup,LayersControl,TileLayer,Polyline } from "react-leaflet";
import ReactLeafletGoogleLayer from "react-leaflet-google-layer";
import { EditControl } from "react-leaflet-draw";
import L from "leaflet";
import "leaflet-routing-machine/dist/leaflet-routing-machine.css";
import "leaflet-routing-machine";
import { withLeaflet } from "react-leaflet"
import './centre.css'
import Routing from "./Routing";
import * as ELG from "esri-leaflet-geocoder";
const { BaseLayer } = LayersControl;
// import marker icons
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl:
"https://unpkg.com/leaflet@1.4.0/dist/images/marker-icon-2x.png",
iconUrl: "https://unpkg.com/leaflet@1.4.0/dist/images/marker-icon.png",
shadowUrl: "https://unpkg.com/leaflet@1.4.0/dist/images/marker-shadow.png"
});
class Path extends Component {
constructor(props) {
super(props);
this.state = {
lat: 17.3850 ,
lng: 78.4867,
zoom: 13,
marker: [17.3850 ,78.4867]
};
}
componentDidMount() {
const map = this.leafletMap.leafletElement;
const searchControl = new ELG.Geosearch().addTo(map);
const results = new L.LayerGroup().addTo(map);
const Polyline = L.Polyline.Arc([43.11667, 131.90000], [55.7522200, 37.6155600]).addTo(map);
searchControl.on("results", function(data) {
results.clearLayers();
for (let i = data.results.length - 1; i >= 0; i--) {
results.addLayer(L.marker(data.results[i].latlng));
}
});
}
terrain = "TERRAIN";
key = "AIzaSyC0QH9aiCXuuRjJe4k5lzAM2bYl-MUhiPk";
removeEverything = e => {
console.log(e);
const { lat, lng } = e.layer._latlng;
this.setState({ marker: [lat, lng] });
const { edit } = this.refs;
var layerContainer = edit.leafletElement.options.edit.featureGroup;
const layers = layerContainer._layers;
const layer_ids = Object.keys(layers);
layer_ids.splice(0, 1);
layer_ids.forEach(id => {
const layer = layers[id];
layerContainer.removeLayer(layer);
});
};
setPos = () => {
this.setState({ marker: [17.3850, 78.4867] });
};
handleOnZoomed = e => {
this.setState({ zoom: e.target._zoom });
};
render() {
const position = [this.state.lat, this.state.lng];
const center = [17.3850, 78.4867];
return (
<div>
<pre>{JSON.stringify(this.state)}</pre>
<button onClick={this.setPos}>remove</button>
<Map
center={this.state.marker}
zoom={this.state.zoom}
onzoomend={this.handleOnZoomed}
ref={m => {
this.leafletMap = m;
}}
>
<Marker
position={this.state.marker}
defaultMarker={{ position: true }}
>
</Marker>
<TileLayer
attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<FeatureGroup>
<EditControl
ref="edit"
position="topright"
onCreated={this.removeEverything}
CircleMarker ="true"
removalMode ="true"
pinningOption ="true"
snappingOption = "true"
draw={{
rectangle: true,
polygon:true,
CircleMarker:true,
removalMode:true,
pinningOption:true,
snappingOption:true
}}
/>
</FeatureGroup>
{/* <ReactLeafletGoogleLayer
googleMapsLoaderConf={{ KEY: this.key }}
type={"satellite"}
/> */}
<div className="pointer" />
</Map>
</div>
);
}
}
export default Path`
@jeppe-style
@ddprajapati I created a code sandbox here. Note that it at the moment it only works with v2.5. Filed a separate issue about that #640.
Fixed in Release: 2.7.0
@ddprajapati I created a code sandbox here. Note that it at the moment it only works with v2.5. Filed a separate issue about that #640.
Fixed in Release:
2.7.0
Just downloaded the code from Sandbox and tried to start, but I'm getting this error:
Failed to compile.
./src/App.tsx
Line 0: Parsing error: Cannot read property 'map' of undefined
Could you please help?
Hey, I was wondering if this library is compatible with react-leaflet or if somebody knows how to make it work with react (and maybe even next.js)