Animate multiple point along routes using Mapbox-GL.JS - javascript

I am having problems with following example :
Animate a point along a route
What I am trying to achieve is to make another point and routes in the same map container.
What I tried so far is this
mapboxgl.accessToken = 'pk.eyJ1IjoicGFwYWJ1Y2t0IiwiYSI6ImNqa2k3azQ1dzA1Zmgza3B1czIxOGhhaW4ifQ.h5OT3NaQf0vcxx3g1q1cXw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [118.0148634, -2.548926],
zoom: 4.1
});
var route = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[117.66769409179686,3.2913401805277034],[117.75009155273438,3.2419820359767444],
[117.81188964843751,3.2008484073844365],[117.93273925781249,3.1514858749293237],
[118.048095703125,3.0637245031869744],[118.20190429687501,2.9649843693339677],
[118.35571289062499,2.855262784366583],[118.443603515625,2.789424777005989],
[118.597412109375,2.67419944615503],[118.817138671875,2.4656692707025543],
[118.93798828125,2.191238104506552],[118.97644042968749,1.9442068658308456],
[119.0643310546875,1.6477220517969353],[119.13574218749999,1.334718132769963],
[119.15222167968751,1.0051974541602744],[119.05334472656249,0.5987439850125229],
[118.9215087890625,0.29113644247137116],[118.8006591796875,-0.027465819260582135],
[118.597412109375,-0.5163504323777461],[118.27880859375001,-0.8953492997435784],
[118.16894531249999,-1.219390359762202],[117.83935546874999,-1.6641946615712557],
[117.7349853515625,-1.8618548574369598],[117.65258789062499,-2.0485136203038063],
[117.40539550781249,-2.67968661580376],[117.07580566406249,-3.2721456350750127],
[116.7572021484375,-3.8806964824972487],[116.44958496093749,-4.209464815163466],
[115.7574462890625,-4.335456463573485],[115.213623046875,-4.510714125698484],
[114.6533203125,-4.647604837557583],[114.1864013671875,-4.70235372255946],
[113.79089355468749,-4.7242520745232515],[113.4228515625,-4.8118385341739005],
[112.9669189453125,-4.8282597468669755],[112.28576660156249,-4.844680562025358],
[111.104736328125,-4.855627550617055],[110.7366943359375,-4.855627550617055],
[110.19287109375,-4.855627550617055],[109.60510253906249,-4.926778627933801],
[109.00634765625,-5.00339434502215],[108.4075927734375,-5.036226914872183],
[108.116455078125,-5.189423479732417],[107.5177001953125,-5.369928743247035],
[107.061767578125,-5.473831889192786],[106.76513671875,-5.544913134097361],
[106.44653320312499,-5.626919311742117],[106.248779296875,-5.747174076651375],
[106.1444091796875,-5.807291968003861],[106.02948188781738,-5.882003409958776]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[-252.99316406250003,-5.932972207945653],[-252.92724609374997,-5.774501181937723],
[-252.872314453125,-5.697981985463135],[-252.8118896484375,-5.572249801113899],
[-252.7789306640625,-5.484768018141262],[-252.7294921875,-5.353521355337321],
[-252.66357421875,-5.244127581489528],[-252.57568359374997,-5.112829778499449],
[-252.509765625,-5.00339434502215],[-252.42187499999997,-4.872047700241915],
[-252.2900390625,-4.740675384778361],[-252.11425781249997,-4.653079918274038],
[-252.00439453125,-4.54357027937176],[-251.78466796875,-4.434044005032582],
[-251.65283203125003,-4.34641127533318],[-251.45507812499997,-4.171115454867424],
[-251.16943359375,-4.083452772038619],[-251.03759765625,-3.9738609758391017],
[-250.90576171875,-3.8204080831949407],[-250.70800781249997,-3.688855143147035],
[-250.42236328125,-3.579212785860631],[-250.31250000000003,-3.513421045640032],
[-250.13671875,-3.3818237353282767],[-249.87304687499997,-3.2940822283128046],
[-249.697265625,-3.118576216781991],[-249.697265625,-2.943040910055132]
]
}
}
]
};
// A single point that animates along the route.
// Coordinates are initially set to origin.
var point = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [117.66769409179686,3.2913401805277034]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [-252.99316406250003,-5.932972207945653]
}
}
]
};
// Calculate the distance in kilometers between route start/end point.
for(i=0;i<2;i++) {
var lineDistance = turf.lineDistance(route.features[0], 'kilometers');
}
console.log(lineDistance)
var arc = [];
// Number of steps to use in the arc and animation, more steps means
// a smoother arc and animation, but too many steps will result in a
// low frame rate
var steps = 1000;
// Draw an arc between the `origin` & `destination` of the two points
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
var segment = turf.along(route.features[0], i, 'kilometers');
arc.push(segment.geometry.coordinates);
}
// Update the route with calculated arc coordinates
route.features[0].geometry.coordinates = arc;
// Used to increment the value of the point measurement against the route.
var counter = 0;
map.on('load', function () {
// Add a source and layer displaying a point which will be animated in a circle.
map.addSource('route', {
"type": "geojson",
"data": route
});
map.addSource('point', {
"type": "geojson",
"data": point
});
map.addLayer({
"id": "route",
"source": "route",
"type": "line",
"paint": {
"line-width": 1,
"line-color": "#007cbf"
}
});
map.addLayer({
"id": "point",
"source": "point",
"type": "symbol",
"layout": {
"icon-image": "airport-15",
"icon-rotate": ["get", "bearing"],
"icon-rotation-alignment": "map",
"icon-allow-overlap": true,
"icon-ignore-placement": true
}
});
function animate() {
// Update point geometry to a new position based on counter denoting
// the index to access the arc.
for(i=0;i < 2;i++) {
point.features[i].properties.bearing = turf.bearing(
turf.point(route.features[i].geometry.coordinates[counter >= steps ? counter - 1 : counter]),
turf.point(route.features[i].geometry.coordinates[counter >= steps ? counter : counter + 1])
);
}
point.features[0].geometry.coordinates = route.features[0].geometry.coordinates[counter];
// Update the source with this new data.
map.getSource('point').setData(point);
// Request the next frame of animation so long the end has not been reached.
if (counter < steps) {
requestAnimationFrame(animate);
}
counter = counter + 1;
}
document.getElementById('replay').addEventListener('click', function() {
// Set the coordinates of the original point back to origin
point.features[0].geometry.coordinates = origin;
// Update the source layer
map.getSource('point').setData(point);
// Reset the counter
counter = 0;
// Restart the animation.
animate(counter);
});
// Start the animation.
animate(counter);
});
.overlay {
position: absolute;
top: 10px;
left: 30px;
}
.overlay button {
font:600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
background-color: #3386c0;
color: #fff;
display: inline-block;
margin: 0;
padding: 10px 20px;
border: none;
cursor: pointer;
border-radius: 3px;
}
.overlay button:hover {
background-color:#4ea0da;
}
body { margin:0; padding:0; }
#map { top:0; bottom:0; width:100%;height: 600px }
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Animate a point along a route</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.css' rel='stylesheet' />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js'></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>
<body>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v2.0.0/turf.min.js' charset='utf-8'></script>
<div class="col-md-12">
<div class="card text-white">
<h5 class="card-header bg-info">Featured</h5>
<div class="card-body">
<div class="col-md-12">
<div id='map'></div>
<div class='overlay'>
<button id='replay'>Replay</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
After few things that I tried,the result of first attempt was Point 1 and Line 1 are reaching to the end.but Point 2 and Line 2 stopped after Point 1 and Line 1 are reaching to the end.
This is my 10th attempt. The other attempt was error on the loop.
What should I do with this ?

