Is there a way to center text inside a polygon in Leaflet? - reactjs

I have GeoJSON that has names and polygons for every country in the world. I have successfully rendered polygons (which is basically world map) but I don't know how to show names of countries inside each polygon. It would be also nice if I could show names only if they fit inside a polygon based on zoom level. I know i can get polygon center with const center = layer.getBounds().getCenter(); but I just don't know what to do with it. This is my code so far
import React, { Component } from "react";
import { MapContainer, GeoJSON } from "react-leaflet";
import countriesData from "../data/countries.json";
import "leaflet/dist/leaflet.css";
import "./Map.css";
export default class Map extends Component {
onEachCountry = (country, layer) => {
const countryName = country.properties.ADMIN;
layer.on({
mouseover: (e) => {
e.target.setStyle({
color: "red",
});
},
mouseout: (e) => {
e.target.setStyle({
color: "black",
});
},
});
};
render() {
return (
<div>
<MapContainer style={{ height: "80vh" }} center={[0, 0]} zoom={1.5}>
<GeoJSON
style={{
color: "black",
weight: 1,
}}
data={countriesData.features}
onEachFeature={this.onEachCountry}
></GeoJSON>
</MapContainer>
</div>
);
}
}

Related

I have used circle marker to show places on a world map in react. How to add popup on circle marker to shows up the location when circle is clicked?

