How to automatically update Mapbox when a website updated - mapbox

I am looking to add markers to Mapbox. These markers will contain links to other websites and I am looking to automatically plot real-time data on the map when the website updates its articles, with a link to the website + shortened version of whatever is being said on the article. Could anyone share any tips?

Can you please share what you have done so far?
You question is very general. Therefore I can only advise to not update the complete website with each change, but use jQuery and update changes incrementally.
In Mapbox, you can add layers. These layers have data sources. When you update the data sources for the layers (that already have been created), the data displayed will be updated with them.
Pleas see this example that adds a periodically updating layer:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Add live realtime data</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = "<Access Token>";
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
zoom: 0
});
var url = 'https://wanderdrone.appspot.com/';
map.on('load', function () {
var request = new XMLHttpRequest();
window.setInterval(function () {
// make a GET request to parse the GeoJSON at the url
request.open('GET', url, true);
request.onload = function () {
if (this.status >= 200 && this.status < 400) {
// retrieve the JSON from the response
var json = JSON.parse(this.response);
// update the drone symbol's location on the map
map.getSource('drone').setData(json);
// fly the map to the drone's current location
map.flyTo({
center: json.geometry.coordinates,
speed: 0.5
});
}
};
request.send();
}, 2000);
map.addSource('drone', { type: 'geojson', data: url });
map.addLayer({
'id': 'drone',
'type': 'symbol',
'source': 'drone',
'layout': {
'icon-image': 'rocket-15'
}
});
});
</script>
</body>
</html>

Related

How to add a custom marker to a mapbox map that displays popups on hover?