The basic problem is that the two routes are different lengths, so you go out of bounds on the coordinates for the shorter one while you're still going through the longer one. The snippet I inserted below accounts for that. Trying it just now, my edit completes without errors.
You'll probably want to tweak it a bit further, right now the shorter route completes much more quickly than the longer one, and moves much faster than the longer one. If you want them to appear to go the same speed, you'll need to use fewer steps for for the shorter one. If you want them to complete in the same amount of time, you'll need to add more points to the shorter one, or reduce the frequency with which the shorter one refreshes.
mapboxgl.accessToken = 'pk.eyJ1IjoicGFwYWJ1Y2t0IiwiYSI6ImNqa2k3azQ1dzA1Zmgza3B1czIxOGhhaW4ifQ.h5OT3NaQf0vcxx3g1q1cXw';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v9',
center: [118.0148634, -2.548926],
zoom: 4.1
});
var route = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[117.66769409179686,3.2913401805277034],[117.75009155273438,3.2419820359767444],
[117.81188964843751,3.2008484073844365],[117.93273925781249,3.1514858749293237],
[118.048095703125,3.0637245031869744],[118.20190429687501,2.9649843693339677],
[118.35571289062499,2.855262784366583],[118.443603515625,2.789424777005989],
[118.597412109375,2.67419944615503],[118.817138671875,2.4656692707025543],
[118.93798828125,2.191238104506552],[118.97644042968749,1.9442068658308456],
[119.0643310546875,1.6477220517969353],[119.13574218749999,1.334718132769963],
[119.15222167968751,1.0051974541602744],[119.05334472656249,0.5987439850125229],
[118.9215087890625,0.29113644247137116],[118.8006591796875,-0.027465819260582135],
[118.597412109375,-0.5163504323777461],[118.27880859375001,-0.8953492997435784],
[118.16894531249999,-1.219390359762202],[117.83935546874999,-1.6641946615712557],
[117.7349853515625,-1.8618548574369598],[117.65258789062499,-2.0485136203038063],
[117.40539550781249,-2.67968661580376],[117.07580566406249,-3.2721456350750127],
[116.7572021484375,-3.8806964824972487],[116.44958496093749,-4.209464815163466],
[115.7574462890625,-4.335456463573485],[115.213623046875,-4.510714125698484],
[114.6533203125,-4.647604837557583],[114.1864013671875,-4.70235372255946],
[113.79089355468749,-4.7242520745232515],[113.4228515625,-4.8118385341739005],
[112.9669189453125,-4.8282597468669755],[112.28576660156249,-4.844680562025358],
[111.104736328125,-4.855627550617055],[110.7366943359375,-4.855627550617055],
[110.19287109375,-4.855627550617055],[109.60510253906249,-4.926778627933801],
[109.00634765625,-5.00339434502215],[108.4075927734375,-5.036226914872183],
[108.116455078125,-5.189423479732417],[107.5177001953125,-5.369928743247035],
[107.061767578125,-5.473831889192786],[106.76513671875,-5.544913134097361],
[106.44653320312499,-5.626919311742117],[106.248779296875,-5.747174076651375],
[106.1444091796875,-5.807291968003861],[106.02948188781738,-5.882003409958776]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[-252.99316406250003,-5.932972207945653],[-252.92724609374997,-5.774501181937723],
[-252.872314453125,-5.697981985463135],[-252.8118896484375,-5.572249801113899],
[-252.7789306640625,-5.484768018141262],[-252.7294921875,-5.353521355337321],
[-252.66357421875,-5.244127581489528],[-252.57568359374997,-5.112829778499449],
[-252.509765625,-5.00339434502215],[-252.42187499999997,-4.872047700241915],
[-252.2900390625,-4.740675384778361],[-252.11425781249997,-4.653079918274038],
[-252.00439453125,-4.54357027937176],[-251.78466796875,-4.434044005032582],
[-251.65283203125003,-4.34641127533318],[-251.45507812499997,-4.171115454867424],
[-251.16943359375,-4.083452772038619],[-251.03759765625,-3.9738609758391017],
[-250.90576171875,-3.8204080831949407],[-250.70800781249997,-3.688855143147035],
[-250.42236328125,-3.579212785860631],[-250.31250000000003,-3.513421045640032],
[-250.13671875,-3.3818237353282767],[-249.87304687499997,-3.2940822283128046],
[-249.697265625,-3.118576216781991],[-249.697265625,-2.943040910055132]
]
}
}
]
};
// A single point that animates along the route.
// Coordinates are initially set to origin.
var point = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [117.66769409179686,3.2913401805277034]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Point",
"coordinates": [-252.99316406250003,-5.932972207945653]
}
}
]
};
// Calculate the distance in kilometers between route start/end point.
for(i=0;i<2;i++) {
var lineDistance = turf.lineDistance(route.features[0], 'kilometers');
}
console.log(lineDistance)
var arc = [];
// Number of steps to use in the arc and animation, more steps means
// a smoother arc and animation, but too many steps will result in a
// low frame rate
var steps = 1000;
// Draw an arc between the `origin` & `destination` of the two points
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
var segment = turf.along(route.features[0], i, 'kilometers');
arc.push(segment.geometry.coordinates);
}
// Update the route with calculated arc coordinates
route.features[0].geometry.coordinates = arc;
// Used to increment the value of the point measurement against the route.
var counter = 0;
map.on('load', function () {
// Add a source and layer displaying a point which will be animated in a circle.
map.addSource('route', {
"type": "geojson",
"data": route
});
map.addSource('point', {
"type": "geojson",
"data": point
});
map.addLayer({
"id": "route",
"source": "route",
"type": "line",
"paint": {
"line-width": 1,
"line-color": "#007cbf"
}
});
map.addLayer({
"id": "point",
"source": "point",
"type": "symbol",
"layout": {
"icon-image": "airport-15",
"icon-rotate": ["get", "bearing"],
"icon-rotation-alignment": "map",
"icon-allow-overlap": true,
"icon-ignore-placement": true
}
});
function animate(featureIdx, cntr) {
// Update point geometry to a new position based on counter denoting
// the index to access the arc.
if (cntr >= route.features[featureIdx].geometry.coordinates.length-1){
return;
}
point.features[featureIdx].geometry.coordinates = route.features[featureIdx].geometry.coordinates[cntr];
point.features[featureIdx].properties.bearing = turf.bearing(
turf.point(route.features[featureIdx].geometry.coordinates[cntr >= steps ? cntr - 1 : cntr]),
turf.point(route.features[featureIdx].geometry.coordinates[cntr >= steps ? cntr : cntr + 1])
);
// Update the source with this new data.
map.getSource('point').setData(point);
// Request the next frame of animation so long the end has not been reached.
if (cntr < steps) {
requestAnimationFrame(function(){animate(featureIdx, cntr+1);});
}
}
document.getElementById('replay').addEventListener('click', function() {
// Set the coordinates of the original point back to origin
point.features[0].geometry.coordinates = origin;
// Update the source layer
map.getSource('point').setData(point);
// Reset the counter
cntr = 0;
// Restart the animation.
animate(0,cntr);
animate(1,cntr)
});
// Start the animation.
animate(0, 0);
animate(1, 0);
});
.overlay {
position: absolute;
top: 10px;
left: 30px;
}
.overlay button {
font:600 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
background-color: #3386c0;
color: #fff;
display: inline-block;
margin: 0;
padding: 10px 20px;
border: none;
cursor: pointer;
border-radius: 3px;
}
.overlay button:hover {
background-color:#4ea0da;
}
body { margin:0; padding:0; }
#map { top:0; bottom:0; width:100%;height: 600px }
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Animate a point along a route</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.css' rel='stylesheet' />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.50.0/mapbox-gl.js'></script>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>
<body>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v2.0.0/turf.min.js' charset='utf-8'></script>
<div class="col-md-12">
<div class="card text-white">
<h5 class="card-header bg-info">Featured</h5>
<div class="card-body">
<div class="col-md-12">
<div id='map'></div>
<div class='overlay'>
<button id='replay'>Replay</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

