No img displayed on the leaflet control - leaflet

My web app contains two basemaps to display. I created a leaflet control layer to manage their visibility :
var baseMaps = {
"Bing Satellite": bingLayer,
"OpenCycleMap": tileLayer
};
L.control.layers(baseMaps).addTo(map);
The issue is the icon which should be within the control doesn't show up. When I inspect, the console renders a 404 error : Failed to load resource: the server responded with a status of 404 (Not Found) on layers-2px.png.
I'm using cdn to call leaflet so I have no clue about the issue!!
Here is the rendering in the map :
Your assistance would be appreciated.
I put a working example.
<html>
<head>
<meta charset=utf-8 />
<title>Leaflet Control.Layers</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<!-- Load Leaflet from CDN -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css"
integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js"
integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA=="
crossorigin=""></script>
<!-- Load Esri Leaflet from CDN -->
<script src="https://unpkg.com/esri-leaflet#2.2.3/dist/esri-leaflet.js"
integrity="sha512-YZ6b5bXRVwipfqul5krehD9qlbJzc6KOGXYsDjU9HHXW2gK57xmWl2gU6nAegiErAqFXhygKIsWPKbjLPXVb2g=="
crossorigin=""></script>
<style>
body { margin:0; padding:0; }
#map { position: absolute; top:0; bottom:0; right:0; left:0; }
</style>
</head>
<body>
<div id="map"></div>
<script>
var gray = L.layerGroup();
// more than one service can be grouped together and passed to the control together
L.esri.basemapLayer("DarkGray").addTo(gray);
L.esri.basemapLayer("GrayLabels").addTo(gray);
var states = L.esri.featureLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",
style: function (feature) {
return {color: '#bada55', weight: 2 };
}
});
var map = L.map('map', {
center: [39, -97.5],
zoom: 4,
layers: [gray, states]
});
var baseLayers = {
"Grayscale": gray,
"Streetmap": L.esri.basemapLayer("Streets")
};
var overlays = {
"U.S. States": states
};
// http://leafletjs.com/reference-1.0.3.html#control-layers
L.control.layers(baseLayers, overlays).addTo(map);
</script>
</body>
</html>

