I have made a lot of try and mix between the mapbox's examples and the stackflow's posts.
I can't disable the default blue marker but this code works fine.
<link href="https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.js"></script>
<style>
#map { position:absolute; top:0; bottom:0; width:80%; }
#marker {
background-image: url('https:/letraitdelas.ddns.net/test2/forecast/weather/113.png');
background-size: cover;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
}
.mapboxgl-popup {
max-width: 200px;
}
</style>
<body>
<?php
$index = 0;
$towns = file_get_contents('towns.json');
$towns = json_decode($towns);
echo "<pre>";
print_r($towns);
echo "</pre>";
?>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'YOUR TOKEN HERE';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [2.751802, 47.50655],
zoom: 10
});
<?php foreach($towns as $town){
$lat = $town[1];
$lon = $town[2];
?>
// var monument = [2.751802, 47.50655];
var town<?php echo $index; ?> = <?php echo "[" . $lon . ", " . $lat . "]"; ?>;
// create the popup
var popup<?php echo $index; ?> = new mapboxgl.Popup(
{offset:[28, 0]}
).setText(
'Location : Le Trait de Las'
);
// create the marker
let marker<?php echo $index; ?> = new mapboxgl.Marker().setLngLat(town<?php echo $index; ?>);
// get the marker element
const element<?php echo $index; ?> = marker<?php echo $index; ?>.getElement();
element<?php echo $index; ?>.id = 'marker<?php echo $index; ?>'
// hover event listener
element<?php echo $index; ?>.addEventListener('mouseenter', () => popup<?php echo $index; ?>.addTo(map));
element<?php echo $index; ?>.addEventListener('mouseleave', () => popup<?php echo $index; ?>.remove());
// add popup to marker
marker<?php echo $index; ?>.setPopup(popup<?php echo $index; ?>);
// add marker to map
marker<?php echo $index; ?>.addTo(map);
<?php
$index = $index + 1;
}
?>
</script>
</body>
So my question is how to disable the blue marker and only have the marker that shows the weather (my variable custom icon) ?
The path of the weather icon is in the array 'towns.json' and is updated one time each day from a forecast weather api.
So in my loop I will change
background-image: url('https:/letraitdelas.ddns.net/test2/forecast/weather/113.png');
by the towns[3] value which is the path of the updated icon.
Best regards.
So I think i've solved it.
I took the examples of "popup hover" and "custom marker" on mapbox site.
I don't need the geoson array because I have a json which give me [latitude, longitude, location name, iconPath].
My code is only with one location but I just have to make my loops like I done in the first post.
I hope It can help someone else and I wait for all the comments and avices you can give to me.
Best Regards.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Add custom icons with Markers</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.8.2/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<style>
.marker {
display: block;
border: none;
border-radius: 50%;
cursor: pointer;
padding: 0;
}
</style>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'YOUR TOKEN HERE';
// Create a DOM element for each marker.
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [2.751802, 47.50655],
zoom: 10
});
// Create a DOM element for each marker.
const el = document.createElement('div');
el.className = 'marker';
el.style.backgroundImage = 'url(https://letraitdelas.ddns.net/test2/forecast/weather/113.png)';
el.style.width = '50px';
el.style.height = '50px';
el.style.backgroundSize = '100%';
// create the popup
var popup = new mapboxgl.Popup().setText('Location : Le Trait de Las');
// hover event listener
el.addEventListener('mouseenter', () => popup.addTo(map));
el.addEventListener('mouseleave', () => popup.remove());
let mymarker = new mapboxgl.Marker().setLngLat([2.751802, 47.50655]);
// add popup to marker
mymarker.setPopup(popup);
// Add markers to the map.
new mapboxgl.Marker(el)
.setLngLat([2.751802, 47.50655])
.addTo(map);
</script>
</body>
</html>
Related
I have created a simple leaflet web app that allows for the user to search for the countries that they have traveled.
The user can use a search box or click on the layer on the map. either action will highlight the country green and load the name and flag in an adjacent table.
This works fine. However, problems arise should the user decide to remove a country visited (for example they made a mistake when selecting)
I have included the ability to delete the table items by user click and enabled a function on double click of the layer itself to reset the colour.
What I need is for these two actions to relate to one another. so if the user removes the flag, the related country is reset and vis versa.
I think I need some sort of listener on the click remove or highlight function or perhaps defining the symbology based on the user-generated table of countries visited. Any suggestions?
<!DOCTYPE html>
<html>
{% load static %}
{% load leaflet_tags %}
<head>
{% leaflet_js %}
{% leaflet_css %}
<script type="text/javascript" src="{% static 'dist/leaflet.ajax.js' %}"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<title>hello world</title>
<link rel="stylesheet" href="{% static 'leaflet-groupedlayercontrol/leaflet.groupedlayercontrol.min.css' %}" />
<link rel="stylesheet" href="https://labs.easyblog.it/maps/leaflet-search/src/leaflet-search.css" />
<link rel="stylesheet" href="https://labs.easyblog.it/maps/leaflet-search/examples/style.css" />
<style type="text/css">
#findbox {
background: #eee;
border-radius: 0.125em;
border: 2px solid #1978cf;
box-shadow: 0 0 8px #999;
margin-bottom: 10px;
padding: 2px 0;
width: 600px;
height: 26px;
}
.search-tooltip {
width: 200px;
}
.leaflet-control-search .search-cancel {
position: static;
float: left;
margin-left: -22px;
}
#map {
width: 50%;
height: 650px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<p style="text-align: center; font-size: 24px; color: #175b81; font-weight: bold;"></p>
<h3>My World Map</h3>
<div id="findbox"></div>
<div id="map" style="height: 680px; width: 48%; display: ;"></div>
<div class="sidebar" style="display: right;">
<p style="text-align: centre; font-size: 24px; color: #175b81; font-weight: bold;">My Flags:</p>
<table style="width: 90%;">
<tr>
<td id="name" hidden></td>
<td id="code" hidden></td>
</tr>
<ul id="Countries_Visted"></ul>
</table>
</div>
<script>
var img1 = "<img src=";
var im2 = ">";
var quotes = "'";
var flagimage_pt1 = "https://www.countryflags.io/";
var flagimage_pt2 = "/flat/64.png";
// creating mapbox basemap
var mapboxAccessToken =
"pk.eyJ1IjoiY2hyaXNyeWFuLXRlY2giLCJhIjoiY2thY2c3bDZyMDZsNDJ4cHJlZmhwZmFjaCJ9.3GuHRvRz-8fxi4r103z05w";
var mapbox = L.map("map").setView([46.0, 8.0], 2.2);
mapbox.doubleClickZoom.disable();
L.tileLayer(
"https://api.mapbox.com/styles/v1/chrisryan-tech/ckaxvc0bt10041iqfz5fb7dgj/tiles/256/{z}/{x}/{y}#2x?access_token=" +
mapboxAccessToken,
{
tileSize: 512,
zoomOffset: -1,
attribution:
'© Mapbox © OpenStreetMap',
}
).addTo(mapbox);
//loading data with style, click function and listener
var data_layer = new L.GeoJSON.AJAX("{% url 'borders_data' %}", {
style: countriesStyle,
onEachFeature: countriesOnEachFeature,
});
//listener - adding to map on load
data_layer.on("data:loaded", function (e) {
layer.addTo(mapbox);
});
function countriesStyle(feature) {
return {
fillColor: "grey",
weight: 2,
opacity: 0.2,
color: "grey",
dashArray: 3,
fillOpacity: 0.2,
};
}
function countriesOnEachFeature(feature, layer) {
layer.on({
click: function (e) {
var layer = e.target;
layer.setStyle({
weight: 1,
color: "#fff",
dashArray: "",
fillOpacity: 0.9,
fillColor: "green",
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
},
});
layer.on({
click: load_name_flag,
});
layer.on({
dblclick: clear,
});
}
///// clearing styling
var layer = data_layer;
function clear(e) {
layer.resetStyle(e.target);
}
///// adding to clicked countries to countries visted list
function load_name_flag(e) {
var field1 = document.getElementById("name");
field1.innerHTML = e.target.feature.properties.name;
var field2 = document.getElementById("code");
field2.innerHTML = e.target.feature.properties.iso2;
var selected_name_search = field1.innerHTML;
var selected_flag_search = img1 + quotes + flagimage_pt1 + field2.innerHTML + flagimage_pt2 + quotes + im2;
var selected_features_combine = selected_name_search + selected_flag_search;
$("#Countries_Visted").append("<li>" + selected_features_combine + "</li>").disabled = true;
}
</script>
<!- search box functionality - searches attribute data -->
<!- contained within Geojson from loaded event listener -->
<script src="https://unpkg.com/leaflet#1.3.0/dist/leaflet.js"></script>
<script src="https://labs.easyblog.it/maps/leaflet-search/src/leaflet-search.js"></script>
<script>
//pointing search function to map layer
var searchControl = new L.Control.Search({
container: "findbox",
layer: data_layer,
initial: false,
collapsed: false,
propertyName: "name",
marker: false,
});
// search box finds layer and adds country name and flag, changes layer symbol to green
searchControl.on("search:locationfound", function (e) {
var field1 = document.getElementById("name");
field1.innerHTML = e.layer.feature.properties.name;
var field2 = document.getElementById("code");
field2.innerHTML = e.layer.feature.properties.iso2;
var selected_name_search = field1.innerHTML;
var selected_flag_search = img1 + quotes + flagimage_pt1 + field2.innerHTML + flagimage_pt2 + quotes + im2;
var selected_features_combine = selected_name_search + selected_flag_search;
// styles for selected country
e.layer.setStyle({ fillColor: "green", color: "black", fillOpacity: 0.8 });
/// adding name and flag to countriesvisted list from searchbox select
$("#Countries_Visted").append("<li>" + selected_features_combine + "</li>").disabled = true;
});
mapbox.addControl(searchControl); //inizialize search control
// function to remove added layers
Countries_Visted.onclick = function remove(e) {
var li = e.target;
var layer = data_layer;
var listItems = document.querySelectorAll("li");
var ul = document.getElementById("ul");
li.parentNode.removeChild(li);
layer.resetStyle(e.target);
};
</script>
</body>
</html>
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.
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
I have 2 toolbars in my scrpit one to add markers and another one to search locations but when i had both in the scrpit the location bar stop fiding location can you tell me why ? i am new at leaflet and mapbox
<style>
#geocoder-container {
position: absolute;
top: 0;
width: 100%;
margin-top: 10px;
}
#geocoder-container > div {
min-width:50%;
margin-left:25%;
}
</style>
<div id='map'></div>
<div id='geocoder-container'></div>
<script>
<!-- MAP Feature-->
L.mapbox.accessToken = 'pk.eyJ1Ijoib2JlY2VuZSIsImEiOiJjaXNicjdja3kwMDE3MnBvMGppMWpubDBqIn0.L4r0u_Em0utvCuFmqbsWQw';
var map = L.mapbox.map('map', 'mapbox.streets')
.setView([38.89399, -77.03659], 17);
var featureGroup = L.featureGroup().addTo(map);
<!-- MAP Feature-->
<!-- Tolbar eddit -->
var drawControl = new L.Control.Draw({
edit: {
featureGroup: featureGroup
}
}).addTo(map);
map.on('draw:created', function(e) {
featureGroup.addLayer(e.layer);
});
var geocoder = new mapboxgl.Geocoder({
container: 'geocoder-container'
});
map.addControl(geocoder);
</script>
</body>
</html>
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 © 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").