React-google-maps - MarkerWithLabel - Labels overlap - react-google-maps

I'm trying to build a react project with the react-google-maps
library.
Basically it calculates the best route between 2 points and displays the route on the map using the library above.
For drawing I'm using the Polyline and MarkerWithLabel modules:
The Polyline to draw the segments
The Markers to place the start of a segment
The issue that I am having is the position of the labels form the MarkerWithLabel, if the zoom level is set to fit the whole route the labels overlap. This is because markers are very close and the zoom level is small, which is normal...
I've also attached 2 images
The first one with the zoom level to fit all the route (in which the markers label overlap)
The second one with the zoom level over one segment(in our case the city of Timisoara) to actual see the all the markers
The code for the MarkerWithLabel is below
const Markers = () => segments.map((segment) => {
const { marker } = segment;
const style = styles.vehicles[marker.vehicle.kind];
return (
<MarkerWithLabel
key={marker.key}
position={{ lat: marker.lat, lng: marker.lng }}
labelAnchor={new goo.Point(-10, 15)}
noRedraw
icon={{
path: goo.SymbolPath.CIRCLE,
scale: 4,
strokeWeight: 2,
fillOpacity: 1,
fillColor: '#ff3f10',
strokeColor: '#ffffff',
}}
labelClass="marker-label"
labelStyle={{
width: '400px',
backgroundColor: 'none',
color: style.color,
}}
>
<div style={{ clearFix: 'both' }}>
<span className="marker-text">
{marker.label}
</span>
<div className="circle">
{style.icon}
</div>
</div>
</MarkerWithLabel>
);
});
I want to know if there is a simple way of resolving the overlapping problem, just to place them somehow one next to the other or in different positions.
One solution would be to manually set the labelAnchor but I don't know how to find a solution for this, to detect which are overlapping and which not

Related

React leaflet - GeoJSON gets hidden on drag

I understand that react-leaflet implements lazyloading/virtualization to render the data in the viewport and that is working fine for me as well.
However, I am facing a strange issue when I drag.
I am using GeoJSON along with Polygon component of react-leaflet to render different data (its large). Whenever I drag to some level I see only the Polygon data rendered and not GeoJSON.
Not sure if it is due to Polygon overlapping GeoJSON. Any help would be appreciated.
Demo here:
Here is my code:
...
// this gets hidden on drag sometimes.
<GeoJSON
style={mapStyle}
key={`key-${Math.random()}`}
data={sampleDataGeoJSON}
onEachFeature={onEachCluster}
interactive={false}
/>
// this always gets rendered.
{regionBoundary.length > 0 && (
<Polygon
positions={regionBoundary}
pathOptions={{
fillColor: orange,
fillOpacity: 0.5,
color: orange, // stroke color,
weight: 3, // stroke weight,
dashArray: '2, 10',
}}
zIndex={800}
interactive={false}
/>
)}
...

react-leaflet _ "Invalid LatLng object: (NaN, NaN)" with valid coordinates on Polyline

Invalid LatLng object: (NaN, NaN) appears with react-leaflet, and comes from leaflet itself, as it seems to come from the core library, even if coordinates are actually valid.
Code:
const plottedPoints: LatLong[] = [
[29.69937, -95.32803],
[30, 30],
[29.69937, -95.32803]
]
const polylineTraveledOptions: PathOptions = {lineCap: 'square', lineJoin: 'miter', color: blue50, weight: 4}
return(
<div id="map" style={{height: '400px', width: '555px'}}>
<MapContainer
// Won't let the user zoom out too much and see outside the world's layout
zoomSnap={0.5}
zoomDelta={0.5}
// We have a custom positioned zoom control
zoomControl={false}
scrollWheelZoom={false}
// Fixes the map's drag to its bounds
maxBoundsViscosity={1}
style={{height: '100%', width: '100%'}}>
<TileLayer
attribution='© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors'
url="https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png"
/>
<ZoomControl position="bottomright" />
<Polyline pathOptions={polylineTraveledOptions} positions={plottedPoints} />
</MapContainer>
</div>
)
I'm also setting the mapBounds:
const map = useMap()
// Zooms in the correct size for the polyline we've set
const mapBounds = [[29.69937, -95.32803], [29.69937, -95.32803]]
map.fitBounds(mapBounds, {padding: [30, 30]})
// Won't let the user zoom to a world's map that's duplicated
map.setMinZoom(2)
// Won't let the user drag outside of the world's map
map.setMaxBounds([
[-90, -300],
[90, 300],
])
May it because it doesn't support overlapping of vectors on Polylines, as two of the coords are on the same location?
Or is it because the mapBounds() function would be on the same point, instead of something that can be calculated as a square?
Or else...?
There's also not much out there on how to fix it, a part of this link: https://github.com/IvanSanchez/Leaflet.Polyline.SnakeAnim/issues/29 which is about the snake animation - and I don't think it's related.
Please, enlighten me.

How to prevent deck gl layers from occupying entire viewport?

