I am trying to add a map in my reactjs project with leaflet and want to show the location's of vehicles on the map. I made a sample usage for this. But When i used marker on the map i see that (as you can see in this image):
marker's left top side stick to my location. I want to see marker's bottom on the center of my location as the circle is. But i could not do it. I read react-leaflet documentation but did not see a parameter for this. If you help me, I appreciate for this. Thanks
import React, { Component } from 'react'
import Leaflet from 'leaflet';
import { Map, CircleMarker, TileLayer, Marker, Popup } from 'react-leaflet'
import 'leaflet/dist/leaflet.css';
import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';
let DefaultIcon = Leaflet.icon({
iconUrl: icon,
shadowUrl: iconShadow
});
Leaflet.Marker.prototype.options.icon = DefaultIcon;
class SimpleExample extends React.Component {
constructor(props) {
super();
this.state = {
lat: 39.9653301,
lng: 32.7760817,
zoom: 5,
markerPoint: {
x: 320,
y: 192
}
};
this.refMap = React.createRef();
}
render() {
const { lat, lng, zoom } = this.state;
const position = [lat, lng];
return (
<Map ref={this.refMap} center={position} zoom={zoom} style={{ height: '400px', width: '100%' }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
<Marker position={position} draggable="True" pane="popupPane" >
</Marker>
<CircleMarker
center={position}
color='green'
fillColor='red'
radius={20}
fillOpacity={0.5}
stroke={false}
>
<Popup>
<span>A pretty CSS3 popup. <br/> Easily customizable.</span>
</Popup>
</CircleMarker>
</Map>
);
}
}
export default SimpleExample;
Define proper iconAnchor size and marker will be placed on the correct location.
let DefaultIcon = Leaflet.icon({
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40],
iconUrl: icon,
shadowUrl: iconShadow
});
Demo
Related
I have a custom map created using the Leaflet library. And also the Marker component. When I place a marker with a value of 100 on the Y-axis, the marker is at the top of the map, but when I place a marker on the Y-axis of 50, the marker is not in the middle of the map. Same thing with the X-axis. How can I find the exact coordinates of the map, what can I do to position the marker according to the coordinates passed from the backend?
Code from component App
import "./styles.css";
import { MapContainer, ImageOverlay } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import Marker from "./Marker";
const M = ({ width, height, zoom, center }) => {
const wh = [width, 500];
const origin = [0, 0];
const bounds = [origin, wh];
return (
<div style={{ width: "1100px", height: "600px" }}>
<MapContainer
style={{ height: "100%", minHeight: "100%" }}
bounds={zoom ? undefined : bounds}
boundsOptions={{
padding: [0, 0]
}}
maxBounds={bounds}
zoom={center ? zoom : undefined}
center={zoom ? center : undefined}
>
<ImageOverlay
url="../ptichnikDraw.png"
bounds={bounds}
className="map_main"
/>
<Marker />
</MapContainer>
</div>
);
};
const App = () => {
return (
<div
style={{
display: "flex",
justifyContent: "center"
}}
>
<M width={1500} height={500} center={[0, 0]} />
</div>
);
};
export default App;
Code from component Marker
import { LeafletTrackingMarker } from "react-leaflet-tracking-marker";
import L from "leaflet";
import { Popup } from "react-leaflet";
const icon = L.icon({
iconSize: [35, 35],
popupAnchor: [2, -20],
iconUrl: require("../public/marker_map.png")
});
export default function Marker() {
return (
<>
<LeafletTrackingMarker
icon={icon}
position={[50, 450]} // changing the position of the marker
duration={10}
></LeafletTrackingMarker>
</>
);
}
Link to full code: https://codesandbox.io/s/dark-worker-8qbzfr?file=/src/Marker.jsx
I have read several posts here on stackoverflow like React Leaflet - How to render custom image using Circle Markers
and
custom marker icon with react-leaflet
On how to include custom icons in react leaflet maps. I have tried the below code
const newicon = new L.icon({
iconUrl: require('../assets/Download-Image.png'),
iconSize: [30, 30]
})
but the image does not render on the map.
However, if I use the url of the same icon as below it works and renders. Any advise on what I could be doing wrong?
const newicon = new L.icon({
iconUrl: 'https://www.somewebsite/Download-Image.png',
iconSize: [30, 30]
})
You should not place require between '': only the image path inside require.
const newicon = new L.icon({
iconUrl: require("./assets/marker.png"),
iconSize: [30, 30]
});
export default function App() {
const position = [51.505, -0.09];
return (
<Map center={position} zoom={13} style={{ height: "500px" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
<Marker position={position} icon={newicon}>
<Popup>
A pretty CSS3 popup.
<br />
Easily customizable.
</Popup>
</Marker>
</Map>
);
}
Another approach, which is mostly used would be to import the image like below:
import marker from "./assets/marker.png";
and then use it like this:
const newicon = new L.icon({
iconUrl: marker,
iconSize: [30, 30]
});
Demo
I am trying to make my app responsive for smaller screens. On bigger screens, I have the <List> buttons for large screens but when the screen size is xs(mobile), I want that the whole screen should be covered with the map. I am able to hide the list in smaller screens but since I am using map width to be 80% the sm screens only cover 80% for the map and 20% is just white screen. How can I bring the map to 100% on sm screen
...
import React from "react";
import { List, ListItem } from "#material-ui/core";
import { Map, Marker, Popup, TileLayer } from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import "./styles.css";
import Icon from "../src/icon.png";
import shadow from "../src/shadow.png";
import Hidden from "#material-ui/core/Hidden";
export default class App extends React.Component {
constructor() {
super();
this.state = {
location: [
{
id: 1,
machine: 1,
lat: 51.503,
lng: -0.091
},
{
id: 2,
machine: 2,
lat: 51.543,
lng: -0.051
}
],
center: [51.505, -0.091],
zoom: 11,
marker: null
};
this.clickAction = this.clickAction.bind(this);
}
Icon = L.icon({
iconUrl: Icon,
shadowUrl: shadow,
iconSize: [38, 50],
shadowSize: [50, 64],
iconAnchor: [22, 34], // point of the icon which will correspond to marker's location
shadowAnchor: [4, 62],
popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
});
openPopUp(marker, id) {
if (marker && marker.leafletElement) {
marker.leafletElement.openPopup(id);
}
}
clickAction(id, lat, lng) {
this.setState({ marker: id, zoom: 16, center: [lat, lng] });
}
render() {
console.log(this.state);
return (
<>
<Map center={this.state.center} zoom={this.state.zoom}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
{this.state.location &&
this.state.location.map(location => {
return location !== null ? (
<Marker
position={[location?.lat, location?.lng]}
icon={this.Icon}
ref={this.openPopUp(location?.id)}
>
<Popup> {location?.id} </Popup>
</Marker>
) : null;
})}
</Map>
{
<Hidden smDown>
<List style={{ width: "20%", float: "left" }}>
{this.state.location &&
this.state.location.map(({ id, machine, lat, lng }) => {
return (
<ListItem
key={id}
button
onClick={() => {
this.clickAction(id, lat, lng);
}}
>
Id {id} <br />
machine {machine}
</ListItem>
);
})}
</List>
</Hidden>
}
</>
);
}
}
}
...
my sample is https://codesandbox.io/s/gallant-star-m42qe?file=/src/App.js
I am trying to test something with react leaflet. I am displaying 2 different machines on map and when i click a specific list button(distinguished by machine id), it moves the center of the map to the position coordinates of that machine. The popups are already added but they only shows when i click the marker on map. I want the Popup to show automatically whenever I click the list button(currently I have to click on the marker on map for it to popup) and it should close like it's usual normal behavior(this is by default). Any idea how can I do this?
PS: I have tried to use refs and even with that it is working partially.
...
export default class App extends React.Component {
constructor() {
super();
this.state = {
location: [
{
id: 1,
machine: 1,
lat: 51.503,
lng: -0.091
},
],
};
}
Icon = L.icon({
iconUrl: Icon,
shadowUrl: shadow,
iconSize: [38, 50],
shadowSize: [50, 64],
iconAnchor: [22, 34], // point of the icon which will correspond to marker's location
shadowAnchor: [4, 62],
popupAnchor: [-3, -76] // point from which the popup should open relative to the iconAnchor
});
openPopUp(marker, id) {
if (marker && marker.leafletElement) {
marker.leafletElement.openPopup(id);
}
}
clickAction(id, lat, lng) {
this.setState({ marker: id, zoom: 16, center: [lat, lng] });
}
render() {
console.log(this.state);
return (
<>
<Map center={this.state.center} zoom={this.state.zoom}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
/>
{this.state.location.map(({ lat, lng, id }) => {
return (
<Marker
position={[lat, lng]}
icon={this.Icon}
ref={this.openPopUp(id)}
>
<Popup> {id} </Popup>
</Marker>
);
})}
</Map>
{
<List style={{ width: "20%", float: "left" }}>
{this.state.location.map(({ id, machine, lat, lng }) => {
return (
<ListItem
key={id}
button
onClick={() => {
this.clickAction(id, lat, lng);
}}
>
Id {id} <br />
machine {machine}
</ListItem>
);
})}
</List>
}
</>
);
}
}
...
The way you're defining your refs is not going to work. Beause you're trying to add refs in a map statement, you need an array to keep track of those refs. In your constructor:
this.markerRefs = []
Then in each marker, add the ref to that array:
<Marker
position={[lat, lng]}
icon={this.Icon}
ref={ref => this.markerRefs[id] = ref} >
{ ... }
</Marker>
Now that your markers have unique references, you can use them in your clickAction function:
clickAction(id, lat, lng) {
this.setState({ marker: id, zoom: 16, center: [lat, lng] });
this.markerRefs[id].leafletElement.openPopup()
}
Here is a working codesandbox
as you can see in the topic is my problem that when i want to import react-leaflet-rotatedmarker, only importing, my react webapplication throws me this message.
I'm using react-leaflet v2.1.2.
Here is a snippet of my js code:
import React, { Component } from 'react';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import L, { map, addTo } from 'leaflet';
import RotatedMarker from 'react-leaflet-rotatedmarker'
import './App.css'
//importing marker/icon
var ego_veh_icon = L.icon({
iconUrl: require('./design/icons/ego_veh_arrow.svg'),
iconSize: [150, 200],
iconAnchor: [82.5, 40],
popupAnchor: [0, -25],
});
var av_veh_icon = L.icon({
iconUrl: require('./design/icons/autonom_veh_arrow.svg'),
iconSize: [150, 200],
iconAnchor: [82.5,55],
popupAnchor: [-5, -25],
});
var nav_veh_icon = L.icon({
iconUrl: require('./design/icons/non_autonom_veh_arrow.svg'),
iconSize: [150, 200],
iconAnchor: [82.5, 60],
popupAnchor: [-10, -25],
});
class Map_hmi extends Component {
constructor() {
super();
this.state = {
markers: [[x, y]],
param: null,
};
}
// ego veh position
ego_veh = {
lat: x,
lng: y,
}
// nav veh position
nav_veh = {
lat: x,
lng: y,
}
// av veh1 position
av_veh1 = {
lat: x,
lng: y,
}
// av veh2 position
av_veh2 = {
lat: x
lng: y,
}
render() {
const ego_veh_pos = [this.ego_veh.lat, this.ego_veh.lng]
const nav_veh_pos = [this.nav_veh.lat, this.nav_veh.lng]
const av_veh1_pos = [this.av_veh1.lat, this.av_veh1.lng]
const av_veh2_pos = [this.av_veh2.lat, this.av_veh2.lng]
return (
// declaring the map
<Map
className="map"
center={ego_veh_pos}
zoom={15}
zoomControl={false}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{/* <RotatedMarker position={position} rotationAngle={180} rotationOrigin={'center'} /> */}
{/* ego veh */}
<Marker
position={ego_veh_pos}
icon= {ego_veh_icon}>
<Popup>
EGO <br/>
</Popup>
</Marker>
{/* nav veh */}
<Marker
position={nav_veh_pos}
icon= {nav_veh_icon}>
<Popup>
NAV <br/>
</Popup>
</Marker>
{/* av veh1 */}
<Marker
position={av_veh1_pos}
icon= {av_veh_icon}>
<Popup>
AV <br/>
</Popup>
</Marker>
{/* av veh2 */}
<Marker
position={av_veh2_pos}
icon= {av_veh_icon}>
<Popup>
AV <br/>
</Popup>
</Marker>
)}
</Map>
);
}
}
export default Map_hmi;
So my code works fine without the import, but as soon as I import it:
TypeError: Super expression must either be null or a function, not object
I only want to rotate the icon ....
Any help?
Greetings
The provided another answer seems to be correct, react-leaflet-rotatedmarker package is not compatible with react-leaflet v2 package.
For react-leaflet v2 library, RotatedMarker component could be implemented like this (offers same behavior as react-leaflet-rotatedmarker package):
import React, { Component } from "react";
import { withLeaflet } from "react-leaflet";
import { Marker } from "react-leaflet";
import { Marker as LeafletMarker } from 'leaflet-rotatedmarker';
const RotatedMarker = props => {
const setupMarker = marker => {
if (marker) {
if (props.rotationAngle)
marker.leafletElement.setRotationAngle(props.rotationAngle);
marker.leafletElement.setRotationOrigin(props.rotationOrigin);
}
};
return <Marker ref={el => setupMarker(el)} {...props} />;
};
RotatedMarker.defaultProps = {
rotationOrigin: "center"
};
export default withLeaflet(RotatedMarker);
Demo page
tldr: Using the code in this comment should fix your problem. https://github.com/verdie-g/react-leaflet-rotatedmarker/issues/1#issuecomment-427285940
Longer answer:
react-leaflet v2 has a very major breaking change from v1 in the way extensions of components are done. If you look at the code for react-leaflet-rotatedmarker you'll see this line: https://github.com/verdie-g/react-leaflet-rotatedmarker/blob/master/src/RotatedMarker.jsx#L5
That extension of the Marker class does not work in v2 and is what's throwing that error. For more info on why that is you can check out the issue I raised in the react-leaflet repo. https://github.com/PaulLeCam/react-leaflet/issues/506