I am organising several layers with an interface which allow order decision. For example I have 3 layers:
WMS Layer, order: 3
Geojson layer: order 2
WMS Layer, order: 1
I am able to order the WMS layers with the zIndex property. The Geojson layer however is unable to fit between these too.
The Leaflet.Pane concept + a custom Pane was something I tried, this helps in moving the custom layers on top of lets say everything. But inside this custom pane, I can't assign an order to this Geojson (svg) layer.
In this example, the tileLayers and geoJSON are in the same custom pane. Inside this pane, I want to switch the order of the layers, base on a property (e.g. zIndex). But I can't find how to dos this with a TileLayer <> Geojson combination.
https://codesandbox.io/s/leaflet-custom-pane-fw0ue
Your issue is that you are trying to set the zIndex on the layers, instead of the panes they belong to. You need to set the zIndex on the pane itself. In vanilla leaflet:
map.createPane("top");
map.getPane("top").style.zIndex = "380";
map.createPane("middle");
map.getPane("middle").style.zIndex = "360";
map.createPane("bottom");
map.getPane("bottom").style.zIndex = "340";
var positron = L.tileLayer(
"https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png",
{
pane: "bottom",
}
).addTo(map);
var geojson = L.geoJson(euCountries, { pane: "middle"}).addTo(map);
var positronLabels = L.tileLayer(
"https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png",
{
pane: "top"
}
).addTo(map);
Working codesandbox
This is a bit more elegant in react-leaflet, where you can wrap your various layers in Pane components:
const Map = (props) => {
return (
<MapContainer
doubleClickZoom={false}
id="mapId"
zoom={4}
center={[47.040182144806664, 9.667968750000002]}
>
<Pane name="top" style={{ zIndex: 380 }}>
<TileLayer
url="https://{s}.basemaps.cartocdn.com/light_only_labels/{z}/{x}/{y}.png"
/>
</Pane>
<Pane name="middle" style={{ zIndex: 360 }}>
<GeoJSON data={countries} />
</Pane>
<Pane name="bottom" style={{ zIndex: 340 }}>
<TileLayer
url="https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png"
/>
</Pane>
</MapContainer>
);
};
Working codesandbox
Related
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.
I am using react-leaflet and rc-tabs and while selecting different row in a table I want to display appropriate marker. I want to draw a line from a row to a certain marker when hover with the help of react-lineto, which accepts only classNames as points (well, coordinates too, but this is not suitable for me) so I need an individual class of a marker, a class that can determine a marker on map.
How can I achieve that?
It seems there is no className attribute for every marker, just for group of markers...
okey, after a day spent here I made an marker's icon classnames unique and after that draw a line between my table's hovered row and marker on the map.
return (
<LeafMap center={[deviceCoordinatesLat, deviceCoordinatesLong]} zoom={14} style={{height: "90vh"}}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
{props.devices.map(device => (
<Marker
className={device.serial}
key={device.id}
position={[degreesToCoord(device.coordinates)[0], degreesToCoord(device.coordinates)[1]]}
icon={hoveredItem.id === device.id ?
markerBigBlue :
new L.Icon({
iconUrl: require('../little-blue-dot.png'),
iconSize: new L.Point(15, 15),
className: "little-blue-dot-" + device.id
})
}
>
{hoveredItem.id === device.id ?
<LineTo
*from={"leaflet-marker-icon little-blue-dot-" + device.id + " leaflet-zoom-animated leaflet-interactive"}*
to={"invisible-blue-dot-" + device.id}
borderWidth={1}
zIndex={100}
borderColor="#0C86B8"
/>
: <div></div>}
<Popup>
<span>{device.model} {device.serial}</span>
</Popup>}
</Marker>
))}
</LeafMap>
)
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
I am using Leaflet to create a map game (very basic).
Basically I want to add an input <div> on the map so that when a user types in a location it will pan to a coordinate on the map.
I have tried creating elements and appending to the map <div> with variations of:
var d1 = document.getElementsByClassName('leaflet-control-container')[0];
d1.insertAdjacentHTML('afterbegin', '<div id="two">two</div>');
But the <div> is displayed behind the map and the image covers it.
How can I get it to show like the Zoom Control?
If I understand correctly, you would like to create your own "Control" (somehow visually similar to the Leaflet default Zoom Control, but with different functionality), that would allow looking for different locations and navigate to them.
As for styling a Control similar to Leaflet default ones (zoom, layers control), you need to:
Extend L.Control
Specify an onAdd method that returns the DOM element to be used as Control on the map. Steps 1 and 2 will make your Control add-able to a map corner as a standard Control, with proper z-index and margin.
Style it using your own class. To get a visual effect similar to the Zoom and Layers Controls, you can build on the leaflet-bar class:
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
border-radius: 5px;
}
Example: (derived from the "Extending Leaflet: Handlers and Controls" tutorial)
var map = L.map('map').setView([48.86, 2.35], 11);
L.Control.MyControl = L.Control.extend({
onAdd: function(map) {
var el = L.DomUtil.create('div', 'leaflet-bar my-control');
el.innerHTML = 'My Control';
return el;
},
onRemove: function(map) {
// Nothing to do here
}
});
L.control.myControl = function(opts) {
return new L.Control.MyControl(opts);
}
L.control.myControl({
position: 'topright'
}).addTo(map);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
.my-control {
background: #fff;
padding: 5px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.0/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.3.0/dist/leaflet-src.js" integrity="sha512-2h9aokfcaYW7k0VPn1JqbQDQCaNQRrZJwetlnQ88yJrtIzGLVW/2StdQKoE+TIVNNTUxf6SVa+2vW2KB2EXnnA==" crossorigin=""></script>
<div id="map" style="height: 200px"></div>
That being said, the Control functionality that you would like to implement sounds very similar to that of the Leaflet Control Search plugin (aka "leaflet-search")
A Leaflet control that search markers/features location by custom property.
We need to disable duplicated world maps at the left and right side of the main world map, which is showing by default.
Problem is that we need exact zoom level there and sometimes leaflet showing duplicates...
Is it possible to remove duplicates at all?
You will disable the noWrap property of your TiledLayer (which extends GridLayer). Documentation here
var layer = new L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
noWrap: true
});
If you use react-leafet you can set this prop in TileLayer component:
<MapContainer
center={{ lat: 51.505, lng: -0.09 }}
zoom={5}
style={mapStyle}
scrollWheelZoom={true}
>
<TileLayer
noWrap={true}
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>