I have a DeckGL component I'm eclosing it in a div tag and giving it size, but the deckGL layer seems to occupy the entire viewport. here is a snippet of my code.
const INITIAL_VIEW_STATE = {
longitude: 83.32247972488423,
latitude: 17.714023254029464,
zoom: 10,
pitch: 0,
bearing: 0
}
<div class="my-container">
<DeckGL initialViewState={INITIAL_VIEW_STATE} layer={layer} controller>
// here I'm putting a static map
</DeckGL>
</div>
How to render deck gl component in a specific div with a given size.
You need to add a dimension to your deck.gl container, in your example 'my-container'. Add height, width and position. Switch height and width values according to your need, but leave position with value 'relative'. In this way you can size DeckGL component and it can render fully inside your container.
Bonus: it is also responsive.
<div class"my-container" style={{ height: '50vh', width: '50vw', position: 'relative' }}
<DeckGL>
...
</DeckGL>
</div>

How to distinguish leaflet zoom triggered by map.fitBounds from user mousewheel?

I have a map which is refreshed every 30 seconds and on each refresh I fit bounds to the new data. I would like to change the way I fit bounds if a user has manipulated the map, e.g. changed zoom level. My problem is that zoom triggered from fitBounds is indistinguishable from user action.
How do I capture/extend mousewheel on the map?
Basically there are multiple ways todo same, but you can go with following simple way to distinguish user zoom triggered.
The onwheel event occurs when the mouse wheel is rolled up or down over an element.
var map = L.map('map', {
// Set latitude and longitude of the map center (required)
center: [12.99766, -84.90838],
// Set the initial zoom level, values 0-18, where 0 is most zoomed-out (required)
zoom: 5,
// scrollWheelZoom: false
});
// Create a Tile Layer and add it to the map
var tiles = new L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png').addTo(map);
document.getElementById("map").addEventListener("wheel", myFunction);
function myFunction() {
alert("Mouse wheel Scrolled by user.")
}
#map {
width: 500px;
height: 400px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.3/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.0.3/dist/leaflet.js"></script>
<div id="map"></div>
Hope this will helps you.

How to apply css on polylines : leaflet

I am working with the application which uses leaflet api.
Introduction
I needed to draw different types of fences, using decorators i can somewhat apply good visuals to the polylines but not much.
Problem
I was willing to show twisted wires instead of dashes, dots or plain lines and I know the twisted wire line will be an image but can't find help about applying custom css to polylines.
Script Example
var fence2Icon = L.icon({
iconUrl: 'xxxx.png',
iconSize: [5, 20]
iconAnchor: [5, 18]
});
// Add coordinate to the polyline
var polylineFence2 = new L.Polyline([], { color: 'red' });
function fencePlace2(e) {
// New marker on coordinate, add it to the map
new L.Marker(e.latlng, { icon: fence2Icon, draggable: false }).addTo(curr);
// Add coordinate to the polyline
polylineFence2.addLatLng(e.latlng).addTo(curr);
var decorator = L.polylineDecorator(polylineFence2, {
patterns:[{offset:5,repeat:'20px',symbol:new L.Symbol.Dash({pixelSize:5})
}]
}).addTo(curr);
}
L.easyButton('fa-flash', function () {
$('.leaflet-container').css('cursor', 'crosshair');
map.on('click', fencePlace2);
polylineFence2 = new L.Polyline([], { color: 'red' });
}).addTo(map);
If someone know anything about polyline or another way please do help.
Thanks for your time:-)
You can add a class in the options of your polyline ...
var polyline = L.polyline(latlngs, { className: 'my_polyline' }).addTo(map);
and add your own settings in the CSS ...
.my_polyline {
stroke: green;
fill: none;
stroke-dasharray: 10,10;
stroke-width: 5;
}
Here is an example: http://jsfiddle.net/FranceImage/9dggfhnc/
You can also access some options directly ...
var polyline = L.polyline(latlngs, { dashArray: '10,10' }).addTo(map);
See Path Options
If you create a polyline you're in fact adding an element to the SVG element which Leaflet uses to draw it's overlays. Styling SVG path elements is different from styling regular HTML elements. There's no such thing as border and background-color etc. It has different properties, if you're interested here's a nice read on the matter:
https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Fills_and_Strokes
You can style Leaflet's path elements when you instanciate them via options or via CSS using the properties (related to styling) described in the documentation here:
http://leafletjs.com/reference.html#path
Via options:
new L.Polyline([...], {
weight: 3,
color: 'red',
opacity: 0.5
}).addTo(map);
Via CSS:
new L.Polyline([...], {
className: 'polyline'
}).addTo(map);
.polyline {
weight: 3,
color: red,
opacity: 0.5
}
However, what you want, using an image simply isn't possible. You can use images as fill for SVG paths, but it would be impossible for your usecase. You'de need to add a pattern definition to the SVG Leaflet is using and then you could use that id as the fill property as outlined in this answer:
https://stackoverflow.com/a/3798797/2019281 but will always fill/tile the image horizontally which won't work if your polyline is vertical.