Related

How to change the markers style with their status inside azure map spider cluster?

I am using Azure map Spider Cluster in this i am unable to change the style of markers group which is display on click of cluster bubble. I got the success in case of marker which is outside the cluster bubble with the help of HtmlMarkerLayer class but unable to change the style of markers inside cluster bubble. Below is my code:
<html lang="en">
<head>
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script src="https://raw.githubusercontent.com/Azure-Samples/azure-maps-html-marker-layer/main/dist/azure-maps-html-marker-layer.min.js"></script>
<script src="https://raw.githubusercontent.com/Azure-Samples/azure-maps-spider-clusters/main/dist/azure-maps-spider-clusters.min.js"></script>
<style>
.customInfobox { max-width: 240px; padding: 10px; font-size: 12px; margin-right: 20px; white-space: normal }
.customInfobox .name { font-size: 14px; font-weight: bold; margin-bottom: 5px }
.popup-content-container .popup-close { top: 12px !important; right: 6px !important; color: #ffffff !important; font-size: 16px !important; line-height: 18px !important; height: 15px !important; background: #000000 !important; width: 15px !important; border-radius: 50px !important; display: flex !important; justify-content: center !important; align-items: center !important; }
.atlas-map-canvas { width: 100% !important }
</style>
</head>
<body onload="GetMap()">
<div id="myMap" style="position:relative;width:100%;min-width:290px;height:600px;"></div>
<script>
var map, datasource, popup, spiderManager;
function GetMap() {
//Initialize a map instance.
map = new atlas.Map('myMap', {
center: [-110, 50],
zoom: 2,
view: 'Auto',
//Add authentication details for connecting to Azure Maps.
authOptions: {
//Use Azure Active Directory authentication.
authType: 'subscriptionKey',
subscriptionKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
}
});
var cordinates = [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-84.28295, 30.46454] }, "properties": { "Name": "aa", "Status": "online" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [-84.28295, 30.46454] }, "properties": { "Name": "bb", "Status": "offline" } },
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-54.28295, 60.46454] }, "properties": { "Name": "cc", "Status": "offline" } },
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-58.28295, 66.46454] }, "properties": { "Name": "dd", "Status": "online" } }];
var positions = { "type": "FeatureCollection", "features": cordinates };
map.setCamera({
//center map
bounds: atlas.data.BoundingBox.fromData(positions),
padding: 50
});
map.events.add('ready', function () {
//Create a popup.
popup = new atlas.Popup();
//Hide popup when user clicks or moves the map.
map.events.add('click', hidePopup);
map.events.add('movestart', hidePopup);
//Create a data source to add your data to.
datasource = new atlas.source.DataSource(null, {
//Tell the data source to cluster point data.
cluster: true,
//The radius in pixels to cluster points together.
// clusterRadius: 45,
clusterProperties: { //Calculate counts for each entity type in a cluster
'online': ['+', ['case', ['==', ['get', 'Status'], 'online'], 1, 0]],
'offline': ['+', ['case', ['==', ['get', 'Status'], 'offline'], 1, 0]]
},
//The maximium zoom level in which clustering occurs.
//If you zoom in more than this, all points are rendered as symbols.
clusterMaxZoom: 24,
maxZoom: 24
});
//set data to datasource
datasource.setShapes(positions)
map.sources.add(datasource);
//Create a layer for rendering clustered data in the data source.
var clusterBubbleLayer = new atlas.layer.BubbleLayer(datasource, null, {
//Scale the size of the clustered bubble based on the number of points inthe cluster.
radius: [
'step',
['get', 'point_count'],
20, //Default of 20 pixel radius.
100, 30, //If point_count >= 100, radius is 30 pixels.
750, 40 //If point_count >= 750, radius is 40 pixels.
],
//Change the color of the cluster based on the value on the point_cluster property of the cluster.
color: [
'case', //Use a conditional case expression.
// all offline
['>', ['get', 'offline'], 0] && ['==', ['get', 'online'], 0],
'#a5a5a5',
// all online
['>', ['get', 'online'], 0] && ['==', ['get', 'offline'], 0],
'#6aa84f',
// online and offline both
'#ff9900'
],
strokeWidth: 0,
filter: ['has', 'point_count'] //Only rendered data points which have a point_count property, which clusters do.
});
//Create a layer to render the individual locations.
var shapeLayer = new atlas.layer.SymbolLayer(datasource, null, {
filter: ['!', ['has', 'point_count']] //Filter out clustered points from this layer.
});
//Add the clusterBubbleLayer and two additional layers to the map.
map.layers.add([
clusterBubbleLayer,
//Create a symbol layer to render the count of locations in a cluster.
new atlas.layer.SymbolLayer(datasource, null, {
iconOptions: {
image: 'none', //Hide the icon image.
},
textOptions: {
textField: '{point_count_abbreviated}',
offset: [0, 0.4]
},
filter: ['!', ['has', 'point_count']]
}),
shapeLayer
]);
markerLayer = new atlas.layer.HtmlMarkerLayer(datasource, null, {
markerCallback: function (id, position, properties) {
//Check to see if marker represents a cluster.
if (properties.cluster) {
return new atlas.PieChartMarker({
position: position,
colors: '#ffffff',
fillColor: 'white',
strokeColor: 'white',
text: properties.point_count_abbreviated
});
} else {
//for single marker
return new atlas.HtmlMarker({
position: position,
color: properties.Status == 'online' ? '#4cae4c' : '#808080',
});
}
}
});
// map.events.add('click', markerLayer, markerClicked);
map.layers.add(markerLayer);
//Create an instance of the spider manager.
spiderManager = new atlas.SpiderClusterManager(map, clusterBubbleLayer, shapeLayer);
//Add event handler for when a feature is selected.
map.events.add('featureSelected', spiderManager, function (e) {
if (e.cluster) {
showPopup(e.cluster.geometry.coordinates, e.shape.getProperties(), [0, 0]);
} else {
showPopup(e.shape.getCoordinates(), e.shape.getProperties(), [0, -20]);
}
});
//Add event handler for when a feature is unselected.
map.events.add('featureUnselected', spiderManager, function () {
hidePopup();
});
});
}
var popupTemplate = '<div class="customInfobox"><div class="name">{name} ({status})</div></div>';
showPopup = function (position, properties, pixelOffset) {
var content = popupTemplate.replace(/{name}/g, properties.Name).replace(/{status}/g, properties.Status);
popup.setOptions({
//Update the content of the popup.
content: content,
//Update the position of the popup with the symbols coordinate.
position: position,
//Offset the popups position for better alignment with the layer.
pixelOffset: pixelOffset
});
//Open the popup.
popup.open(map);
}
hidePopup = function () {
popup.close();
}
</script>
</body>
</html>
For more explanation, please check below image:
Please help me to fix this.
Thanks in advance.
I wouldn't recommend using the HtmlMarker layer unless you need to use HTML DOM elements or CSS to style your marker, SymbolLayer is much faster.
If you customize how the shapeLayer (Symbol layer) in your app renders the points, you will find that the spider manager automatically aligns with the same style when showing the expanded points.
I'm guessing you are using HtmlMarker layer as you wanted to specify custom colors for your markers, and want pie charts for the clusters. For symbol layers you use icons, but there is a built-in tool for generating these icons from built in templates (samples).
Here is a modified version of your code that hides the HtmlMarker for individual points, generates the green and grey marker icons, and uses the symbol layer to customize how your points appear on the map.
<html lang="en">
<head>
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css" rel="stylesheet" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script src="https://raw.githubusercontent.com/Azure-Samples/azure-maps-html-marker-layer/main/dist/azure-maps-html-marker-layer.min.js"></script>
<script src="https://raw.githubusercontent.com/Azure-Samples/azure-maps-spider-clusters/main/dist/azure-maps-spider-clusters.min.js"></script>
<style>
.customInfobox { max-width: 240px; padding: 10px; font-size: 12px; margin-right: 20px; white-space: normal }
.customInfobox .name { font-size: 14px; font-weight: bold; margin-bottom: 5px }
.popup-content-container .popup-close { top: 12px !important; right: 6px !important; color: #ffffff !important; font-size: 16px !important; line-height: 18px !important; height: 15px !important; background: #000000 !important; width: 15px !important; border-radius: 50px !important; display: flex !important; justify-content: center !important; align-items: center !important; }
.atlas-map-canvas { width: 100% !important }
</style>
</head>
<body onload="GetMap()">
<div id="myMap" style="position:relative;width:100%;min-width:290px;height:600px;"></div>
<script>
var map, datasource, popup, spiderManager;
function GetMap() {
//Initialize a map instance.
map = new atlas.Map('myMap', {
center: [-110, 50],
zoom: 2,
view: 'Auto',
//Add authentication details for connecting to Azure Maps.
authOptions: {
//Use Azure Active Directory authentication.
authType: 'subscriptionKey',
subscriptionKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
}
});
var cordinates = [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-84.28295, 30.46454] }, "properties": { "Name": "aa", "Status": "online" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [-84.28295, 30.46454] }, "properties": { "Name": "bb", "Status": "offline" } },
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-54.28295, 60.46454] }, "properties": { "Name": "cc", "Status": "offline" } },
{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-58.28295, 66.46454] }, "properties": { "Name": "dd", "Status": "online" } }];
var positions = { "type": "FeatureCollection", "features": cordinates };
map.setCamera({
//center map
bounds: atlas.data.BoundingBox.fromData(positions),
padding: 50
});
map.events.add('ready', function () {
//Load customized icons for use with the symbol layer.
var iconPromises = [
map.imageSprite.createFromTemplate('onlineIcon', 'marker', '#4cae4c', '#fff'),
map.imageSprite.createFromTemplate('offlineIcon', 'marker', '#808080', '#fff')
];
//Wait for icons to load into the map sprite.
Promise.all(iconPromises).then(() => {
//Create a data source to add your data to.
datasource = new atlas.source.DataSource(null, {
//Tell the data source to cluster point data.
cluster: true,
//The radius in pixels to cluster points together.
// clusterRadius: 45,
clusterProperties: { //Calculate counts for each entity type in a cluster
'online': ['+', ['case', ['==', ['get', 'Status'], 'online'], 1, 0]],
'offline': ['+', ['case', ['==', ['get', 'Status'], 'offline'], 1, 0]]
},
//The maximium zoom level in which clustering occurs.
//If you zoom in more than this, all points are rendered as symbols.
clusterMaxZoom: 24,
maxZoom: 24
});
//set data to datasource
datasource.setShapes(positions)
map.sources.add(datasource);
//Create a layer for rendering clustered data in the data source.
var clusterBubbleLayer = new atlas.layer.BubbleLayer(datasource, null, {
//Scale the size of the clustered bubble based on the number of points inthe cluster.
radius: [
'step',
['get', 'point_count'],
20, //Default of 20 pixel radius.
100, 30, //If point_count >= 100, radius is 30 pixels.
750, 40 //If point_count >= 750, radius is 40 pixels.
],
//Change the color of the cluster based on the value on the point_cluster property of the cluster.
color: [
'case', //Use a conditional case expression.
// all offline
['>', ['get', 'offline'], 0] && ['==', ['get', 'online'], 0],
'#a5a5a5',
// all online
['>', ['get', 'online'], 0] && ['==', ['get', 'offline'], 0],
'#6aa84f',
// online and offline both
'#ff9900'
],
strokeWidth: 0,
filter: ['has', 'point_count'] //Only rendered data points which have a point_count property, which clusters do.
});
//Create a layer to render the individual locations.
var shapeLayer = new atlas.layer.SymbolLayer(datasource, null, {
//Define style for individual points.
iconOptions: {
//Use a case expression to select the image icon based on the Status property of the data point.
image: [
'case',
//Check if status is online
['==', ['get', 'Status'], 'online'],
'onlineIcon',
//Offline/default icon.
'offlineIcon'
]
},
filter: ['!', ['has', 'point_count']] //Filter out clustered points from this layer.
});
//Add the clusterBubbleLayer and two additional layers to the map.
map.layers.add([
clusterBubbleLayer,
//Create a symbol layer to render the count of locations in a cluster.
new atlas.layer.SymbolLayer(datasource, null, {
iconOptions: {
image: 'none', //Hide the icon image.
},
textOptions: {
textField: '{point_count_abbreviated}',
offset: [0, 0.4]
},
filter: ['!', ['has', 'point_count']]
}),
shapeLayer
]);
markerLayer = new atlas.layer.HtmlMarkerLayer(datasource, null, {
markerCallback: function (id, position, properties) {
//Check to see if marker represents a cluster.
if (properties.cluster) {
return new atlas.PieChartMarker({
position: position,
colors: '#ffffff',
fillColor: 'white',
strokeColor: 'white',
text: properties.point_count_abbreviated
});
} else {
//for single marker
return new atlas.HtmlMarker({
visible: false
});
}
}
});
// map.events.add('click', markerLayer, markerClicked);
map.layers.add(markerLayer);
//Create an instance of the spider manager.
spiderManager = new atlas.SpiderClusterManager(map, clusterBubbleLayer, shapeLayer);
//Add event handler for when a feature is selected.
map.events.add('featureSelected', spiderManager, function (e) {
if (e.cluster) {
showPopup(e.cluster.geometry.coordinates, e.shape.getProperties(), [0, 0]);
} else {
showPopup(e.shape.getCoordinates(), e.shape.getProperties(), [0, -20]);
}
});
//Add event handler for when a feature is unselected.
map.events.add('featureUnselected', spiderManager, function () {
hidePopup();
});
});
});
}
var popupTemplate = '<div class="customInfobox"><div class="name">{name} ({status})</div></div>';
showPopup = function (position, properties, pixelOffset) {
var content = popupTemplate.replace(/{name}/g, properties.Name).replace(/{status}/g, properties.Status);
popup.setOptions({
//Update the content of the popup.
content: content,
//Update the position of the popup with the symbols coordinate.
position: position,
//Offset the popups position for better alignment with the layer.
pixelOffset: pixelOffset
});
//Open the popup.
popup.open(map);
}
hidePopup = function () {
popup.close();
}
</script>
</body>
</html>
I've also added an example to the GitHub repo for the spider cluster manager.

