How to use leaflet.js heat with pane? - leaflet

I want to show/hide Leaflet.heat(https://github.com/Leaflet/Leaflet.heat) layer, and new pane should somehow do this.
But is there any support for panes on Leaflet.heat?
This code does not work.
var heatPane = map.createPane("heat");
var heat = L.heatLayer([], {
radius: 10,
maxZoom: 6,
pane: "heat"
}).addTo(map);
heat.addLatLng([44,7])
heat.addLatLng([44,7])
UPD: I can use heat._heat._canvas.style.display = "none" to hide heat layer, but I don't think it is a good practice.
Thanks.

Is seems current release version of leaflet-heat.js does not support using pane option. You can use beta/development version if you want and you can achieve your requirements by just setting style on the pane.
Check out the code below:
document.onreadystatechange = function(e){
if(document.readyState != 'complete') return;
var map = L.map('map').setView([44, 7], 12);
var tiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {}).addTo(map);
var heatPane = map.createPane("heat");
var heat = L.heatLayer([[44, 7], [44, 7], [44, 7], [44, 7]], {
radius: 10,
maxZoom: 6,
pane: "heat"
}).addTo(map);
document.getElementById("btnShow").onclick = function(){
heatPane.style.display = 'block';
};
document.getElementById("btnHide").onclick = function(){
heatPane.style.display = 'none';
};
};
#map {
width: 400px;
height: 400px;
}
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v1.3.4/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet/v1.3.4/leaflet.js"></script>
<!-- <script src="http://leaflet.github.io/Leaflet.heat/dist/leaflet-heat.js"></script> -->
<script src="http://leaflet.github.io/Leaflet.heat/src/HeatLayer.js"></script>
<script src="http://mourner.github.io/simpleheat/simpleheat.js"></script>
<div>
<button id="btnHide">Hide</button>
<button id="btnShow">Show</button>
</div>
<div id="map"></div>
P.S: You can uncomment the code and use release version of the script but it will not work because current release version of leaflet-heat draws canvas on default map layer.

Related

How to select only one layer through a Select (leaflet)

I'm trying to select only one layer using a select.
This is my first time with leaflet and I use this great guide: https://maptimeboston.github.io/leaflet-intro/
Now I have on my map the part of "markerclusters" and the last one "heatmap" and I want to choose only one layer or the other or both.. I've been looking for examples but I don't know how to apply them.
(The select right now is ornamental as you can see.)
And here's the image of my map:
Image
here is my code, thanks in advance!
<html>
<head>
<title>MAPA PRUEBA</title>
<link rel="stylesheet" href="leaflet.css"/>
<link rel="stylesheet" href="MarkerCluster.css"/>
<script src="leaflet.js"></script>
<script src="leaflet.markercluster.js"></script>
<script src="leaflet.heat.js"></script>
<script src="jquery-2.1.1.min.js"></script>
<style>
#map{ height: 100% }
</style>
</head>
<body>
<div id="panel" style = "top-left:10px; background-color:#D3D3D3;">
<label>Tipo de mapa</label>
<select id="estilo" onchange="Bordeaux()">
<option value="points" >PUNTOS</option>
<option value="heat">MAPA DE CALOR</option>
</select>
<div id="map"></div>
<script>
// initialize the map
var map = L.map('map').setView([40.46, -3.74], 4);
// load a tile layer
L.tileLayer('http://192.168.0.103/osm/{z}/{x}/{y}.png',
{
attribution: 'Tiles by MAPC, Data by MassGIS',
maxZoom: 17,
minZoom: 1
}).addTo(map);
// load GeoJSON from an external file
$.getJSON("rodents.geojson",function(data){
var ratIcon = L.icon({
iconUrl: 'images/marker-icon.png'});
var rodents = L.geoJson(data,{
pointToLayer: function(feature,latlng){
var marker = L.marker(latlng,{icon: ratIcon});
marker.bindPopup(feature.properties.Location);
return marker;}
});
var clusters = L.markerClusterGroup();
clusters.addLayer(rodents);
map.addLayer(clusters);
});
// HEAT LAYER
$.getJSON("rodents.geojson",function(data){
var locations = data.features.map(function(rat) {
// the heatmap plugin wants an array of each location
var location = rat.geometry.coordinates.reverse();
location.push(1.9);
return location;
});
var heat = L.heatLayer(locations, { radius: 50 });
map.addLayer(heat);
});
</script>
</body>
</html>
change the clusters and heat variable to global. And add only one of both layers to the map.
var clusters, heat;
$.getJSON("rodents.geojson",function(data){
// ...
clusters = L.markerClusterGroup();
clusters.addLayer(rodents);
map.addLayer(clusters);
});
// HEAT LAYER
$.getJSON("rodents.geojson",function(data){
//...
heat = L.heatLayer(locations, { radius: 50 });
});
Then add / remove the layers in your onchange function from the select:
<select id="estilo" onchange="changeFnc(this)">
<option value="points" >PUNTOS</option>
<option value="heat">MAPA DE CALOR</option>
</select>
function changeFnc(obj){
var value = obj.value;
if(value == "points"){
if(map.hasLayer(clusters)){
map.removeLayer(clusters);
}
map.addLayer(points);
}else{
if(map.hasLayer(points)){
map.removeLayer(points);
}
map.addLayer(clusters);
}
}
PS: This code is not tested but should work