You can modify the background-image property of the following css selectors by setting your custom image:
.leaflet-control-layers-toggle, .leaflet-touch .leaflet-control-layers-toggle {
background-image: url('http://ovrdc.github.io/parcel-viewer/assets/images/layers-bl.png');
background-size: 80%;
margin-top: 0px;
width: 36px;
height: 36px;
}
<html>
<head>
<meta charset=utf-8 />
<title>Leaflet Control.Layers</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<!-- Load Leaflet from CDN -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css"
integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js"
integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA=="
crossorigin=""></script>
<!-- Load Esri Leaflet from CDN -->
<script src="https://unpkg.com/esri-leaflet#2.2.3/dist/esri-leaflet.js"
integrity="sha512-YZ6b5bXRVwipfqul5krehD9qlbJzc6KOGXYsDjU9HHXW2gK57xmWl2gU6nAegiErAqFXhygKIsWPKbjLPXVb2g=="
crossorigin=""></script>
<style>
body { margin:0; padding:0; }
#map { position: absolute; top:0; bottom:0; right:0; left:0; }
.leaflet-control-layers-toggle, .leaflet-touch .leaflet-control-layers-toggle {
background-image: url('http://ovrdc.github.io/parcel-viewer/assets/images/layers-bl.png');
background-size: 80%;
margin-top: 0px;
width: 36px;
height: 36px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var gray = L.layerGroup();
// more than one service can be grouped together and passed to the control together
L.esri.basemapLayer("DarkGray").addTo(gray);
L.esri.basemapLayer("GrayLabels").addTo(gray);
var states = L.esri.featureLayer({
url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3",
style: function (feature) {
return {color: '#bada55', weight: 2 };
}
});
var map = L.map('map', {
center: [39, -97.5],
zoom: 4,
layers: [gray, states]
});
var baseLayers = {
"Grayscale": gray,
"Streetmap": L.esri.basemapLayer("Streets")
};
var overlays = {
"U.S. States": states
};
// http://leafletjs.com/reference-1.0.3.html#control-layers
L.control.layers(baseLayers, overlays).addTo(map);
</script>
</body>
</html>

Related

Leaflet - BindPopup USGS Earthquakes Magnitude

In the brochure, I am making an earthquake map from data that comes from the USGS earthquakes. My question is how can I click and get the magnitude of each of the earthquakes as a popup? The script is as follows:
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.1/dist/leaflet.css" type="text/css">
<script src="https://unpkg.com/leaflet#1.3.1/dist/leaflet.js" type="text/javascript"></script>
<script src="https://unpkg.com/esri-leaflet#2.1.4/dist/esri-leaflet.js"></script>
<script src="/js/leaflet.ajax.min.js" type="text/javascript"></script>
<style>
html, body {
height: 100%;
width: 100%;
margin: 0
}
#mapa {
height: 100%;
width: 100%;
}
</style>
<title>Simbologia</title>
</head>
<body>
<div id="mapa"></div>
<script type="text/javascript">
var mapa = L.map("mapa", {
center: [0, 0],
zoom: 2
});
var capaOrtoFoto = L.esri.basemapLayer("Imagery");
capaOrtoFoto.addTo(mapa);
var url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson";
L.Util.ajax(url).then(
function (datosGeoJOSN) {
var capaTerremotos = L.geoJSON(datosGeoJOSN, {
pointToLayer: function (entidad, latlng) {
return L.circleMarker(latlng);
}
});
capaTerremotos.addTo(mapa);
capaTerremotos.bindPopup().openPopup();
});
</script>
</body>
</html>
How can I make the "bindPopup" function call the magnitude of the earthquake?
Use feature.properties.mag to access the magnitude in your response:
fetch(url)
.then(data => data.json())
.then(data => {
L.geoJSON(data, {
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng).bindPopup(`Magnitude: ${feature.properties.mag}`).openPopup();
}
}).addTo(mapa);
})
Also you can use fetch API which requires no script importing to make the request.
Moreover the version of leaflet, esri-leaflet that you are using seem old.
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" type="text/css">
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" type="text/javascript"></script>
<script src="https://unpkg.com/esri-leaflet#3.0.4/dist/esri-leaflet.js"></script>
<style>
html,
body {
height: 100%;
width: 100%;
margin: 0
}
#mapa {
height: 100%;
width: 100%;
}
</style>
<title>Simbologia</title>
</head>
<body>
<div id="mapa"></div>
<script type="text/javascript">
var mapa = L.map("mapa", {
center: [0, 0],
zoom: 2
});
var capaOrtoFoto = L.esri.basemapLayer("Imagery");
capaOrtoFoto.addTo(mapa);
var url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson";
fetch(url)
.then(data => data.json())
.then(data => {
L.geoJSON(data, {
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng).bindPopup(`Magnitude: ${feature.properties.mag}`).openPopup();
}
}).addTo(mapa);
})
</script>
</body>
</html>

How to add my own TIF file to Mapbox GL JS maps in my code?

I am trying to add a TIF file to my Mapbox GL JS code which is in html. I haven't found any relevant solution as to how I can add the file to my html code. Can anyone please tell me how to solve this? I need to upload the Georeferenced TIF file to my map in Mapbox GL JS.
Should I convert the TIF file to some other format? It will be better for me if I can upload the whole TIF file to Mapbox.
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Change a map's style</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.2.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.2.1/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style type='text/css'>
#info {
display: block;
position: relative;
margin: 0px auto;
width: 30%;
padding: 8px;
border: none;
border-radius: 3px;
font-size: 14px;
text-align: center;
color: #222;
background: #fff;
}
</style>
<style>
#menu {
position: absolute;
background: #fff;
padding: 10px;
font-family: 'Open Sans', sans-serif;
}
</style>
<div id='map'></div>
<div id='menu'>
<input id='streets-v11' type='radio' name='rtoggle' value='streets' checked='checked'>
<label for='streets'>streets</label>
<input id='light-v10' type='radio' name='rtoggle' value='light'>
<label for='light'>light</label>
<input id='dark-v10' type='radio' name='rtoggle' value='dark'>
<label for='dark'>dark</label>
<input id='outdoors-v11' type='radio' name='rtoggle' value='outdoors'>
<label for='outdoors'>outdoors</label>
<input id='satellite-v9' type='radio' name='rtoggle' value='satellite'>
<label for='satellite'>satellite</label>
</div>
<pre id='info'></pre>
<script>
mapboxgl.accessToken = 'pk.eyJ1Ijoic2lmYXQ1NzciLCJhIjoiY2p6dXNvN3ZnMGVqZTNjcDRrNWNqcTE5byJ9.Bg8-lwZjjNoswew2k1w2RA';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
zoom: 13,
center: [90.3897, 23.7270]
});
// Add zoom and rotation controls to the map.
map.addControl(new mapboxgl.NavigationControl());
//for displaying the latlon of mouse curson in map
map.on('mousemove', function (e) {
document.getElementById('info').innerHTML =
// e.point is the x, y coordinates of the mousemove event relative
// to the top-left corner of the map
JSON.stringify(e.point) + '<br />' +
// e.lngLat is the longitude, latitude geographical position of the event
JSON.stringify(e.lngLat.wrap());
});
var layerList = document.getElementById('menu');
var inputs = layerList.getElementsByTagName('input');
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/mapbox/' + layerId);
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
</script>
</body>
</html>
One way to do this (as you spoke about) is to convert the georeferenced image to another format. Here is an example of how to add a georeferenced image, as long as you know the geographic bounds :
map.addSource("myImageSource", {
"type": "image",
"url": "test.gif",
"coordinates": [
[-80.425, 46.437],
[-71.516, 46.437],
[-71.516, 37.936],
[-80.425, 37.936]
]
});
map.addLayer({
"id": "overlay",
"source": "myImageSource",
"type": "raster",
"paint": {
"raster-opacity": 0.85
}
});
You can also see https://docs.mapbox.com/mapbox-gl-js/example/image-on-a-map/ for more reference material.