Multiple Leaflet maps

I have this webpage that I am developing which involves multiple Leaflet maps on the webpage using jQuery from top to bottom. See this lo-fi wireframe for a closer look . I have tried to add multiple <div>s in index.html and multiple map variables in main.js (and yes, styled in CSS), as well as
creating a function like kboul's answer here on StackOverflow but no matter what I do, it ends up just being one map that does not load the base map. For now, I have included the code that works with only one map See this image of what the code looks like with all the layers on and working. Also please note the coordinates have been redacted because there were so many.
Here is my code:
/*Stylesheet by Will P. Campbell,2021*/
//map to contain '31500' polygon
var map = L.map('mapid').setView([45.5, -89.5], 7);
//map to contain '27500' polygon
var map2 = L.map('mapid2').setView([45.5, -89.5], 7);
//map to contain '24000' polygon
var map3 = L.map('mapid3').setView([45.5, -89.5], 7);
//map to contain '20500' polygon
var map4 = L.map('mapid4').setView([45.5, -89.5], 7);
//map to contain '17000' polygon
var map5 = L.map('mapid5').setView([45.5, -89.5], 7);
//map to contain '14600' polygon
var map6 = L.map('mapid6').setView([45.5, -89.5], 7);
//map to contain '11000' polygon
var map7 = L.map('mapid7').setView([45.5, -89.5], 7);
var baseMap = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.{ext}', {
attribution: 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap contributors',
subdomains: 'abcd',
minZoom: 0,
maxZoom: 18,
ext: 'png'
}).addTo(map);
/*Glacier 11000*/
var Toe_11000 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
//redacted
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 1,
"Years_Ago": 11000,
"SHAPE_Leng": 387749.141631,
"Shape_Le_1": 5.06435076694,
"Shape_Area": 0.429078160361,
"filename": "11000.jpg"
}
}]
};
var g11000 = L.geoJSON(Toe_11000, {
style: {
color: "#e41a1c"
}
});
g11000.on({
click: function() {
$("#panel").html(Toe_11000.features[0].properties.Years_Ago + " Years Ago" + info11000 + glacierInfo + selfPlug);
}
});
/*Glacier 14600*/
var Toe_14600 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-90.65116417499996, 47.70293454200004],
[-90.72482365299999, 47.673924999000064],
[-90.79822703099995, 47.63344243800003],
[-90.87151684099996, 47.592913355000064],
[-90.93607653299995, 47.54240954900007],
[-90.98389479799994, 47.50486972300007],
[-91.01266156999998, 47.46605101600005],
[-91.03524057399994, 47.43585163000006],
[-91.09569047499997, 47.40672034700003],
[-91.16068607799997, 47.39608128700007],
[-91.20242634199997, 47.38136616700007],
[-91.24370674999994, 47.34807033200008],
[-91.24727017899994, 47.32089010200008],
[-91.27829107399998, 47.30054916700004],
[-91.35252049299999, 47.24684182500005],
[-91.42454322999998, 47.19454164700005],
[-91.49851758599999, 47.142169952000074],
[-91.58297018999997, 47.09531966900005],
[-91.69593298799998, 47.02941600500003],
[-91.78970295499994, 46.95941544900006],
[-91.82835428899995, 46.930232197000066],
[-91.91162510599997, 46.86744039100006],
[-91.99554737199998, 46.82743409100004],
[-92.06911560299994, 46.79183942000003],
[-92.12271105199994, 46.779428163000034],
[-92.18228311199994, 46.76116312500005],
[-92.25397574199997, 46.73548525600006],
[-92.32346255299996, 46.70837829200008],
[-92.37452539699996, 46.68875637000008],
[-92.41380912499994, 46.68507654200005],
[-92.47155654999995, 46.67669948400004],
[-92.49779041299996, 46.66041357700004],
[-92.53630909799995, 46.640992280000034],
[-92.60352557599998, 46.61519304900003],
[-92.65025475699997, 46.595545755000046],
[-92.66997578199994, 46.57508444400003],
[-92.69410222099998, 46.56023089900003],
[-92.73425967299994, 46.53498854400004],
[-92.79268852199999, 46.503571829000066],
[-92.84256524699998, 46.468051606000074],
[-92.88183268599994, 46.42849094400003],
[-92.92753540999996, 46.394466917000045],
[-92.94989701799994, 46.34959887800005],
[-92.95186608799997, 46.30954130100008],
[-92.92975250899997, 46.28153421700006],
[-92.85925850399997, 46.27331860700008],
[-92.79127616799997, 46.27357100900008],
[-92.71321257399995, 46.27830917600005],
[-92.63952461199995, 46.28860811000004],
[-92.57829646799996, 46.301436514000045],
[-92.50925582199994, 46.32440533500005],
[-92.44221727099995, 46.347289440000054],
[-92.41261793199999, 46.37792243000007],
[-92.37035638299994, 46.40309578500006],
[-92.32010085699994, 46.43555965100006],
[-92.22421472899998, 46.46604055800003],
[-92.16676037899998, 46.47714513900007],
[-92.07164040799995, 46.47747958900004],
[-91.96355058399996, 46.462242262000075],
[-91.88129117799997, 46.47505522800003],
[-91.84860834599993, 46.487018110000065],
[-91.75759648199994, 46.48702458100007],
[-91.67480884399998, 46.485409692000076],
[-91.61092690599997, 46.49347106100004],
[-91.53298945499995, 46.517401738000046],
[-91.46184380399995, 46.56548027200006],
[-91.39439978099995, 46.60108704600003],
[-91.31293960199997, 46.66110276500007],
[-91.18166198599994, 46.731109263000064],
[-91.12163612599994, 46.77552488500004],
[-91.02482937399998, 46.78786178000007],
[-90.98063779999995, 46.797773128000074],
[-90.96927097899999, 46.782631328000036],
[-90.95760682899999, 46.75034730400006],
[-91.00666688699994, 46.706114670000034],
[-91.04472870499995, 46.66958103600007],
[-91.09664029099997, 46.636712301000045],
[-91.13687825499994, 46.57726777900007],
[-91.18839689999999, 46.532931133000034],
[-91.22591702999995, 46.48300696300004],
[-91.22480609399997, 46.433490293000034],
[-91.18738430599996, 46.359591409000075],
[-91.12616009499999, 46.325921202000075],
[-90.99618142799994, 46.285217860000046],
[-90.89141040599998, 46.26322281700004],
[-90.77320977799997, 46.256463342000075],
[-90.59165834999999, 46.22897204100008],
[-90.47359851299996, 46.22571206300006],
[-90.21011180299996, 46.22840493600006],
[-90.07834092799999, 46.21714115300006],
[-89.99052527699996, 46.20002253800004],
[-89.63663278999996, 46.19754044900003],
[-89.30472963899996, 46.19409865700004],
[-89.14564109599996, 46.193020372000035],
[-89.10690236799996, 46.21367948200003],
[-88.97509624199995, 46.21828879600008],
[-88.74396655199996, 46.24455812300005],
[-88.43920812199997, 46.263282384000036],
[-88.18463496799995, 46.27857294900008],
[-88.00977466999996, 46.175646776000065],
[-87.99389010599998, 46.04677587200007],
[-88.03142757799998, 45.90454467200004],
[-88.07824403599994, 45.733876871000064],
[-88.11693049199994, 45.64521481500003],
[-88.15630836499997, 45.53154329200004],
[-88.25459067099996, 45.31159869500004],
[-88.32963412999999, 45.169820886000025],
[-88.40834291299996, 45.06376788400007],
[-88.48581727299995, 44.99336901300006],
[-88.79481685399998, 44.90415892300007],
[-88.88639060299994, 44.84792515000004],
[-88.88261184299995, 44.78357859500005],
[-88.94319230899998, 44.76271860500003],
[-88.97231671099996, 44.62840776200005],
[-89.00318747399996, 44.57866096200007],
[-89.02004076199995, 44.46804576400007],
[-89.04649611099995, 44.37537170000007],
[-89.10740785599995, 44.30082986600007],
[-89.08883401599996, 44.21492877800006],
[-89.02088686299999, 44.117891385000064],
[-88.83475711099999, 43.998228366000035],
[-88.68786675299998, 43.92517043600003],
[-88.62533997199995, 43.84939582800007],
[-88.57299960499995, 43.76656712400006],
[-88.46045322499998, 43.73294585800005],
[-88.39507582999994, 43.78207346700003],
[-88.33422715399996, 43.841949181000075],
[-88.26389529699998, 43.883781630000044],
[-88.26171217099994, 43.95878690500007],
[-88.25436012199998, 44.04085874400005],
[-88.13665456199999, 44.003267237000045],
[-88.04759712699996, 44.00177966800004],
[-87.97724235799996, 44.03271403600007],
[-87.91264601899996, 44.03869804900006],
[-87.85100620199995, 43.96251794800003],
[-87.84031258699997, 43.84797273600003],
[-87.77934997599993, 43.76104507100007],
[-87.69970123099995, 43.65226923900008],
[-87.59451333699997, 43.57506238600007],
[-87.41895871099996, 43.54264457600004],
[-87.19847646199997, 43.53030423300004],
[-87.05535483399996, 43.54457143500008],
[-86.90199607799997, 43.56552812900003],
[-86.73246550099998, 43.61082922300005],
[-86.59688342599998, 43.66046715300007],
[-86.47311237099996, 43.75675903800004],
[-86.41494068499998, 43.905016706000026],
[-86.38487126299998, 43.99339418100004],
[-86.33611529199999, 44.14190469500005],
[-86.23094835399996, 44.23494796600005],
[-86.07578505799995, 44.32618325100003],
[-85.99546925899995, 44.409139733000075],
[-85.93780993299998, 44.44997420000004],
[-85.94529025199995, 44.48596854700003],
[-85.88575853799995, 44.551719080000055],
[-85.82903334099996, 44.64612264200008],
[-85.67299230199995, 44.65817042300006],
[-85.49721378799995, 44.66565292100006],
[-85.37988257999996, 44.69311130300008],
[-85.26070073999995, 44.74180747400004],
[-85.20102381099997, 44.79647274300004],
[-85.12731019099994, 44.896951657000045],
[-85.07522771199996, 44.976883351000026],
[-84.82164997499996, 47.579520486000035],
[-90.67336377599997, 47.71242423500007],
[-90.65116417499996, 47.70293454200004]
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 1,
"Years_Ago": 14600,
"SHAPE_Leng": 2202706.20984,
"Shape_Le_1": 25.0028099606,
"Shape_Area": 17.1995913109,
"filename": "14600.jpg"
}
}]
}
var g14600 = L.geoJSON(Toe_14600, {
style: {
color: "blue"
}
});
g14600.on({
click: function() {
$("#panel").html(Toe_14600.features[0].properties.Years_Ago + " Years Ago" + info14600 + glacierInfo + selfPlug);
}
});
/*Glacier 17000*/
var Toe_17000 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
//redacted
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 2,
"Years_Ago": 17000,
"SHAPE_Leng": 2261336.18634,
"Shape_Le_1": 24.4337768448,
"Shape_Area": 21.6098467975,
"filename": "17000.jpg"
}
}]
}
var g17000 = L.geoJSON(Toe_17000, {
style: {
color: "#4daf4a"
}
});
g17000.on({
click: function() {
$("#panel").html(Toe_17000.features[0].properties.Years_Ago + " Years Ago" + info17000 + glacierInfo + selfPlug);
}
});
/*Glacier 20500*/
var Toe_20500 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
//redacted
]
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 1,
"Years_Ago": 20500,
"SHAPE_Leng": 3087165.91023,
"Shape_Le_1": 33.5221258781,
"Shape_Area": 32.9568211425,
"filename": "20500.jpg"
}
}]
}
var g20500 = L.geoJSON(Toe_20500, {
style: {
color: "#ffff33"
}
});
g20500.on({
click: function() {
$("#panel").html(Toe_20500.features[0].properties.Years_Ago + " Years Ago" + info20500 + glacierInfo + selfPlug);
}
});
/*Glacier 24000*/
var Toe_24000 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
//redacted
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 1,
"Years_Ago": 24000,
"SHAPE_Leng": 3034250.36063,
"Shape_Le_1": 33.0014683974,
"Shape_Area": 35.7394984299,
"filename": "24000.jpg"
}
}]
}
var g24000 = L.geoJSON(Toe_24000, {
style: {
color: "#984ea3"
}
}
);
g24000.on({
click: function() {
$("#panel").html(Toe_24000.features[0].properties.Years_Ago + " Years Ago" + info24000 + glacierInfo + selfPlug);
}
});
/*Glacier 27500*/
var Toe_27500 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
//redacted
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 1,
"Years_Ago": 27500,
"SHAPE_Leng": 2984589.95454,
"Shape_Le_1": 32.3931138132,
"Shape_Area": 34.4347324387,
"filename": "27500.jpg"
}
}]
}
var g27500 = L.geoJSON(Toe_27500, {
style: {
color: "#ff7f00"
}
}
);
g27500.on({
click: function() {
$("#panel").html(Toe_27500.features[0].properties.Years_Ago + " Years Ago" + info27500 + glacierInfo + selfPlug);
}
});
/*Glacier 31500*/
var Toe_31500 = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
//redacted
]
]
},
"properties": {
"OBJECTID_1": 1,
"OBJECTID": 2,
"Years_Ago": 31500,
"SHAPE_Leng": 1478866.18087,
"Shape_Le_1": 15.9994195189,
"Shape_Area": 9.83976333148,
"filename": "31500.jpg"
}
}]
}
var g31500 = L.geoJSON(Toe_31500, {
style: {
color: "#a65628"
}
});
g31500.on({
click: function() {
$("#panel").html(Toe_31500.features[0].properties.Years_Ago + " Years Ago" + info31500 + glacierInfo + selfPlug)
}
});
var overlayMaps = {
"31500 years ago": g31500,
"27500 years ago": g27500,
"24000 years ago": g24000,
"20500 years ago": g20500,
"17000 years ago": g17000,
"14600 years ago": g14600,
"11000 years ago": g11000
};
var glacierLayers = L.control.layers(null, overlayMaps).addTo(map);
/*Stylesheet by Will P. Campbell,2021*/
body {
background-color: #ECECEC;
}
#mapid,
#mapid2,
#mapid3,
#mapid4,
#mapid5,
#mapid6,
#mapid7 {
position: fixed;
height: 650px;
width: 60%;
border: 5px solid black;
display: inline-block;
}
h1 {
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
}
#panel {
position: fixed;
right: 0;
border: 5px outset black;
background-color: lightblue;
text-align: center;
width: 25%;
height: auto;
padding: 20px;
display: inline-block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>WISCONSIN GLACIER TIME LAPSE</title>
<!--put your external stylesheet links here-->
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="lib/leaflet/leaflet.css">
<!--[if IE<9]>
<link rel="stylesheet" href="css/style.ie.css">
<![endif]-->
</head>
<body>
<h1>WISCONSIN GLACIER TIME LAPSE</h1>
<!-- map 1 -->
<div id="mapid"></div>
<!-- map 2 -->
<div id="mapid2"></div>
<!-- map 3 -->
<div id="mapid3"></div>
<!-- map 4 -->
<div id="mapid4"></div>
<!-- map 5 -->
<div id="mapid5"></div>
<!-- map 6 -->
<div id="mapid6"></div>
<!-- map 7 -->
<div id="mapid7"></div>
<div id="panel"><b>Glacier Information Panel</b><br>
<p>Use the checkbox and click on each glacier to learn more about them!</p>
</div>
<!--put your initial page content here-->
<!--you can also use this space for internal scripts or stylesheets;
place these within <script> or <style> tags-->
<!--put your external script links here-->
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="js/main.js"></script>
<script type="text/javascript" src="js/geojson.js"></script>
</body>
</html>
Please let me know if you need any more clarification. I'm new to StackOverflow as well so I apologize if this is an improper or repeat question.
Thanks!
Create an Object mapsData with properties that match your DIV Element data-map value.
Loop your Elements DIVs ELS_map.forEach(initMap); and apply the data you stored beforehand for each map ID inside the mapsData
const L_tiles = 'https://stamen-tiles-{s}.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.{ext}';
const L_options = {
attribution: 'Tiles: SD, CC BY 3.0 © OSM contrib.',
minZoom: 0,
maxZoom: 18,
ext: 'png'
};
// ALL YOUR DATA GOES HERE!
// Name your properties the same as data-map="" value in HTML
const mapsData = {
glacier_1: {
center: [45.5, -89.5],
zoom: 7,
description: "Glacier one Lorem...",
// add title, shapes etc here
},
glacier_2: {
center: [45.5, -89.5],
zoom: 7,
description: "Glacier 2 Ipsum...",
// add title, shapes etc here
},
};
const initMap = (EL) => {
const id = EL.dataset.map; // rerturns i.e: "glacier_1"
const data = mapsData[id];
const map = L.map(EL).setView(data.center, data.zoom);
L.tileLayer(L_tiles, L_options).addTo(map);
};
const ELS_map = document.querySelectorAll("[data-map]");
ELS_map.forEach(initMap);
[data-map] {
height: 300px;
border: 5px solid black;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" />
<div data-map="glacier_1"></div>
<div data-map="glacier_2"></div>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>

How to visualize the geocode of an adress ? and in ideal situation knowing if this is inside my polygon?

I am doing a script for test if an adress is in an area, for exemple around a point. I use node.js for the server and then JavaScript with the API mapbox. I display the map with the polygon (the area), the central point and the search with autocomplete for adress.
But now I am wondering, how to have the geocode (lattitude and longitude) from the adress ?
I would like to take this coordinate for calculate if those coordinate are inside my polygon for example with one of those methods :
http://geomalgorithms.com/a03-_inclusion.html#wn_PinPolygon()
here my code :
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title>Adress in/out area</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.3.1/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.3.1/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.4.1/mapbox-gl-geocoder.min.js'></script>
<link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v4.4.1/mapbox-gl-geocoder.css' type='text/css' />
<div id='map'> </div>
<script>
mapboxgl.accessToken = 'mytoken';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-73.943851,40.720021],
zoom: 13
});
var geocoder =new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl
});
map.addControl(geocoder);
geocoder.on('result', function(result) {
console.log(result);
});
map.on('load', function () {
map.addSource("checked-area", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-73.9346845,40.7284786],
[-73.9382465,40.7281208 ],
[-73.9457138,40.7274053],
[-73.9517648,40.725454],
[-73.9560993,40.721486],
[-73.9564855,40.710394],
[-73.9406068,40.7118904],
[-73.9330966,40.713582],
[-73.9347274,40.7172251],
[-73.933955,40.7202501],
[-73.9351995,40.722722],
[-73.9282472,40.7243482],
[-73.9298351,40.727633],
[-73.9346845,40.7284786]
]
]
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-73.943851,40.720021]
}
}]
}
});
map.addLayer({
"id": "area-boundary",
"type": "fill",
"source": "checked-area",
"paint": {
"fill-color": "#088",
"fill-opacity": 0.5
},
"filter": ["==", "$type", "Polygon"]
});
map.addLayer({
"id": "area-store",
"type": "circle",
"source": "checked-area",
"paint": {
"circle-radius": 6,
"circle-color": "#B42222"
},
"filter": ["==", "$type", "Point"],
});
});
</script>
</body>
</html>
this is more specially this part of code which deals with the search part for adress :
var geocoder =new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
mapboxgl: mapboxgl
});
map.addControl(geocoder);
geocoder.on('result', function(result) {
console.log(result);
});
I would like from this code to take the coordinate to be able to calculate if they are inside the defined area (and in the future even without showing the map only with a message).
I tried with JSON.parse(result) and I have :
Uncaught SyntaxError: Unexpected token o in JSON
I also tried with result.geometry.coordinates and result['geometry']['coordinates']
If you have an idea you will help me a lot :)
PS: in case of minus please let me know why so that I could improve my post :)
Uncaught SyntaxError: Unexpected token o in JSON
This is mostly because you're trying to parse an object instead of JSON string. Have you tried accessing result.result.geometry instead. That gives the geometry.
geocoder.on("result", result => {
console.log(result.result.geometry);
});
You can also check if a point geometry lies within a polygon using turf.inside [1]
Here's a codepen: https://codepen.io/manishraj/full/bGbxOVG. Try searching for Pune, India and Delhi, India.
[1] https://github.com/Turfjs/turf-inside

