Add polyline on button click - reactjs

I'd like to add a poly line to my map but can't seem to get it to render on button click. Here is the code I currently have:
<button onClick={
function(){
console.log(asset.past);
var pathLine = new L.Polyline(asset.past, {
color: 'red',
weight: 3,
opacity: 0.5,
smoothFactor: 1
}
);
leafletMap.addLayer(pathLine);}
}
className="btn btn-info eachBtn">Go</button>
Thanks, Ed.

It appears that you're trying to manage the map state outside the context of react-leaflet. I'm not even sure if you're using the react-leaflet package or sort of trying to roll your own react website that happens to have leaflet.
If you are indeed using react-leaflet, you should be maintaining a list of polylines that you want to render in the component's state or a property that is updated and sent by a parent component. Then, in your render function you would iterate over these polylines and render each of them as react-leaflet polylines.
Something like this:
render() {
return (
<Map
center={[51.505, -0.09]}
zoom={13}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
{this.state.polylines.map((positions, idx) =>
<Polyline key={`polyline-${idx}`} positions={positions} />
)}
</Map>
);
}
Also, see the example over here of a similar react-leaflet application that adds markers after points are clicked on the map.

Related

React leaflet cannot update state

Building a React Leaflet app for first time, what I am trying to do is an onclick event on a layer that would update my state, the idea would be that the coordinates I add will modify state and I can then use this array to form a polygon. For some reasons I cannot make it work at the beginning of the project, this is the simplified code.
When clicking on one of the layers, I can console log all the information of the layer from the event no problem but cannot modify my state so I am thinking I might be rerendering. Can anyone spot the mistake? Thanks
const [coords, setCoords] = useState([])
const onclickevent = e => {
setCoords([...coords, e.target])
}
let givedata = (country, layer) => {
layer.on({click: onclickevent
});
};
<MapContainer className='leaflet-container' center={[48.85078290000001, 2.27537]} zoom={13} style={{ height: "100vh" }}>
<GeoJSON data={quartiersgeojson.features} onEachFeature={givedata}/>
<TileLayer
attribution='&copy OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>

Custom Marker as a React Component with react-google-maps-api

We are converting from google-map-react to react-google-maps-api which means more of a native Google Maps API experience.
Prior to the change, we were able to load a custom Marker as a React Component like:
<GoogleMaps>
<UserPinContainer lat={userLocation.lat} lng={userLocation.lng}>
<Tidal.Icon type="UserLocation" text="User" />
</UserPinContainer>
</GoogleMaps>
From their docs of our original lib google-map-react, it says:
Instead of the default Google Maps markers, balloons and other map components, you can render your cool animated react components on the map.
While that is great, it proves this library moves away from the native API...
However, with the new Marker API from react-google-maps-api, React Components are not possible. They only expect string | google.maps.Icon | google.maps.Symbol; types, such as:
<Marker
icon={{
path: google.maps.SymbolPath.CIRCLE,
scale: 7,
}}
position={centers[0]}
/>
or
<Marker position={{ lat: userLocation.lat, lng: userLocation.lng }}>
<Tidal.Icon img type="UserLocation" text="User" />
</Marker>
I thought I could create a true custom-marker like:
const newMarker = new window.google.maps.Marker(MyComponent)
but no such luck.
What would be a good solution for this?
Maybe it's a bit late to answer, but if it helps, you can use the OverlayView component instead of Marker, it works practically the same and you must pass a react component as children.
<GoogleMap
id="overlay-view-example"
mapContainerStyle={mapContainerStyle}
zoom={11}
center={center}
>
<OverlayView
position={center}
mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
>
<div style={divStyle}>
<h1>OverlayView</h1>
<button
onClick={onClick}
type='button'
>
Click me
</button>
</div>
</OverlayView>
</GoogleMap>
This is an example taken from the doc:
https://react-google-maps-api-docs.netlify.app/#overlayview

React leaflet How to have all markers with a specific icons but the one active with a different icon