Measuring drawn line length with turf.js and mapbox

I'm trying to build out the functionality to measure a line that a user draws over a Mapbox map, using turf.js 'length' feature.
That said, I'm a coding newb - I know just barely enough to be dangerous.
Ultimately I'd like to be able to draw both areas and lines, and have their respective measures returned (area for polygons, lengths for line strings).
Can anyone offer insight as to why this code doesn't work?
https://jsfiddle.net/knxwu342
<html>
<head>
<meta charset=utf-8 />
<title>Line Test</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
.calculation-box-length {
height: 75px;
width: 100px;
position: absolute;
bottom: 40px;
left: 10px;
background-color: rgba(255, 255, 255, .9);
padding: 15px;
text-align: center;
}
</style>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v3.0.11/turf.min.js'>
</script>
<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.0.9/mapbox-gl-draw.js'></script>
<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.0.9/mapbox-gl-draw.css' type='text/css'/>
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.45.0/mapbox-gl.js'>
</script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.45.0/mapbox-gl.css' rel='stylesheet' />
</head>
<body>
<div id='map'></div>
<div class='calculation-box-length'>
<p>Length:</p>
<div id='calculated-length'></div>
</div>
<nav id="menu"></nav>
<script>mapboxgl.accessToken = 'pk.eyJ1IjoibWJsYWNrbGluIiwiYSI6ImNqaWMxcGk2MzAwd3YzbG1oeW4yOHppdnYifQ.xdb-2slu5LapzpuMCiKzQQ';
//*********-----------------------------------------------------------------------------------------------------------------**********
//Create new map object
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mblacklin/cjii8o7w91g9o2stcktaeixai', // stylesheet location
center: [-117.572737, 51.746916], // starting position [lng, lat]
zoom: 16 // starting zoom
});
//*********-----------------------------------------------------------------------------------------------------------------**********
// Add navigation controls to the map
map.addControl(new mapboxgl.NavigationControl());
//*********-----------------------------------------------------------------------------------------------------------------**********
// Add the ability to draw geometries and display their measurements
//
var draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
line_string: true,
polygon: true,
trash: true
}
});
map.addControl(draw);
map.on('draw.create.', updateLength);
map.on('draw.delete', updateLength);
map.on('draw.update', updateLength);
function updateLength(e) {
var data = draw.getAll();
var answer = document.getElementById('calculated-length');
if (data.features.length > 0) {
var length = turf.length(data);
// restrict to area to 2 decimal points
answer.innerHTML = '<p><strong>' + length + '</strong></p><p> meters</p>';
} else {
answer.innerHTML = '';
if (e.type !== 'draw.delete') alert("Use the draw tools in the upper right to calculate a distance");
}
};
//
//*********-----------------------------------------------------------------------------------------------------------------**********
</script>
</body>
</html>
I see two little problems in your code:
There is a typo in your 'draw.create' listener. Just remove the point after create:
map.on('draw.create', updateLength);
The version of Turf you are using is too old and does not seem to have the length function. Try using the most recent one: https://npmcdn.com/#turf/turf/turf.min.js

Mapbox GL JS: Change a map's style without hiding map layer?

