Last active
June 19, 2018 16:16
-
-
Save c16a/6e3916eb8156c3ccfa231c627fd5ab8e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset='utf-8' /> | |
<title>Animate a point</title> | |
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=yes' /> | |
<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' /> | |
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.21.2.js"></script> | |
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/turf/v2.0.0/turf.min.js' charset='utf-8'></script> | |
<style> | |
body { | |
margin: 0; | |
padding: 0; | |
} | |
#map { | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
width: 100%; | |
} | |
</style> | |
</head> | |
<body> | |
<div id='map'></div> | |
<script> | |
var points = []; | |
class Point { | |
constructor(id, lat, lon) { | |
this.id = id; | |
this.lat = lat; | |
this.lon = lon; | |
} | |
} | |
mapboxgl.accessToken = 'pk.eyJ1IjoibXVudWt1dGxhIiwiYSI6ImNqaWFoZDE1YzAxdnEzcG54dDd1M3dhbWEifQ.JdHu_4E9Ky3n-73LSUfwdQ'; | |
var map = new mapboxgl.Map({ | |
container: 'map', | |
style: 'mapbox://styles/mapbox/streets-v9', | |
center: [0, 0], | |
zoom: 2 | |
}); | |
pubnub = new PubNub({ | |
publishKey: '', | |
subscribeKey: 'sub-c-18580a92-f8cc-11e5-9086-02ee2ddab7fe' | |
}) | |
pubnub.addListener({ | |
message: pubnubListener, | |
presence: function (presenceEvent) { | |
// handle presence | |
} | |
}); | |
map.on('load', () => { | |
pubnub.subscribe({ | |
channels: ['exp-channel'] | |
}); | |
}) | |
function getCenter(points) { | |
var minLat = Math.min(...points.map(p => p.lat)); | |
var maxLat = Math.max(...points.map(p => p.lat)); | |
var minLong = Math.min(...points.map(p => p.lon)); | |
var maxLong = Math.max(...points.map(p => p.lon)); | |
var centerLong = (maxLong - minLong) / 2; | |
var centerLat = (maxLat - minLat) / 2; | |
return [centerLat, centerLong]; | |
} | |
// San Francisco | |
var origin = [-122.414, 37.776]; | |
function pubnubListener(m) { | |
var point = JSON.parse(m.message); | |
var coords = [parseFloat(point["Latitude"]), parseFloat(point["Longitude"])]; | |
var deviceId = point["DeviceID"]; | |
console.log(coords); | |
console.log(deviceId); | |
var pointObj = new Point(deviceId, coords[0], coords[1]); | |
var center = getCenter(points); | |
if (points.length > 1) { | |
map.setCenter(center); | |
} | |
var point = { | |
"type": "FeatureCollection", | |
"features": [{ | |
"type": "Feature", | |
"properties": { | |
"name": deviceId, | |
"icon": "monument" | |
}, | |
"geometry": { | |
"type": "Point", | |
"coordinates": coords | |
} | |
}] | |
}; | |
var oldPoint = points.find(p => p.id == deviceId) | |
var objIndex = points.findIndex(p => p.id == deviceId) | |
if (oldPoint) { | |
console.log("old point") | |
// If it's an old point | |
var route = { | |
"type": "FeatureCollection", | |
"features": [{ | |
"type": "Feature", | |
"geometry": { | |
"type": "LineString", | |
"coordinates": [ | |
[oldPoint.lat, oldPoint.lon], | |
[coords[0], coords[1]] | |
] | |
} | |
}] | |
}; | |
// Calculate the distance in kilometers between route start/end point. | |
var lineDistance = turf.lineDistance(route.features[0], 'kilometers'); | |
var arc = []; | |
var steps = 200; | |
// 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; | |
function animate() { | |
// Update point geometry to a new position based on counter denoting | |
// the index to access the arc. | |
point.features[0].geometry.coordinates = route.features[0].geometry.coordinates[counter]; | |
// Update the source with this new data. | |
map.getSource('points-' + deviceId).setData(point); | |
// Request the next frame of animation so long the end has not been reached. | |
if (counter < steps) { | |
requestAnimationFrame(animate); | |
} | |
counter = counter + 1; | |
} | |
// Reset the counter | |
counter = 0; | |
// Restart the animation. | |
animate(counter); | |
points[objIndex].lat = coords[0]; | |
points[objIndex].lon = coords[1]; | |
} else { | |
console.log("New point") | |
map.addLayer({ | |
"id": "points-" + deviceId, | |
"type": "symbol", | |
"source": { | |
"type": "geojson", | |
"data": point | |
}, | |
"layout": { | |
"icon-image": "{icon}-15", | |
"text-field": "{title}", | |
"text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"], | |
"text-offset": [0, 0.6], | |
"text-anchor": "top" | |
} | |
}); | |
points.push(pointObj); | |
map.on('click', 'points-' + deviceId, function (e) { | |
new mapboxgl.Popup() | |
.setLngLat(e.lngLat) | |
.setHTML(e.features[0].properties.name) | |
.addTo(map); | |
}); | |
// Change the cursor to a pointer when the mouse is over the states layer. | |
map.on('mouseenter', 'points-' + deviceId, function () { | |
map.getCanvas().style.cursor = 'pointer'; | |
}); | |
// Change it back to a pointer when it leaves. | |
map.on('mouseleave', 'points-' + deviceId, function () { | |
map.getCanvas().style.cursor = ''; | |
}); | |
var center = getCenter(points); | |
map.setCenter(center); | |
} | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment