Marker tooltips outside the map in MAPBOX JS - popup

I created a mapbox map with markers based on the latitude and longitude in my database.
now I need to insert on my mapbox map, when I click on a marker, a popup that is not above the marker but lateral, outside the map. I need that when I click on a marker on the map, I open a side panel in which to insert various information.
I have tried with this: https://docs.mapbox.com/mapbox.js/example/v1.0.0/marker-tooltips-outside-map/ but I don't know if it is ok.
how can I do?
this is my code
<?php
$connection = mysqli_connect("localhost","root","","mytable") or die("Error " . mysqli_error($connection));
$sql = "select * from mytable";
$result = mysqli_query($connection, $sql) or die("Error in Selecting " . mysqli_error($connection));
$geojson = array(
'type' => 'FeatureCollection',
'features' => array()
);
while ($row =mysqli_fetch_assoc($result)) {
$properties = $row;
$feature = array(
'type' => 'Feature',
'geometry' => array(
'type' => 'Point',
'coordinates' => array(
$row['longitude'],
$row['latitude']
)
),
'properties' => $properties
);
array_push($geojson['features'], $feature);
}
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"/>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<script src='https://api.mapbox.com/mapbox-gl-js/v2.7.0/mapbox-gl.js'></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map" style='width: 100%; height: 100%;'></div>
<script>
mapboxgl.accessToken =mytoken;
var geo = <?php echo(json_encode($geojson)); ?>;
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/ckzvceby8000c15mftv62np1l',
center: [12.932228160498084, 42.36956868099429],
zoom: 7
});
for (const marker of geo.features) {
const el = document.createElement('div');
new mapboxgl.Marker()
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup({ offset: 25 })
.setHTML(`<p>${marker.properties.nome}</p>`)).addTo(map);}
const geocoder = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
placeholder: 'Cerca Località',
mapboxgl: mapboxgl,
marker: false
});
map.addControl(geocoder);
map.addControl(new mapboxgl.NavigationControl());
</script>
</body>
</html>

Related

changing the color of polylines and marker icon's when the layer changes?