I am using Mapbox GL JS and I would like to allow users to change a map's background style from streets to satellite, while showing a polygon layer above the map background.
I have adapted the Mapbox example, but I can't work out how to stop map.setStyle from setting the new style above (and thus hiding) my polygon layer. I would like it to change without hiding the polygon layer.
Before switching layers:
After switching layers - polygon overlay missing, would like to carry on showing it:
This is my code in full:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></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.33.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.33.1/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
#menu {
position: absolute;
background: #fff;
padding: 10px;
font-family: 'Open Sans', sans-serif;
}
</style>
<div id='map'></div>
<div id='menu'>
<input id='basic' type='radio' name='rtoggle' value='basic' checked='checked'>
<label for='basic'>basic</label>
<input id='satellite' type='radio' name='rtoggle' value='satellite'>
<label for='satellite'>satellite</label>
</div>
<script>
mapboxgl.accessToken = 'pk.eyTOKEN';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/basic-v9',
zoom: 5,
center: [-3.0, 54.6]
});
map.on('load', function () {
map.addSource('xxx', {
type: 'vector',
url: 'mapbox://xxx.xxx'
});
map.addLayer({
'id': 'xxx',
'source': 'xxx',
'type': 'fill',
'paint': {
'fill-color': 'red'
},
'source-layer': mylayer
}, 'road'); // Note that I'd like this to display above the OSM 'roads' layer
var layerList = document.getElementById('menu');
var inputs = layerList.getElementsByTagName('input');
function switchLayer(layer) {
var layerId = layer.target.id;
map.setStyle('mapbox://styles/mapbox/' + layerId + '-v9');
}
for (var i = 0; i < inputs.length; i++) {
inputs[i].onclick = switchLayer;
}
});
</script>
</body>
</html>
Mapbox GL JS does not have the concept of a "base layer" and "overlays." All layers of all maps are drawn with the same basic primitives.
If you need to persist one or more custom layers while switching between the provided Mapbox styles, you may choose to
fork the Mapbox style and add your custom layers in Studio
re-add your custom layers after switching styles
download the Mapbox style as JSON in the browser and add your custom layers to the style in the browser

Open info layer together with click on marker (leaflet)

I would like to trigger an extra event when clicking on a marker. Now, it opens a popup, but instead I would like to show the information in an extra info layer. I have managed to show the layer (var info), but I don't know how to change the information with a click on the marker.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Schönberg Topography</title>
<link rel="stylesheet" href="../lib/mapbox.css" />
<script src="../lib/mapbox.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../dist/MarkerCluster.css" />
<link rel="stylesheet" href="../dist/MarkerCluster.Default.css" />
<script src="../dist/leaflet.markercluster-src.js"></script>
<script charset="UTF-8" src="topography.js"></script>
<style>
body {
padding: 0;
margin: 0;
}
html,
body,
#map {
height: 100%;
}
.info {
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255, 255, 255, 0.8);
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
border-radius: 5px;
}
.info h4 {
margin: 0 0 5px;
color: #777;
}
</style>
<style type="text/css">
a:link {
text-decoration: none;
}
</style>
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<body>
<div id="map"></div>
<script type="text/javascript">
var cloudmadeUrl = 'http://otile1.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png',
cloudmadeAttribution = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 Mapbox, Points &copy 2012 LINZ',
cloudmade = new L.TileLayer(cloudmadeUrl, {
maxZoom: 17,
attribution: cloudmadeAttribution
}),
latlng = new L.LatLng(48.86, 2.34);
var map = new L.Map('map', {
center: latlng,
zoom: 12,
maxBounds: [
[49, 2.7],
[48.7, 2, 45]
],
layers: [cloudmade]
});
var markers = new L.MarkerClusterGroup();
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var name = a[3]
var colormarker = a[4]
var typemarker = a[5]
var marker = L.marker(new L.LatLng(a[0], a[1]), {
icon: L.mapbox.marker.icon({
'marker-symbol': typemarker,
'marker-color': colormarker
}),
title: name
});
var info = L.control();
info.onAdd = function() {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
this.update();
return this._div;
};
// method that we will use to update the control based on feature properties passed
info.update = function() {
this._div.innerHTML = title;
};
marker.bindPopup(title);
markers.addLayer(marker);
}
map.addLayer(markers);
info.addTo(map);
</script>
</body>
</html>
You would need to modify your update function to take a parameter to begin here.You also only need to be creating this info control once, not each time inside the loop..because you only need one open at a time, right?
info.update = function(content) {
this._div.innerHTML = content;
};
Don't forget to update your onAdd with regards to removing the update.
info.onAdd = function() {
this._div = L.DomUtil.create('div', 'info'); // create a div with a class "info"
return this._div;
};
Then, inside the callback for a click event on a marker, you would call info.update("My new content").