Shift between WMS Tiles in Leaflet

I use Leaflet to show a WMS Layer via a proxy.php (for authentication). That is working on most WMS Layers. But I have some WMS Sources, which are having a small shift in the tiles. See Overlay Map in the example.
var map1 = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 30,
maxNativeZoom: 18
});
var map4 = new L.tileLayer.wms("https://entwicklung.firetab.ch/maptest/proxy.php?url=http://geoshop.kommunalportal.ch/SWMS?", {
layers: 'lk_wms_wasser',
format: 'image/png',
transparent: true,
maxZoom:30
});
var map = L.map('mapid').setView([47.549904, 9.152927], 18);
var baseMaps = {
"map1": map1
};
var overlayMaps = {
"map4": map4
};
L.control.layers(baseMaps, overlayMaps).addTo(map);
map1.addTo(map);
map4.addTo(map);
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.6.0/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.6.0/dist/leaflet.js"></script>
<div id="mapid" style="width: 100%; height: 800px;"></div>

How can you put leaflet polylines in multiple panes?

What am I doing wrong? The intent is to have a few (say 6) leafletjs panes, each containing many markers and polylines, so the panes can be hidden independently. Here is a simplified program showing just two lines and markers in jsfiddle. The problem is, the polylines all get grouped in the same SVG and all get hidden together. Each pane in the example should show one polyline and one marker.
I don't want to remove the polylines from the map to hide them, then recreating them would not perform well.
If needed, the polylines could be drawn using D3 on top of the leaflet map but I was hoping it could all be done in leaflet.
Thanks!
JS:
'use strict';
document.addEventListener("DOMContentLoaded", function(event) {
var map = L.map('map').setView([30.5, -0.09], 2);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var pane1 = map.createPane('pane1');
var pane2 = map.createPane('pane2');
function hide(pane) {
pane.style.display = 'none';
}
function show(pane) {
pane.style.display = '';
}
let icon = new L.Icon.Default();
function dr(pane, latlng){
L.polyline([[45.421, -75.697], latlng], {
weight: 2,
pane: pane
}).addTo(map);
L.marker(latlng, {
icon: icon,
pane: pane
}).addTo(map);
}
// define two locations with lines from Ottawa
dr(pane1, [ 42.3732216, -72.5198537 ]);
dr(pane2, [ 35.9606384, -83.9207392 ]);
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function loop(){
for( var i = 0; i<100; i++){
hide(pane1);
show(pane2);
await sleep(1000);
hide(pane2);
show(pane1);
await sleep(1000);
}
}
loop();});
HTML:
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.5.1/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.6.0/leaflet-src.js" integrity="sha256-wc8X54qvAHZGQY6nFv24TKlc3wtO0bgAfqj8AutTIu0=" crossorigin="anonymous"></script>
<style>
html, body {
height: 100%;
margin: 0;
}
#map {
width: 900px;
height: 500px;
}
</style>
</head>
<body>
<div id='map'></div>
</body>
</html>
<script src="c.js"></script>