Mapbox How to show marker on current location?

I want to build a page which shows users current location.
Feature I want to build is that user can select any place on the map and script will calculate the distance between his location and clicked location.
What have been achieved: the web site shows location and I user can click to put second marker.
Problem: the first marker should be appearing on users current location.
Code which already have:
JSfiddle
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Distance between two markers</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox.js/v2.4.0/mapbox.js'></script>
<link href='https://api.mapbox.com/mapbox.js/v2.4.0/mapbox.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
pre.ui-distance {
position:absolute;
bottom:10px;
left:10px;
padding:5px 10px;
background:rgba(0,0,0,0.5);
color:#fff;
font-size:11px;
line-height:18px;
border-radius:3px;
}
.ui-button {
background:#3887BE;
color:#FFF;
display:block;
position:absolute;
top:50%;left:50%;
width:160px;
margin:-20px 0 0 -80px;
z-index:100;
text-align:center;
padding:10px;
border:1px solid rgba(0,0,0,0.4);
border-radius:3px;
}
.ui-button:hover {
background:#3074a4;
color:#fff;
}
</style>
<div id='map'></div>
<div class='ui-button'>
<a href='#' id='geolocate' >Find me</a>
<pre id='distance' class='ui-distance'>Click to place a marker</pre>
<script>
L.mapbox.accessToken = 'pk.eyJ1IjoiYWJ6YWwiLCJhIjoiY2llempiaW9oMWJvdXNnbTAxZnY4NTNvOSJ9.I0bW1wxrOYS2MPZD0FrTtA';
var map = L.mapbox.map('map', 'mapbox.streets')
.setView([38.9, -77], 12);
// Start with a fixed marker.
var fixedMarker = L.marker(new L.LatLng(38.9131775, -77.032544), {
icon: L.mapbox.marker.icon({
'marker-color': 'ff8888'
})
}).bindPopup('Mapbox DC').addTo(map);
// Store the fixedMarker coordinates in a variable.
var fc = fixedMarker.getLatLng();
// Create a featureLayer that will hold a marker and linestring.
var featureLayer = L.mapbox.featureLayer().addTo(map);
// When a user clicks on the map we want to
// create a new L.featureGroup that will contain a
// marker placed where the user selected the map and
// a linestring that draws itself between the fixedMarkers
// coordinates and the newly placed marker.
map.on('click', function(ev) {
// ev.latlng gives us the coordinates of
// the spot clicked on the map.
var c = ev.latlng;
var geojson = [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [c.lng, c.lat]
},
"properties": {
"marker-color": "#ff8888"
}
}, {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[fc.lng, fc.lat],
[c.lng, c.lat]
]
},
"properties": {
"stroke": "#000",
"stroke-opacity": 0.5,
"stroke-width": 4
}
}
];
featureLayer.setGeoJSON(geojson);
// Finally, print the distance between these two points
// on the screen using distanceTo().
var container = document.getElementById('distance');
container.innerHTML = (fc.distanceTo(c)).toFixed(0) + 'm';
});
var geolocate = document.getElementById('geolocate');
if (!navigator.geolocation) {
geolocate.innerHTML = 'Geolocation is not available';
} else {
geolocate.onclick = function (e) {
e.preventDefault();
e.stopPropagation();
map.locate();
};
}
// Once we've got a position, zoom and center the map
// on it, and add a single marker.
map.on('locationfound', function(e) {
map.fitBounds(e.bounds);
myLayer.setGeoJSON({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [e.latlng.lng, e.latlng.lat]
},
properties: {
'title': 'Here I am!',
'marker-color': '#ff8888',
'marker-symbol': 'star'
}
});
// And hide the geolocation button
geolocate.parentNode.removeChild(geolocate);
});
// If the user chooses not to allow their location
// to be shared, display an error message.
map.on('locationerror', function() {
geolocate.innerHTML = 'Position could not be found';
});
</script>
</body>
</html>
Sorry, it's a little messy and not exactly what I believe you want, but could be altered to work as you want (I created a second featureLayer so that the original marker that denotes the found user location stays on the map - This way one has to click twice to measure two distances but at least the user gets to choose the starting point whereas the "found" starting point might not be the user's exact location.) I got rid of the fixedMarker that it starts with because we don't need it.
The JSFiddle
var map = L.mapbox.map('map', 'mapbox.streets')
.setView([38.9, -77], 12);
// Create a featureLayer that will hold a marker and linestring.
var featureLayer = L.mapbox.featureLayer().addTo(map);
var secondFeatureLayer = L.mapbox.featureLayer().addTo(map);
// 1. Let's create a counter so that we can record the separate clicks
var counter = 0;
// 2. Let's use some variables outside the function scope
var c,
c2,
prevClick;
map.on('click', function(ev) {
// 3. Check if we've yet to click once
if (counter < 1) {
// 4. assign current click coordinates to prevClick for later use
prevClick = ev.latlng;
// ev.latlng gives us the coordinates of
// the spot clicked on the map.
c = ev.latlng;
counter++;
} else {
c = prevClick;
counter = 0;
}
c2 = ev.latlng;
var geojson = [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [c.lng, c.lat]
},
"properties": {
"marker-color": "#ff8888"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [c2.lng, c2.lat]
},
"properties": {
"marker-color": "#ff8888"
}
},{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[c.lng, c.lat],
[c2.lng, c2.lat]
]
},
"properties": {
"stroke": "#000",
"stroke-opacity": 0.5,
"stroke-width": 4
}
}
];
secondFeatureLayer.setGeoJSON(geojson);
// Finally, print the distance between these two points
// on the screen using distanceTo().
var container = document.getElementById('distance');
container.innerHTML = (c2.distanceTo(c)).toFixed(0) + 'm';
});
var geolocate = document.getElementById('geolocate');
if (!navigator.geolocation) {
geolocate.innerHTML = 'Geolocation is not available';
} else {
geolocate.onclick = function (e) {
e.preventDefault();
e.stopPropagation();
map.locate();
};
}
// Once we've got a position, zoom and center the map
// on it, and add a single marker.
map.on('locationfound', function(e) {
map.fitBounds(e.bounds);
featureLayer.setGeoJSON({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [e.latlng.lng, e.latlng.lat]
},
properties: {
'title': 'Here I am!',
'marker-color': '#ff8888',
'marker-symbol': 'star'
}
});
// And hide the geolocation button
geolocate.parentNode.removeChild(geolocate);
});
// If the user chooses not to allow their location
// to be shared, display an error message.
map.on('locationerror', function() {
geolocate.innerHTML = 'Position could not be found';
});