I apologize in advance if my question sounds stupid, but I am in way over my head here …
I am trying to create a map with mapbox with custom markers that display a popup on hover. I followed this tutorial, copied the code and added my places and descriptions, but I can’t change the URL of the custom marker. Is there a way to change the code so I can keep the hover effect, but with my custom markers?
Thank you very much!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a popup on hover</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<style>
.mapboxgl-popup {
max-width: 400px;
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
}
</style>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoicGllcm8xMDEiLCJhIjoiY2toNHY1ejFqMGV5ajJyczVxeHAwcHo3eCJ9.xauie-TVwLVSYj3l6AAmOw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-77.04, 38.907],
zoom: 11.15
});
map.on('load', function () {
map.loadImage(
'https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png',
// Add an image to use as a custom marker
function (error, image) {
if (error) throw error;
map.addImage('custom-marker', image);
map.addSource('places', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {
'description':
'<strong>Make it Mount Pleasant</strong><p>Make it Mount Pleasant is a handmade and vintage market and afternoon of live entertainment and kids activities. 12:00-6:00 p.m.</p>'
},
'geometry': {
'type': 'Point',
'coordinates': [-77.038659, 38.931567]
}
},
]
}
});
// Add a layer showing the places.
map.addLayer({
'id': 'places',
'type': 'symbol',
'source': 'places',
'layout': {
'icon-image': 'custom-marker',
'icon-allow-overlap': true
}
});
}
);
// Create a popup, but don't add it to the map yet.
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
map.on('mouseenter', 'places', function (e) {
// Change the cursor style as a UI indicator.
map.getCanvas().style.cursor = 'pointer';
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.description;
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
// Populate the popup and set its coordinates
// based on the feature found.
popup.setLngLat(coordinates).setHTML(description).addTo(map);
});
map.on('mouseleave', 'places', function () {
map.getCanvas().style.cursor = '';
popup.remove();
});
});
</script>
</body>
</html>
Your code works perfectly, including the popup on hover. To change the marker image, replace the URL used here...
map.loadImage(
'https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png'
...to another URL, like this:
map.loadImage(
'https://i.imgur.com/kiw0dR2.png'
Here's a screenshot of your code and map before and after changing the URL.
Please note that your token pk.ey... should be kept private, not shared on public forums. To protect this token from unauthorized use, you can rotate this token apply URL restrictions so it only works on a site like CodePen or JSFiddle.

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>

ArcGis layers on mapbox gl

I'm trying to add a layer from an api on ArcGis:
https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Facility_and_Structure/MapServer/1
In leaflet it is posible with:
L.esri.featureLayer({
url:"https://maps2.dcgis.dc.gov/dcgis/rest/services/DCGIS_DATA/Facility_and_Structure/MapServer/1",
style: function () {
return { color: "#70ca49", weight: 2 };
}
}).addTo(map);
Is there a way to do this on mapboxgl?
Hi Jorge Monroy - Mapbox GL JS expects the data sources as such. In your case where you're wanting to load building footprints from an ArcGIS REST Service, your best bet is to load them as a geojson.
It looks like you're publishing the services from ArcServer 10.31. In that case, the way that I've loaded ArcGIS REST services is by exposing them through AGOL as explained there. If you have that option, that seems easiest. Otherwise, there are other (work-arounds)[https://gis.stackexchange.com/questions/13029/converting-arcgis-server-json-to-geojson] that I've no experience with.
Using Washington D.C. as an example, if you navigate to: http://opendata.dc.gov/datasets/building-footprints and then click on APIs, you can copy the link to the geojson service.
You can then load into MapboxGL JS through the data property of the geojson source shown there.
You can use leaflet-mapbox-gl.js to integrate leaflet and mapbox. Get token from mapbox and add it to below example to make it work.
References: https://github.com/mapbox/mapbox-gl-leaflet
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.5.0/mapbox-gl.css' rel='stylesheet' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.5.0/mapbox-gl.js'></script>
<script src="https://unpkg.com/mapbox-gl-leaflet/leaflet-mapbox-gl.js"></script>
<script src="https://unpkg.com/esri-leaflet/dist/esri-leaflet.js"></script>
<style>
html, body, #map {
margin:0; padding:0; width : 100%; height : 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var token = "";//add token before running this example
const INITIAL_VIEW_STATE = {
latitude: 45.528,
longitude: -122.680,
zoom: 13
};
var map = L.map('map').setView([45.528, -122.680], 13);
L.esri.basemapLayer("NationalGeographic").addTo(map);
var parks = L.esri.featureLayer({
url: "https://services.arcgis.com/rOo16HdIMeOBI4Mb/arcgis/rest/services/Portland_Parks/FeatureServer/0",
style: function () {
return { color: "#70ca49", weight: 2 };
}
}).addTo(map);
var gl = L.mapboxGL({
accessToken: token,
style: 'mapbox://styles/mapbox/dark-v10'
}).addTo(map);
//To add anything on mapbox, first access the mapbox using getMapboxMap()
gl.getMapboxMap().on('load', () => {
//To load any layer on mapbox
//gl.getMapboxMap().addLayer();
});
var popupTemplate = "<h3>{NAME}</h3>{ACRES} Acres<br><small>Property ID: {PROPERTYID}<small>";
parks.bindPopup(function(e){
return L.Util.template(popupTemplate, e.feature.properties)
});
</script>
</body>
</html>

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>

How to specify accessToken for Mapbox with Leaflet

From Mapbox site I tested this code and success:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title></title>
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.cs
<style>
body { margin:0; padding:0; }
.map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id='map' class='map'> </div>
<script>
var map = new L.Map('map', {
center: new L.LatLng(51.505, -0.09),
zoom: 8,
layers: new L.TileLayer('https://a.tiles.mapbox.com/v3/mapbox.world-bright/{z}
});
</script>
</body>
</html>
How can I access my own map with markers and features? I suppose the "mapbox.world-bright" would be replaced by my own map.id, but how can I set the accessToken?
For some reasons I need to stick with Leaflet, and don't want to switch to mapbox.js.
It's just a matter of using the right url in L.TileLayer. You'll need to add your mapId and token and use the correct attribution. It's also much better if you load the tiles from multiple subdomains because your browser can handle up to four connection as once. Code example:
L.tileLayer('https://{s}.tiles.mapbox.com/v4/{mapId}/{z}/{x}/{y}.png?access_token={token}', {
attribution: '© Mapbox © OpenStreetMap',
subdomains: ['a','b','c','d'],
mapId: 'myMapId',
token: 'myUserToken'
});
To add the features of your map you'll need to query those in a separate request. Here's an example using jQuery. You'll need to swap the MAPID and TOKEN for your mapid and token ofcourse:
$.getJSON('http://a.tiles.mapbox.com/v4/MAPID/features.json?access_token=TOKEN', function (data) {
// Assuming the variable map contains your mapinstance
var geojson = L.geoJson(data).addTo(map);
map.fitBounds(geojson.getBounds());
});
Here's a working example on Plunker: http://plnkr.co/edit/h8F3kC?p=preview