Leaflet.Deflate with Leaflet.markercluster does not show cluster coverage on hover

when you mouse over a cluster, Leaflet.markercluster should show the bounds of its markers. this is the (simplified) code I am using:
map = new L.Map('map');
L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 13,
attribution: 'Map data © OpenStreetMap contributors'
}
).addTo(map);
map.setView([51.505, -0.09], 11);
let deflate_features = L.deflate({
minSize: 40,
markerCluster: true
});
deflate_features.addTo(map);
var polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]);
deflate_features.addLayer(polygon);
var polyline = L.polyline([
[51.52, -0.05],
[51.53, -0.10],
], {
color: 'red'
});
deflate_features.addLayer(polyline);
#map {position: absolute; top: 0; bottom: 0; left: 0; right: 0;}
<html>
<head>
<link href="https://unpkg.com/leaflet#1.3.3/dist/leaflet.css" rel="stylesheet" />
<link href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.css" rel="stylesheet" />
<link href="https://unpkg.com/leaflet.markercluster#1.3.0/dist/MarkerCluster.Default.css" rel="stylesheet" />
<script src="https://unpkg.com/leaflet#1.3.3/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet.markercluster#1.3.0/dist/leaflet.markercluster.js"></script>
<script src="https://unpkg.com/Leaflet.Deflate#1.0.0-alpha.2/dist/L.Deflate.js"></script>
</head>
<body>
<div id="map"></div>
</body>
</html>
why does the cluster coverage on hover not show?
coverage is not shown if there are only 2 objects... :|
adding a third object, e.g.:
var polyline2 = L.polyline([
[51.535, -0.1],
[51.525, -0.05],
], {
color: 'green'
});
deflate_features.addLayer(polyline2);
enables cluster coverage:

Mapbox GL JS: Export map to PNG or PDF?

I'm using Mapbox GL JS version 0.32. Is there a way to export the map to a high-res PNG or PDF?
Obviously, I can just screenshot, but it would be nice if there was a more formal way.
I found this repo, but it looks old and isn't clear how it works.
I tried using the preserveDrawingBuffer option:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
minZoom: 4,
maxZoom: 14,
center: [-2.0, 53.3],
preserveDrawingBuffer: true
});
console.log(map.getCanvas().toDataURL());
This outputs a long data URL in the console, but copying and pasting it into a base64 converter just seems to produce an empty image.
UPDATE: This is my new code, in full:
mapboxgl.accessToken = 'pk.eyXXX';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
minZoom: 4,
maxZoom: 14,
center: [-2.0, 53.3],
preserveDrawingBuffer: true
});
var dpi = 300;
Object.defineProperty(window, 'devicePixelRatio', {
get: function() {return dpi / 96}
});
map.on('load', function () {
var content = map.getCanvas().toDataURL();
console.log(content)
});
The output to the console is this: http://pastebin.com/raw/KhyJkJWJ
There are two main questions:
1. How do I get the map canvas as an image?
Actually, you are doing the right thing, but just too early. Give that map some time to load and fetch the image data when the load event is triggered:
map.on('load', () => console.log(map.getCanvas().toDataURL()));
2. How do I get that image in high-res?
By changing window.devicePixelRatio according to your destination dpi, you can trick your browser into generating high-res output. I found that solution in an implementation created by Matthew Petroff, see his code on https://github.com/mpetroff/print-maps.
This is the trick he's using for generating high-res output:
Object.defineProperty(window, 'devicePixelRatio', {
get: function() {return dpi / 96}
});
Source
I created a simple working example for anybody stumbling upon this thread:
(Thanks #Vic for pointing out the preserveDrawingBuffer-option in Mapbox GL JS)
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Display a map</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css' rel='stylesheet' />
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<style>
#map {
margin: auto;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<div id='map'></div>
<a id="downloadLink" href="" download="map.png">Download ↓</a>
<div id="image"></div>
<script>
mapboxgl.accessToken = 'your-token-here';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [-74.50, 40],
zoom: 9,
preserveDrawingBuffer: true
});
$('#downloadLink').click(function() {
var img = map.getCanvas().toDataURL('image/png')
this.href = img
})
</script>
</body>
</html>