Loading geojson markers into mapbox setting custom icon image

I'm new to mapbox/leaflet and I think it's a pretty basic problem I'm fighting the last two days and though I've tried several ways I can't wrap my head around it.
I'm loading markers via geojson:
var ma_3 = L.mapbox.featureLayer().loadURL('./data/marathon/marker3x.geojson');
and then try to change properties like size or color according to the title used in the geojson data:
ma_3.on('ready', function(layer) {
this.eachLayer(function(marker) {
if (marker.toGeoJSON().properties.title === 'Verpflegung') {
marker.setIcon(L.mapbox.marker.icon({
"marker-size": 'large'
}));
} else {
marker.setIcon(L.mapbox.marker.icon({}));
}
marker.bindPopup(marker.toGeoJSON().properties.id + ', ' +
marker.toGeoJSON().properties.title);
});
})
.addTo(baseMap);
The geojson looks like this:
{
"type": "Feature",
"properties": {
"id": "marker-ie2tbbh05",
"title": "Verpflegung",
"description": "",
"marker-size": "medium",
"marker-color": "#b7ddf3",
"marker-symbol": "marker-stroked"
},
"geometry": {
"type": "Point",
"coordinates": [
6.431395,
51.19433
]
},
Am I missing something because I've also tried giving the marker a new face by using
var icon_live = L.icon({ iconUrl: './img/icon-live.png', iconSize: [35,35] });
somewhere in the setIcon function but nothing seems to work.
If someone could please point me in right direction. It's really appriciated.
I guess it's a typical beginners mistake and maybe it's just me but I found it pretty confusing in which context to use the several options of setIcon.
In the end I made it work using .on(layeradd) and marker.setIcon(pathToYourIcon).
ma_3.on('layeradd', function(layer) {
this.eachLayer(function(marker) {
if (marker.toGeoJSON().properties.title === 'Verpflegung') {
marker.setIcon(icon_live);
}
marker.bindPopup(marker.toGeoJSON().properties.id + ', ' +
marker.toGeoJSON().properties.title);
});
});
Have you seen this example yet?
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Custom marker icons</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.mapbox.com/mapbox.js/v2.2.2/mapbox.js'></script>
<link href='https://api.mapbox.com/mapbox.js/v2.2.2/mapbox.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>
L.mapbox.accessToken = '<your access token here>';
var map = L.mapbox.map('map', 'mapbox.streets')
.setView([40, -74.50], 8);
var myLayer = L.mapbox.featureLayer().addTo(map);
var geoJson = [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-75.00, 40]
},
"properties": {
"title": "Small astronaut",
"icon": {
"iconUrl": "/mapbox.js/assets/images/astronaut1.png",
"iconSize": [50, 50], // size of the icon
"iconAnchor": [25, 25], // point of the icon which will correspond to marker's location
"popupAnchor": [0, -25], // point from which the popup should open relative to the iconAnchor
"className": "dot"
}
}
}, {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-74.00, 40]
},
"properties": {
"title": "Big astronaut",
"icon": {
"iconUrl": "/mapbox.js/assets/images/astronaut2.png",
"iconSize": [100, 100],
"iconAnchor": [50, 50],
"popupAnchor": [0, -55],
"className": "dot"
}
}
}];
// Set a custom icon on each marker based on feature properties.
myLayer.on('layeradd', function(e) {
var marker = e.layer,
feature = marker.feature;
marker.setIcon(L.icon(feature.properties.icon));
});
// Add features to the map.
myLayer.setGeoJSON(geoJson);
</script>
</body>
</html>
*Source: https://www.mapbox.com/mapbox.js/example/v1.0.0/custom-marker/

Categories

Resources