Let's say I'm a purple polyline and am using a purple icon for markers with one layer but wanted to use orange polylines and orange marker icon's for another layer. How would I do that? Is there an onlayerchange event? But even if there were how could I change all the icon's for all the markers? Alternatively, maybe I could delete all the markers and then replace them, albeit with a different icon, but idk how to delete markers, en masse or otherwise.
Any ideas?
I am not sure if I understood correctly but here is what you can do.
If you want to toggle between markers with polylines and assign different color you can use this plugin and return icon markers by passing the color.
const icon = (color) => L.icon({
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40],
iconUrl: `https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-${color}.png`,
shadowUrl: "https://unpkg.com/leaflet#1.6/dist/images/marker-shadow.png"
});
and then you have the latlngs and assing to the markers an icon with the prefered color
var places1 = [
{ latlng: [39.61, -105.02], popup: 'This is Littleton, CO.'},
{ latlng: [39.74, -104.99], popup: 'This is Denver, CO.'},
{latlng: [39.73, -104.8], popup: 'This is Aurora, CO.'}
];
places1.forEach(place => L.marker(place.latlng, {
icon: icon('violet')
}).bindPopup(place.popup).addTo(cities1))
and here define the polyline color
L.polyline(places1.map(({latlng}) => latlng), {
color: 'purple'
}).addTo(cities1);
Similarly you can follow the same steps for any other overlay
<!DOCTYPE html>
<html>
<head>
<title>Layers Control Tutorial - Leaflet</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<style>
html,
body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
var cities1 = L.layerGroup();
var cities2 = L.layerGroup();
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
const icon = (color) => L.icon({
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40],
iconUrl: `https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-${color}.png`,
shadowUrl: "https://unpkg.com/leaflet#1.6/dist/images/marker-shadow.png"
});
var places1 = [{
latlng: [39.61, -105.02],
popup: 'This is Littleton, CO.'
},
{
latlng: [39.74, -104.99],
popup: 'This is Denver, CO.'
},
{
latlng: [39.73, -104.8],
popup: 'This is Aurora, CO.'
}
];
places1.forEach(place => L.marker(place.latlng, {
icon: icon('violet')
}).bindPopup(place.popup).addTo(cities1))
var places2 = [{
latlng: [39.77, -105.23],
popup: 'This is Golden, CO.'
},
{
latlng: [39.75, -105.16],
popup: 'This is Applewood, CO.'
}
];
places2.forEach(place => L.marker(place.latlng, {
icon: icon('orange')
}).bindPopup(place.popup).addTo(cities2))
L.polyline(places1.map(({
latlng
}) => latlng), {
color: 'purple'
}).addTo(cities1);
L.polyline(places2.map(({
latlng
}) => latlng), {
color: 'orange'
}).addTo(cities2);
var overlays = {
"cities1": cities1.addTo(map),
"cities2": cities2
};
L.control.layers(null, overlays).addTo(map);
</script>
</body>
</html>
For the scenario you want to change the color upon baselayer change:
you can still reuse icon() function and use now the follow chunk to change the color dynamically when the layer is changed by listening to map's baselayerchange event
function addMarkersAndPolyline(color) {
places.forEach(place => L.marker(place.latlng, {
icon: icon(color)
}).bindPopup(place.popup).addTo(cities))
L.polyline(places.map(({
latlng
}) => latlng), {
color
}).addTo(cities);
}
<!DOCTYPE html>
<html>
<head>
<title>Layers Control Tutorial - Leaflet</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<style>
html,
body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
var cities = L.layerGroup();
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
});
var mbAttr = 'Map data © OpenStreetMap contributors, ' +
'Imagery © Mapbox',
mbUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';
var grayscale = L.tileLayer(mbUrl, {
id: 'mapbox/light-v9',
tileSize: 512,
zoomOffset: -1,
attribution: mbAttr
}),
streets = L.tileLayer(mbUrl, {
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1,
attribution: mbAttr
});
var baseLayers = {
"Grayscale": grayscale.addTo(map),
"Streets": streets
};
const icon = (color) => L.icon({
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40],
iconUrl: `https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-${color}.png`,
shadowUrl: "https://unpkg.com/leaflet#1.6/dist/images/marker-shadow.png"
});
var places = [{
latlng: [39.61, -105.02],
popup: 'This is Littleton, CO.'
},
{
latlng: [39.74, -104.99],
popup: 'This is Denver, CO.'
},
{
latlng: [39.73, -104.8],
popup: 'This is Aurora, CO.'
}
];
function addMarkersAndPolyline(color) {
places.forEach(place => L.marker(place.latlng, {
icon: icon(color)
}).bindPopup(place.popup).addTo(cities))
L.polyline(places.map(({
latlng
}) => latlng), {
color
}).addTo(cities);
}
addMarkersAndPolyline('violet')
map.on('baselayerchange', function(e) {
cities.clearLayers();
if (e.name === 'Streets') {
addMarkersAndPolyline('orange');
return
}
addMarkersAndPolyline('violet');
});
var overlays = {
"cities1": cities.addTo(map),
};
L.control.layers(baseLayers, overlays).addTo(map);
</script>
</body>
</html>

changing the default layer in leafletjs

In https://leafletjs.com/examples/layers-control/example.html there are two layers - Grayscale and Streets. It defaults to Grayscale but how would one change the default to Streets instead?
In that example there's this:
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
layers: [grayscale, cities]
});
I tried swapping the order of the variables in layers but that didn't do anything.
There's also this:
var baseLayers = {
"Grayscale": grayscale,
"Streets": streets
};
I tried reversing that, as well, without success.
I even tried renaming the names of the layers, thinking that it might be done alphabetically, but no such luck.
Any ideas?
It has to do with which layer has been added to the map. So remove the array layers from the map instance and add streets layer to the map. That will define the preselected layer.
<!DOCTYPE html>
<html>
<head>
<title>Layers Control Tutorial - Leaflet</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<style>
html,
body {
height: 100%;
margin: 0;
}
#map {
width: 600px;
height: 400px;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
var cities = L.layerGroup();
L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.').addTo(cities),
L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.').addTo(cities),
L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.').addTo(cities),
L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.').addTo(cities);
var mbAttr = 'Map data © OpenStreetMap contributors, ' +
'Imagery © Mapbox',
mbUrl = 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';
var map = L.map('map', {
center: [39.73, -104.99],
zoom: 10,
});
var grayscale = L.tileLayer(mbUrl, {
id: 'mapbox/light-v9',
tileSize: 512,
zoomOffset: -1,
attribution: mbAttr
});
var streets = L.tileLayer(mbUrl, {
id: 'mapbox/streets-v11',
tileSize: 512,
zoomOffset: -1,
attribution: mbAttr
}).addTo(map)
var baseLayers = {
"Streets": streets,
"Grayscale": grayscale
};
var overlays = {
"Cities": cities
};
L.control.layers(baseLayers, overlays).addTo(map);
</script>
</body>
</html>

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>