I have used circle marker to show places on a world map in react. How to add popup on circle marker to show details when circle is clicked. Currently the code shows a interactive map with circle marker for locations and countries are highlighted when clicked on using tool tip
import React, { memo } from "react";
import classes from "./MapChart.module.css"
import {
ZoomableGroup,
ComposableMap,
Geographies,
Geography,
Marker,
} from "react-simple-maps";
import ReactTooltip from "react-tooltip";
//cities and their longitude and latitude
const markers = [
{
markerOffset: -20,
name: "Sao Paulo",
coordinates: [-58.3816, -34.6307],
},
const geoUrl =
"https://raw.githubusercontent.com/zcreativelabs/react-simple-maps/master/topojson-
maps/world-110m.json";
//creating interactive world map
const MapChart = ({ setTooltipContent }) => {
return (
<>
<ComposableMap data-tip="" projectionConfig={{scale: 200}}>
<ZoomableGroup zoom = {2}>
<Geographies geography={geoUrl}>
{({geographies}) =>
geographies.map(geo => (
<Geography
key={geo.rsmKey}
geography={geo}
onMouseEnter={() => {
const {NAME} = geo.properties;
setTooltipContent(`${NAME}`);
}}
onMouseLeave={() => {
setTooltipContent("");
}}
//This is where the output to console occurs.
onClick={() => {
const {NAME} = geo.properties;
console.log(NAME);
}}
style={{
default: {
fill: "#D6D6DA",
outline: "none"
},
hover: {
fill: "#F53",
outline: "none"
},
pressed: {
fill: "#E42",
outline: "none"
}
}}
/>
))
}
</Geographies>
//adding circle marker on the map
{
markers.map(({name, coordinates, markerOffset})=>(
<Marker key ={name} coordinates={coordinates}>
<circle r={5} fill= "#F00" stroke= "#fff" strokeWidth={1}/>
<text textAnchor="middle"
y={markerOffset}
style={{fontFamily: "system-ui",fill: "#5D5A6D" }}
>
{name}
</text>
</Marker>
))}
</ZoomableGroup>
</ComposableMap>
</>
);
};
export default memo(MapChart);

How to add image grid list to class?

So what I'm trying to do is to add the single line grid list from here:
https://github.com/mui-org/material-ui/blob/master/docs/src/pages/components/grid-list/SingleLineGridList.js
to the following class:
import React from 'react';
import { withTranslation } from 'react-i18next';
import '../css/home.css';
import Navbar from '../components/Navbar'
import ImgsViewer from 'react-images-viewer'
import image1 from '../resources/examples/1.jpg'
import image2 from '../resources/examples/2.jpg'
import { makeStyles } from '#material-ui/core/styles';
import GridList from '#material-ui/core/GridList';
import GridListTile from '#material-ui/core/GridListTile';
import GridListTileBar from '#material-ui/core/GridListTileBar';
import IconButton from '#material-ui/core/IconButton';
import StarBorderIcon from '#material-ui/icons/StarBorder';
import tileData from './tileData';
class HomeReal extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen : false,
};
}
render(){
const { t } = this.props;
const state = {
isOpen : false,
}
return(
... html code
);
}
}
export default withTranslation()(HomeReal);
I'm really NEW to react so I barely have some understanding.
I already added the neccesary imports.
And now I don't know how to proceed.
I simply want that image list from Material inside my HTML. I've tried several things but I always get compilation errors.
Can you at least give me a hint?
Try this out exactly this will help you
1. create a folder name Assets then copy-paste all your
desired images in that folder
2. then import like this below(see code in import section)
3. then follow the code
4. it worked for me
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import GridList from "#material-ui/core/GridList";
import GridListTile from "#material-ui/core/GridListTile";
import GridListTileBar from "#material-ui/core/GridListTileBar";
import IconButton from "#material-ui/core/IconButton";
import StarBorderIcon from "#material-ui/icons/StarBorder";
import game from "../Assets/game.jpeg";
import ME from "../Assets/ME.JPG";
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
flexWrap: "nowrap",
// Promote the list into his own layer on Chrome. This cost memory but helps keeping high FPS.
transform: "translateZ(0)",
},
title: {
color: theme.palette.primary.light,
},
titleBar: {
background:
"linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)",
},
}));
const tileData = [
{
img: game,
title: "Image",
author: "author",
},
{
img: ME,
title: "Image",
author: "author",
},
{
img: game,
title: "Image",
author: "author",
},
{
img: game,
title: "Image",
author: "author",
},
];
export default function LeisureTime() {
const classes = useStyles();
return (
<div className={classes.root}>
<GridList className={classes.gridList} cols={2.5}>
{tileData.map((tile) => (
<GridListTile key={tile.img}>
<img src={tile.img} alt={tile.title} />
<GridListTileBar
title={tile.title}
classes={{
root: classes.titleBar,
title: classes.title,
}}
actionIcon={
<IconButton aria-label={`star ${tile.title}`}>
<StarBorderIcon className={classes.title} />
</IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
If your tileData looks like below :
const tileData = [
{
img: image,
title: 'Image',
author: 'author',
},
...
];
This should work :
const useStyles = makeStyles(theme => ({
// make your style
}));
class HomeReal extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen : false,
};
}
const classes = useStyles();
render(){
return(
<div className={classes.root}>
<GridList cellHeight={180} className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: 'auto' }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{tileData.map(tile => (
<GridListTile key={tile.img}>
<img src={tile.img} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.author}</span>}
actionIcon={
<IconButton aria-label={`info about ${tile.title}`} className={classes.icon}>
<InfoIcon />
</IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
If you wanted to use images from
import image1 from '../resources/examples/1.jpg'
import image2 from '../resources/examples/2.jpg'
then replace tile.img with image1

Why react-google-maps rendering one Circle component twice?

When I added react-google-maps to project, render worked twice. So I have 2 circles one under another. Also, I display the center coordinates by onDragEnd() method. This event works for only one of this circles.
Any others google maps dosen`t exist on project.
Here is some ways I was trying to fix it:
1) Use only withGoogleMap,
2) Use GoogleMapsWrapper component inside render() method of parent component,
3) Use componentDidMount();
trying everything from satckoverflow :)
and nothing helps.
import React, { Component } from 'react';
import MapForm from './mapForm';
import { GoogleMap, withGoogleMap, withScriptjs, Circle } from 'react-google-maps';
const GoogleMapsWrapper = withScriptjs(withGoogleMap(props => {
const {onMapMounted, ...otherProps} = props;
return <GoogleMap {...otherProps} ref={c => {
onMapMounted && onMapMounted(c)
}}>{props.children}</GoogleMap>
}));
class GoogleMapsContainer extends Component {
state = {
coords: {lat:0, lng: 0}
};
dragCircle = () => {
this.setState({
coords: {
lat: this._circle.getCenter().lat(),
lng: this._circle.getCenter().lng()
}
})
}
render() {
return(
<div style={{display: 'flex',flexDirection: 'row', width: '100%', marginLeft: '37px'}}>
<MapForm
filters={this.props.filters}
coords={this.state.coords}
/>
<GoogleMapsWrapper
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${KEY}&v=3.exp&libraries=geometry,drawing,places`}
loadingElement={<div style={{height: `100%`}}/>}
containerElement={<div style={{position: 'relative',width: '100%', }} />}
mapElement={<div style={{height: `100%`}}/>}
defaultZoom={13}
defaultCenter={KYIV}
>
<Circle
ref={(circle) => {this._circle = circle}}
defaultCenter = {KYIV}
defaultDraggable={true}
defaultEditable={true}
defaultRadius={2000}
onDragEnd = {this.dragCircle}
options={{
strokeColor: `${colors.vividblue}`,
fillColor: `${colors.vividblue}`,
fillOpacity: 0.1
}}
/>
</GoogleMapsWrapper>
</div>
)
}
}
export default GoogleMapsContainer;
I need only one circle with my methods.mycircles
Ok, the problem was in React StrictMode component in project.

google-map-react marker not showing

hi all im trying to implement google maps in react.js , the map is showing fine however when i try to show my marker , nothing is being displayed. IF i remove lat and long values then marker will show up on top of the map. But if i add lat and long values to it , then it stops showing. Can someone please help?
import React, { Component } from 'react';
import GoogleMapReact from 'google-map-react';
import marker from './marker.png';
import { geolocated } from 'react-geolocated';
const AnyReactComponent = ({ text }) => (
<div>
<img src={marker} style={{ height: '50px', width: '50px' }} />
</div>
);
export default class Map extends Component {
static defaultProps = {
zoom: 11,
};
Componentwillmount() {
console.log(this.props.center.latitude);
}
render() {
return (
<div className="google-map" style={{ width: '100%', height: '2000px', backgroundColor: 'red' }}>
<GoogleMapReact
options={{
styles:ExampleMapStyles
}}
center={this.props.center} defaultZoom={this.props.zoom}>
<AnyReactComponent
lat={59.955413}
lng={30.337844}
text={'Kreyser Avrora'}
/>
</GoogleMapReact>
</div>
);
}
}
The documentation shows that you can use<AnyReactCompenent/> which you can use if you want to have your own Marker or text. However, if you wish to use the default marker then you would have to pass as a property into the <GoogleMapReact></GoogleMapReact> component. The docs mention 'You can access Google Maps map and maps objects by using onGoogleApiLoaded, in this case, you will need to set yesIWantToUseGoogleMapApiInternals to true'. This just means add the name of the property without passing a value to it as I have in mine. It may not be entirely clear from the description in the Readme, but the maps argument is, in fact, the maps API object (and map is, of course, the current Google Map instance). Therefore, you should pass both into the method with the renderMarkers = (map, maps) => {} function.
You can try this:
import React, { Fragment } from 'react';
import GoogleMapReact from 'google-map-react';
const GoogleMaps = ({ latitude, longitude }) => {
const renderMarkers = (map, maps) => {
let marker = new maps.Marker({
position: { lat: latitude, lng: longitude },
map,
title: 'Hello World!'
});
return marker;
};
return (
<Fragment>
<div style={{ height: '50vh', width: '100%' }}>
<GoogleMapReact
bootstrapURLKeys={{ key: 'YOUR KEY' }}
defaultCenter={{ lat: latitude, lng: longitude }}
defaultZoom={16}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => renderMarkers(map, maps)}
>
</GoogleMapReact>
</div>
</Fragment>
);
};
export default GoogleMaps;
I think the main question that you need to answer is: What are your center props?
I used your code in sandbox and did a some small adaption: I used the same lat/longitude where your marker should be rendered in order to see at a glance whether it is actually shown. And it is:
https://codesandbox.io/s/00p1ry2v0v
export default class Map extends Component {
static defaultProps = {
zoom: 11,
center: {
lat: 49.955413,
lng: 30.337844
}
};
render() {
const mapStyles = {
width: "100%",
height: "100%"
};
return (
<div
className="google-map"
style={{ width: "100%", height: "2000px", backgroundColor: "red" }}
>
<GoogleMapReact
style={mapStyles}
center={this.props.center}
defaultZoom={this.props.zoom}
>
<AnyReactComponent
lat={49.955413}
lng={30.337844}
text={"Kreyser Avrora"}
/>
</GoogleMapReact>
</div>
);
}
}
So, make sure you start the map with a proper initial center position. :)

React leaflet marker layer not updating on zoom

The react-leaflet-marker-layer does not update on zooming the map in/out.
It stays the same, while the map content changes its zoom level.
This happens both during zoom using mouse scroll and the +/- buttons.
NOTE: This may be related, I noticed the map rendering is very slow and some tiles take very long to load. Zooming in/out helps to load them instantly.
import React from 'react';
import ReactDOM from 'react-dom';
import { Map, Marker, Popup, TileLayer } from 'react-leaflet';
import MarkerLayer from 'react-leaflet-marker-layer';
const position = { lng: -122.673447, lat: 45.522558 };
const markers = [
{
position: { lng: -122.67344700000, lat: 45.522558100000 },
text: 'Voodoo Doughnut',
},
{
position: { lng: -122.67814460000, lat: 45.5225512000000 },
text: 'Bailey\'s Taproom',
},
{
position: { lng: -122.67535700000002, lat: 45.5192743000000 },
text: 'Barista'
},
{
position: { lng: -122.65596570000001, lat: 45.5199148000001 },
text: 'Base Camp Brewing'
}
];
class ExampleMarkerComponent extends React.Component {
render() {
const style = {
border: 'solid 1px lightblue',
backgroundColor: '#333333',
borderRadius: '50%',
marginTop: '-5px',
marginLeft: '-5px',
width: '10px',
height: '10px'
};
return (
<div style={Object.assign({}, this.props.style, style)}></div>
);
}
}
class MapView extends React.Component {
render() {
return (
<div
style={{
height:"700px"
}}>
<Map center={position} zoom={13}
style={{
height:"700px"
}}>
<TileLayer
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
attribution='© OpenStreetMap contributors'
/>
<MarkerLayer
markers={markers}
longitudeExtractor={m => m.position.lng}
latitudeExtractor={m => m.position.lat}
markerComponent={ExampleMarkerComponent} />
</Map>
</div>
);
}
}
module.exports = MapView;
I also encountered this issue. Seems like the developer didn't add some event hadlers dor these casese. Not sure if this was intended, but looks more like a bug. The module version at this moment is 0.0.3, so I would't expect much from it.
You can actually just override the method, that sets the event handlers for the layer.
class MarkerLayer extends MapLayer {
attachEvents () {
const map = this.props.map;
map.on('viewreset', () => this.updatePosition());
map.on('zoom', () => this.updatePosition());
map.on('zoomlevelschange', () => this.updatePosition());
}
}
Now, if you use MarkerLayer class, markers would saty where they belong

Resources