Showing full map on smaller screens in Material UI - javascript

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='&copy 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

Related

Marker position on the map Leaflet

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

How can I make the Leaflet Popup to show when i click on a list button

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='&copy 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

ReactJs Leaflet Marker Location Position Problem

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

react-leaflet-rotatedmarkers: TypeError: Super expression must either be null or a function, not object

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='&copy 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

Having trouble getting a custom zoom button in React-Leaflet

I'm trying to build my own Zoom button with react-leaflet
I have the following code:
import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import { Map, TileLayer } from 'react-leaflet';
import Control from 'react-leaflet-control';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import ZoomIn from 'material-ui/svg-icons/action/zoom-in';
import ZoomOut from 'material-ui/svg-icons/action/zoom-out';
class LeafletMap extends React.Component {
constructor(props) {
super(props);
this.state = {
animate: true,
center: [
-34.989610443115,
-71.232476234436
],
zoom: 13,
zoomControl: false
};
}
render() {
return (
<div>
<Map
animate={this.state.animate}
center={this.state.center}
zoom={this.state.zoom}
zoomControl={this.state.zoomControl}
>
<TileLayer
url={'http://{s}.tile.osm.org/{z}/{x}/{y}.png'}
attribution={'© OpenStreetMap'}
/>
<Control position="topleft">
<MuiThemeProvider>
<div>
<div> </div>
<FloatingActionButton mini={true}>
<ZoomIn onClick={ () => alert('Zoom In') } />
</FloatingActionButton>
<div> </div>
<FloatingActionButton mini={true}>
<ZoomOut onClick={ () => alert('Zoom Out') }/>
</FloatingActionButton>
</div>
</MuiThemeProvider>
</Control>
</Map>
</div>
);
}
}
export default LeafletMap;
All this is displaying good way, but now I want to to put a funcion where I can able to do zoom in or out. I don't have an idea how to call leaflet's methods using react-leaflet library.
I've tried many ways to implement it but without success.
Do you have any idea how to implement it?
There are a few ways to handle map functions/actions.
Pass via props
Many options are available via the Map's props(bounds, center, zoom). This way allows you to hold the zoom in your one state/store, instead of in leaflet.
const React = window.React;
const {
Map,
TileLayer,
Marker,
Popup
} = window.ReactLeaflet;
class ZoomInState extends React.Component {
constructor() {
super();
this.state = {
lat: 51.505,
lng: -0.09,
zoom: 13,
};
this.zoomIn = () => this.setState({zoom: this.state.zoom+1})
this.zoomOut = () => this.setState({zoom: this.state.zoom-1})
}
render() {
const position = [this.state.lat, this.state.lng];
return ( < Map center = {
position
}
zoom = {
this.state.zoom
}
>
< TileLayer attribution = '© OpenStreetMap contributors'
url = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png' / >
< Marker position = {
position
} >
< Popup >
< span >
<button onClick={this.zoomOut}>
Zoom out
</button >
< button onClick = {this.zoomIn} >
Zoom in
< /button>
< /span>
</Popup >
< /Marker>
</Map >
);
}
}
export default ZoomInState
Get map via refs
This way will not hold the zoom level in your component. Often this is a good practice, because it keeps a single source of truth. You can always get the zoom with map.getZoom()
const React = window.React;
const { Map, TileLayer, Marker, Popup } = window.ReactLeaflet;
class MapByRef extends React.Component {
constructor() {
super();
this.state = {
lat: 51.505,
lng: -0.09,
zoom: 13,
};
}
bindMap(el) {
this.map = el.leafletElement;
}
zoomIn() {
this.map.zoomIn();
}
zoomOut() {
this.map.zoomOut();
}
render() {
const position = [this.state.lat, this.state.lng];
return (
<Map center={position} zoom={this.state.zoom} ref={::this.bindMap}>
<TileLayer
attribution='© OpenStreetMap contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
<Marker position={position}>
<Popup>
<span>
<button onClick={::this.zoomIn} >Zoom In</button>
<button onClick={::this.zoomIn} >Zoom Out</button>
</span>
</Popup>
</Marker>
</Map>
);
}
}
export default MapByRef
3. Get from Context
This way is nice if you want to make many child components that need to interact with the map. It also keeps leaflet as the single source of truth.
const React = window.React;
const { Map, TileLayer, Marker, Popup } = window.ReactLeaflet;
class CustomMarker {
zoomIn(){
this.context.map.zoomIn()
}
zoomOut(){
this.context.map.zoomOut()
}
render() {
return (
<Marker position={position}>
<Popup>
<button onCLick={::this.zoomIn}>Zoom In</button>
<button onCLick={::this.zoomOut}>Zoom In</button>
</Popup>
</Marker>
)
}
}
export CustomMarker
class MapWithCustomChildren extends React.Component {
constructor() {
super();
this.state = {
lat: 51.505,
lng: -0.09,
zoom: 13,
};
}
render() {
const position = [this.state.lat, this.state.lng];
return (
<Map center={position} zoom={this.state.zoom}>
<TileLayer
attribution='© OpenStreetMap contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
<CustomMarker />
</Map>
);
}
}
export default MapWithCustomChildren

Categories

Resources