So I am trying to have an active marker that is different from the rest of the non active marker.
So basically I want something like this.
To display all of the icon I am using the following.
that is displayed inside the map
{parkdata.features.map(park =>(
<Marker key = {park.properties.PARK_ID} position={[
park.geometry.coordinates[1],
park.geometry.coordinates[0]
]}
onClick={()=>{this.selected(park);
The selected function that was intended to be used to change the active icon. But it does not seem to be doing anything
selected(park){
return(
<Marker key = {park.properties.PARK_ID} position={[
park.geometry.coordinates[1],
park.geometry.coordinates[0]
]}
icon= {active}
/>
)
}
UPDATE:
This is what I have now.
SO when I click on one of the markers I want to change to a different icon. For now, it just does not do anything.
The following example demonstrates how to create a markers and update icon property on marker click:
function createIcon(url) {
return new L.Icon({
iconUrl: url,
});
}
function MapExample(props) {
const [selectedIndex, setSelectedIndex] = useState(-1);
function handleClick(e) {
setSelectedIndex(e.target.options.index) //get index via custom marker property
}
function getMarkerIcon(index) {
if(index === selectedIndex)
return createIcon("/bigcity_red.png");
return createIcon("/bigcity_green.png");
}
return (
<Map center={props.center} zoom={props.zoom}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
{props.data.map((item, index) => (
<Marker
key={index}
index={index}
position={item.position}
icon={getMarkerIcon(index)}
onclick={handleClick}
/>
))}
</Map>
);
}
Notes:
icon property for Marker component expects the value of L.Icon type
selectedIndex state is used to keep track of selected Marker (index)
Here is a demo for your reference

How to clear leaflet map in reactjs by button?

I want to clear my leaflet map by clicking a button...how to do this... I want to clear all drawed shapes on the map, so the map to be clear
This is my code of the leaflet map in the return statement:
<Map
key={this.state.keyMAP}
style={{ height: "50vh" }}
center={position}
zoom={13}
onClick={this.handleClick}
onCreate={this.onCreate}
onLocationfound={this.handleLocationFound}
>
{/* startDirectly */}
<TileLayer
attribution='© OpenStreetMap contributors'
url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
layers="NDVI"
// baseUrl="https://services.sentinel-hub.com/ogc/wms/bb1c8a2f-5b11-42bb-8ce4-dbf7f5300663"
/>
<FeatureGroup>
{viewMap && (
<EditControl
position="topleft"
onEdited={this._onEditPath}
onCreated={this.onCreate}
onDeleted={this._onDeleted}
onMounted={this._mounted}
onEditStart={this._onEditStart}
onEditStop={this._onEditStop}
onDeleteStart={this._onDeleteStart}
onDeleteStop={this._onDeleteStop}
draw={{
rectangle: false,
marker: false,
circleMarker: false,
circle: false,
circlemarker: false,
}}
/>
)}
</FeatureGroup>
</Map>
Button:
<button
className="waves-effect waves-light btn"
onClick={this.resetMap}
>
Clear map
</button>
Clear method:
resetMap() {
console.log("Reset");
}
Full code of my component:
https://github.com/SoilViews/SoilViews/blob/master/src/components/dashboard/Dashboard.js
I will propose two solutions so that you can choose whichever suits you best. You just need to create DOM references of your map/feature group in React(depends on the chosen method).
How to create a reference:
On your constructor, insert the following line:
this.mapRef = React.createRef(); // Create a Map reference
OR
this.fgRef = React.createRef(); // Create a Feature group reference
Then at your <Map> or <FeatureGroup> components you should add the following attributes accordingly:
<Map ref={this.mapRef}
key={this.state.keyMAP}
....rest of the code
OR
<FeatureGroup ref={this.fgRef}>
{viewMap && (
....rest of the code
If you choose the map clearing method, you can proceed like this:
function clearMap() {
const map = this.mapRef.current.leafletElement;
map.eachLayer(function (layer) {
map.removeLayer(layer);
});
}
Or, if you choose the Feature Group method:
function clearFeatureGroup() {
const fg = this.fgRef.current.leafletElement;
fg.clearLayers();
}
Finally, in your button you can call the according method:
<button onClick={clearMap}>
Clear!
</button>
OR
<button onClick={clearFeatureGroup}>
Clear!
</button>

Rendering react components inside popup of react-leaflet-draw drawn layer on react-leaflet

I'm trying to render some react components inside a layer created by react-leaflet-draw.
This is my attempt:
_onCreate(e) {
var layer = e.layer
layer.bindPopup(
<Content>
<Label>Flower Name</Label>
<Input type="text" placeholder="Flower Name"/>
<Label>Flower Index</Label>
<Input type="number" placeholder="Flower Index"/>
<Label>Flower Radius</Label>
<Input type="number" placeholder="Flower Radius"/>
<Button color="isSuccess" >Add Flower</Button>
</Content>
)
}
The components are supplied by react-bulma.
But I try this approach I get the following error:
Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
If I make the content a simple string I get plain HTML fields and a button but no access to external functions nor the actual Bulma components.
Essentially I want to be able to save the new shape on the database.
From a brief online search it seems that this is a limitation of react-leaflet, but I wanted to check here first.
Also, is this the best way to set a popup for a newly created shape? I'm having a hard time translating the regular leaflet-draw approaches to react-leaflet-draw.
It is possible to have react components inside a react-leaflet Popup. In your example you're using leaflet's API when instead you should be using react-leaflet's components. See the following example of showing a popup after clicking on a map:
const React = window.React;
const { Map, TileLayer, Marker, Popup } = window.ReactLeaflet;
let numMapClicks = 0
class SimpleExample extends React.Component {
state = {}
addPopup = (e) => {
this.setState({
popup: {
key: numMapClicks++,
position: e.latlng
}
})
}
handleClick = (e) => {
alert('clicked')
}
render() {
const {popup} = this.state
return (
<Map
center={[51.505, -0.09]}
onClick={this.addPopup}
zoom={13}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
{popup &&
<Popup
key={`popup-${popup.key}`}
position={popup.position}
>
<div>
<p>A pretty CSS3 popup. <br/> Easily customizable.</p>
<button onClick={this.handleClick}>Click Me!</button>
</div>
</Popup>
}
</Map>
);
}
}
window.ReactDOM.render(<SimpleExample />, document.getElementById('container'));
Here is a jsfiddle to demonstrate.

Resources