I'm, trying to figure out why LeafletJS is refusing to update the boundaries of the map when you do the fitBounds(). Please see the example below:
window.VARS = {
lat: "44.849666595459",
lng: "-0.45023700594902"
};
the_markers = [
{ latitude: "43.5587495722976360", longitude: "2.91172027587890620" },
{ latitude: "42.447154030597420", longitude: "3.1617611646652220" },
{ latitude: "42.934817491341060", longitude: "2.2226071357727050" },
{ latitude: "43.942591406202790", longitude: "4.5511722564697270" },
{ latitude: "43.971010439915080", longitude: "3.53219582705082760" },
{ latitude: "43.791295604602740", longitude: "4.244724512100220" },
{ latitude: "44.06685920", longitude: "4.7537072999999740" },
{ latitude: "42.93469966783150", longitude: "2.22310066223144530" },
{ latitude: "43.468867614829250", longitude: "2.6916503906250" },
{ latitude: "43.38313951013020", longitude: "1.89306401852422820" },
{ latitude: "43.2689484490373960", longitude: "2.5141417980194090" },
{ latitude: "42.9351204832447950", longitude: "2.22281125026245260" },
{ latitude: "44.0415390", longitude: "3.737170" },
{ latitude: "43.461446687325310", longitude: "3.4211683273315430" },
{ latitude: "43.103510", longitude: "2.091930" },
{ latitude: "42.9912035311160140", longitude: "2.9541689157485960" },
{ latitude: "43.37033920", longitude: "2.2828302000000350" }
];
window.VARS.Map_Modal = L.map('google_map_modal_inner', {
center: [window.VARS.lat,window.VARS.lng],
zoom: 10,
maxZoom: 20,
zoomControl: false
});
new L.Control.Zoom({ position: 'topright' }).addTo(window.VARS.Map_Modal);
setTimeout(function() {
window.VARS.Map_Modal.invalidateSize();// stop the grey tiles due to being a flex div
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA, Imagery © Mapbox',
maxZoom: 18,
id: 'mapbox.streets',
accessToken: 'pk.eyJ1IjoiYW5keW5ld2J5IiwiYSI6ImNqbjRmY3htNzAzNTUzeGxwdnFza3k2bmIifQ.DDUWhS_xib2LSIcSd3FMZg'
}).addTo(window.VARS.Map_Modal);
}, 500);
window.VARS.markerCluster = L.markerClusterGroup();
the_markers.forEach(function(item, i){
window.VARS.markerCluster.addLayer(
L.marker([item.latitude, item.longitude])
.bindPopup('A pretty CSS3 popup.<br> Easily customizable.')
.on("click", function(marker) {
console.dir(marker);
})
);
});
// add the clusters to map
window.VARS.Map_Modal.addLayer(window.VARS.markerCluster);
// fit to map
// HERE IS WHERE THE ERROR HAPPENS
window.VARS.Map_Modal.fitBounds(window.VARS.markerCluster.getBounds());
var mapBounds = window.VARS.Map_Modal.getBounds();
var rect = L.rectangle(mapBounds, {color: 'blue', weight: 1}).addTo(window.VARS.Map_Modal);
You can see a fiddle here:
https://jsfiddle.net/youradds/3ugk7L9y/42/
If you zoom out you can see the location that getBounds() returns (the highlighted rectangle);
What do I need to do to make it get the new boundaries?
Thanks
Eugh, turns out I was being dumb!
Rather than:
var mapBounds = window.VARS.Map_Modal.getBounds();
I needed to get the bounds on the cluster itself!
var mapBounds = window.VARS.markerCluster.getBounds();
Related
I am trying to use a custom layer and update it over time but can't seem to get it to work to update when state changes. I am using a library to interpolate I thought the use memo runs but the Layer doesn't get updated. How can I make it so it gets updated?
Codesandbox:https://codesandbox.io/s/elastic-jasper-p8xeme?file=/src/Map.jsx
import React, { useEffect, useState } from "react";
import MapGL, { Layer } from "react-map-gl";
import "mapbox-gl/dist/mapbox-gl.css";
const interpolateHeatmapLayer = require("interpolateheatmaplayer");
const MapDisplay = () => {
const mapRef = React.useRef();
function handleChange() {
setCount(count + 1);
console.log(count);
}
function generateRandomInteger(min, max) {
return min + Math.random() * (max + 1 - min);
}
const [count, setCount] = useState(0);
function generateRandomPoints() {
const points = [];
for (let i = 0; i < 100; i++) {
const lat = generateRandomInteger(50, 65);
const long = generateRandomInteger(5, 15);
const value = generateRandomInteger(-20, 20);
points.push({ lat: lat, lon: long, val: value });
}
return points;
}
const InterPolateLayer = React.useMemo(() => {
return interpolateHeatmapLayer.create({
points: generateRandomPoints(),
layerID: "InterPolateLayer",
p: 4,
maxValue: 20,
minValue: -20,
roi: [
{
lat: 58.876757827896306,
lon: 11.881643616280888
},
{
lat: 58.82822263473829,
lon: 11.186346643290852
},
{
lat: 57.912686819868505,
lon: 7.476790555439328
},
{
lat: 62.044315808590355,
lon: 4.497823276243542
},
{
lat: 63.90167395134969,
lon: 8.386691071710919
},
{
lat: 65.78132314149487,
lon: 10.969111182413434
},
{
lat: 68.99622052100831,
lon: 12.799815394602154
},
{
lat: 71.32599822634651,
lon: 24.95207832070384
},
{
lat: 63.99473920322428,
lon: 13.975403465948437
},
{
lat: 58.876757827896306,
lon: 11.881643616280888
}
]
});
}, [count]);
//How can I change the Layer on buttonclick?
//I am trying to rerender the InterPolateLayer but dosent seem to work
return (
<>
<MapGL
initialViewState={{
longitude: 10.757933,
latitude: 59.91149
}}
//onViewportChange={setViewport}
style={{ width: "100vw", height: "100vh" }}
/* onLoad={onMapLoad} */
ref={mapRef}
mapStyle="mapbox://styles/mapbox/dark-v9"
mapboxApiAccessToken="pk.eyJ1Ijoib2xlZHliZWRva2tlbiIsImEiOiJja3ljb3ZvMnYwcmdrMm5vZHZtZHpqcWNvIn0.9-uQhH-WQmh-IwrA6gNtUg"
>
<Layer {...InterPolateLayer}></Layer>
<button style={{ position: "absolute" }} onClick={handleChange}>
Only Show 5 points!
</button>
</MapGL>
)
</>
);
};
export default MapDisplay;
in leaflet.js i have polyline in openstreet map:
point1(long, lat), 2(long, lat)....pointXY(long,lat)
Is possible (and how) highlight or change color only segment from point 2 to 5, no matter how to invoke.
I try add another polyline, but with more segments its mess with more and more duplicit points.
Working sample:
http://next.plnkr.co/edit/FyUzMG9Y9NrbYrzL
i looking for turn segment between [40,10],[10,10],[10,30] red. If its possible, by index [2,3,4]
thanks for help
You can try GeoJson layer to highlight a line. Just make sure that geojson coordinates are in LngLat format.
var map = L.map('map', {
center: [0, 0],
zoom: 0,
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © OpenStreetMap contributors',
}),
],
});
var data = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[30, 10], [45, 45]],
},
properties: {
color: 'green',
},
},
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[10, 40], [10, 10], [30, 10]],
},
properties: {
color: 'red',
},
},
{
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [[-45, -45], [10, 40]],
},
properties: {
color: 'black',
},
},
],
};
var geoJsonLayer = L.geoJson(data, {
onEachFeature: function(feature, layer) {
if (layer instanceof L.Polyline) {
layer.setStyle({
color: feature.properties.color,
});
}
},
}).addTo(map);
Plunker: http://next.plnkr.co/edit/s4Q72s7RyOLp714U?preview
Ref: https://embed.plnkr.co/plunk/XqzvdR
I want to change the icon-size on map click based on the turf-nearest. How do i accomplish this? nearestBuilding.properties['icon-size'] = 0.2; does not work.
var retail = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
title: 'TEST',
description: 'TEST'
},
geometry: {
type: 'Point',
coordinates: [121.051779, 14.550224]
}
},
{
type: 'Feature',
properties: {
title: 'TEST',
description: 'TEST'
},
geometry: {
type: 'Point',
coordinates: [121.04568958282472, 14.552170837008527]
}
}
]
};
map.on('load', function() {
map.loadImage('https://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Wiki_Loves_Earth_map_marker.svg/600px-Wiki_Loves_Earth_map_marker.svg.png', function(error, image) {
if (error) throw error;
map.addImage('marker', image);
map.addLayer({
id: 'retail',
type: 'symbol',
source: {
type: 'geojson',
data: retail
},
layout: {
'icon-image': 'marker',
'icon-size': 0.1
},
paint: { }
});
});
});
var marker = null;
map.on('click', function(e){
if(marker != null) {
marker.remove();
}
var currentLocation = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [e.lngLat.lng, e.lngLat.lat]
}
};
var el = document.createElement('div');
el.className = 'currLocMarker';
marker = new mapboxgl.Marker(el, { offset: [-50 / 2, -50 / 2] })
.setLngLat(currentLocation.geometry.coordinates)
.addTo(map);
var currentLocation = turf.point([e.lngLat.lng, e.lngLat.lat]);
var nearestBuilding = turf.nearest(currentLocation, retail);
var distance = turf.distance(currentLocation, nearestBuilding);
if (distance <= 0.5) {
nearestBuilding.properties['icon-size'] = 0.2;
}
});
Since icon-size supports data-driven styling(https://www.mapbox.com/mapbox-gl-js/style-spec/#layout-symbol-icon-size), have you tried doing that, with an identity function from the property on each feature? You would configure this inside the layout, instead just hard-coding 0.1.
More docs on data-driven styling is here - https://www.mapbox.com/mapbox-gl-js/style-spec/#function-type
I'm trying to add the Leaflet Draw library / control.
I can add a marker, and it persists (and stays visible). But when I add a line or polygon they aren't visible (persisted though if I inspect the .layers, also check the screenshot. The element seems to be there, but it just isn't visible).
Any guidance would be highly appreciated!
Edit: I'm using the following code to initialize the map:
var elem = angular.element('#datasetLeafletMap'); //using Angular
console.log('initting map', elem[0]);
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttrib = '© OpenStreetMap contributors',
osm = L.tileLayer(osmUrl, { maxZoom: 18, attribution: osmAttrib });
var map = new L.Map(elem[0], { layers: [osm], center: new L.LatLng(52.105289405897, 5.2629891004852425), zoom: 13 });
console.log('map ready');
var drawnItems = new L.FeatureGroup();
var coords = [new L.latLng(51.2, 4.5), new L.latLng(51.2, 4.6), new L.latLng(51.2, 4.9)];
var poly = new L.Polyline(coords, {
color: 'blue',
opacity: 1,
weight: 5
});
drawnItems.addLayer(poly);
map.addLayer(drawnItems);
var drawControl = new L.Control.Draw({
draw: {
position: 'right',
polygon: {
title: 'Polygon',
allowIntersection: false,
drawError: {
color: '#b00b00',
timeout: 1000
},
shapeOptions: {
color: '#bada55'
},
showArea: true
},
polyline: {
metric: false
},
circle: {
shapeOptions: {
color: '#662d91'
}
}
},
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
map.on('draw:created', function (e) {
var type = e.layerType,
layer = e.layer;
if (type === 'marker') {
layer.bindPopup('A popup!');
}
drawnItems.addLayer(layer);
console.log('adding layer', layer, drawnItems);
});
Working with leaflet api where i have added a custom marker control...
There also we can add multiple baseLayer and toggle between these layers....
Lately i was trying to bind the markers with this base layer and i can't understand the documentaion very well so having difficulty if someone help.....
Script
//Custom control for marker
L.easyButton('fa-arrow', function () {
map.on('click', function arrow(e) {
L.marker(e.latlng, { icon: arrIcon, draggable: true}).addTo(map);
map.off('click', arrow);
});
}).addTo(map);
//already added layer and needs to bind marker with this
var layerGroup = new L.LayerGroup(),
imageOverlayUrl = 'abc.jpg',
imageOverlay = new L.ImageOverlay(imageOverlayUrl, bounds).addTo(layerGroup),
featureGroup = new L.FeatureGroup().addTo(layerGroup);
var layerGroupings = { "Main": layerGroup };
var layerControl = new L.control.layers(layerGroupings,null, { collapsed: false }).addTo(map);
In short, i have a need to bind my custom marker with this layer i have defined in script, if there is a way please guide or give reference..thanks for your time
I am not sure if this is what you are looking for.
<!DOCTYPE html>
<html ng-app="demoapp">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="../bower_components/angular/angular.min.js"></script>
<script src="../bower_components/leaflet/dist/leaflet.js"></script>
<script src="../dist/angular-leaflet-directive_dev_mapped.js"></script>
<link rel="stylesheet" href="../bower_components/leaflet/dist/leaflet.css"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
var app = angular.module("demoapp", ["leaflet-directive"]);
app.controller('MixedMOverlaysMarkersNestedNoWatchController', function ($scope, leafletData, $timeout) {
var _clonedMarkers;
$timeout(function () {
//should do nothing (not watched) and only see one destroy
_clonedMarkers = angular.extend({},$scope.markers);
$scope.markers = {};
},1000);
$timeout(function () {
leafletData.getDirectiveControls().then(function (controls) {
//move all markers by a few decimal points
for (var layer in _clonedMarkers) {
var markerSet = _clonedMarkers[layer];
for (var markerName in markerSet) {
var marker = markerSet[markerName];
marker.lat += .05;
}
}
//force manual update
$scope.markers = _clonedMarkers;
controls.markers.create($scope.markers);
});
}, 4000);
angular.extend($scope, {
markersWatchOptions: {
doWatch: false,
isDeep: false,
individual: {
doWatch: false,
isDeep: false
}
},
center: {
lat: 42.20133,
lng: 2.19110,
zoom: 11
},
layers: {
baselayers: {
osm: {
name: 'OpenStreetMap',
type: 'xyz',
url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
layerOptions: {
subdomains: ['a', 'b', 'c'],
attribution: '© OpenStreetMap contributors',
continuousWorld: true
}
},
cycle: {
name: 'OpenCycleMap',
type: 'xyz',
url: 'http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png',
layerOptions: {
subdomains: ['a', 'b', 'c'],
attribution: '© OpenCycleMap contributors - © OpenStreetMap contributors',
continuousWorld: true
}
}
},
overlays: {
hillshade: {
name: 'Hillshade Europa',
type: 'wms',
url: 'http://129.206.228.72/cached/hillshade',
visible: true,
layerOptions: {
layers: 'europe_wms:hs_srtm_europa',
format: 'image/png',
opacity: 0.25,
attribution: 'Hillshade layer by GIScience http://www.osm-wms.de',
crs: L.CRS.EPSG900913
}
},
fire: {
name: 'OpenFireMap',
type: 'xyz',
url: 'http://openfiremap.org/hytiles/{z}/{x}/{y}.png',
layerOptions: {
attribution: '© OpenFireMap contributors - © OpenStreetMap contributors',
continuousWorld: true
}
},
cars: {
name: 'Cars',
type: 'group',
visible: true
},
bikes: {
name: 'Bicycles',
type: 'group',
visible: false
},
runners: {
name: 'Runners',
type: 'group',
visible: false
}
}
},
markers: {
cars: {
m1: {
lat: 42.20133,
lng: 2.19110,
message: "I'm a car"
},
m2: {
lat: 42.21133,
lng: 2.18110,
message: "I'm a car"
}
},
bikes: {
m3: {
lat: 42.19133,
lng: 2.18110,
layer: 'bikes',
message: 'A bike!!'
},
m4: {
lat: 42.3,
lng: 2.16110,
layer: 'bikes'
}
},
runners: {
m5: {
lat: 42.1,
lng: 2.16910
},
m6: {
lat: 42.15,
lng: 2.17110
}
}
}
});
});
</script>
</head>
<body ng-controller="MixedMOverlaysMarkersNestedNoWatchController">
<leaflet
center="center"
markers="markers"
layers="layers"
markers-nested="true"
markers-watch-options="markersWatchOptions"
height="480px" width="100%">
</leaflet>
<h1>Overlays with nested markers no watchers example</h1>
</body>
</html>
*Source: https://tombatossals.github.io/angular-leaflet-directive/examples/0000-viewer.html#/mixed/overlays-markers-nested-no-watch-example