Mapbox separate geocoder two autocomplete inputs css output visual crossing problem

I've got mapbox separate geocoder two autocomplete inputs with output CSS visual crossing problem - when I input something, class .suggestions-wrapper goes underneath the second input (input.mapboxgl-ctrl-geocoder--input) is there any way to make it work properly?
<html>
<head>
<link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.6.1/mapbox-gl.css">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.4.2/mapbox-gl-geocoder.css">
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.6.1/mapbox-gl.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v4.0.2/mapbox-gl-directions.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.4.2/mapbox-gl-geocoder.min.js"></script>
<script>
$( document ).ready(function() {
mapboxgl.accessToken = 'pk.eyJ1IjoidmltcGlsIiwiYSI6ImNrMjhvNXU0MTIyZGszbG16dWw1enVlamwifQ.5DWWvMDwGn1VfUD9uJjBEg';
var map = new mapboxgl.Map({
container: 'map_home_page',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-79.4512, 43.6568],
zoom: 13
});
window.pick_up_forntinput = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
placeholder:'Pick Up Location',
countries: 'gb',
});
document.getElementById('pick_up_forntinput').appendChild(pick_up_forntinput.onAdd(map));
window.dropp_off_forntinput = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
placeholder:'Dropp Off Location',
countries: 'gb',
});
document.getElementById('dropp_off_forntinput').appendChild(dropp_off_forntinput.onAdd(map));
});
</script>
<body>
<div id="pick_up_forntinput" class="geocoder"></div>
<div id="dropp_off_forntinput" class="geocoder"></div>
<div id="map_home_page"></div>
</body>
</html>
There is two ways to resolve this problem for now:
1) change CSS style for 1st field so the .suggestions class with all the addresses go under the 2nd field;
#pick_up_forntinput ul.suggestions {
top: 60px;
position: absolute;
}
2) making the script for 2nd field so it will disappear on .suggestions class appear
$(document).ready(function() {
mapboxgl.accessToken = 'pk.eyJ1IjoidmltcGlsIiwiYSI6ImNrMjhvNXU0MTIyZGszbG16dWw1enVlamwifQ.5DWWvMDwGn1VfUD9uJjBEg';
var map = new mapboxgl.Map({
container: 'map_home_page',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-79.4512, 43.6568],
zoom: 13
});
window.pick_up_forntinput = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
placeholder: 'Pick Up Location',
countries: 'gb',
});
document.getElementById('pick_up_forntinput').appendChild(pick_up_forntinput.onAdd(map));
window.dropp_off_forntinput = new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl,
placeholder: 'Dropp Off Location',
countries: 'gb',
});
document.getElementById('dropp_off_forntinput').appendChild(dropp_off_forntinput.onAdd(map));
});
$(document).on('input', '#pick_up_forntinput', function() {
setTimeout(function() {
if ($('#pick_up_forntinput .mapboxgl-ctrl-geocoder .suggestions').is(':visible')) {
$('div#dropp_off_forntinput').hide("slow");
} else {
$('div#dropp_off_forntinput').show("slow");
}
}, 300);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.6.1/mapbox-gl.css">
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.4.2/mapbox-gl-geocoder.css">
</head>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.6.1/mapbox-gl.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v4.0.2/mapbox-gl-directions.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.4.2/mapbox-gl-geocoder.min.js"></script>
<script>
</script>
<body>
<div id="pick_up_forntinput" class="geocoder"></div>
<div id="dropp_off_forntinput" class="geocoder"></div>
<div id="map_home_page"></div>
</body>
</html>

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: