Skip to content

Commit

Permalink
Merge pull request #4 from ably/feature/add-mapbox-demo
Browse files Browse the repository at this point in the history
Add mapbox demo
  • Loading branch information
owenpearson authored Dec 11, 2020
2 parents 8aa7f0c + aed4bc0 commit ece1157
Show file tree
Hide file tree
Showing 32 changed files with 2,471 additions and 30 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist/
examples/
webpack.config.js
2 changes: 2 additions & 0 deletions examples/subscribing-example-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.env
430 changes: 430 additions & 0 deletions examples/subscribing-example-app/README.md

Large diffs are not rendered by default.

1,236 changes: 1,236 additions & 0 deletions examples/subscribing-example-app/package-lock.json

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions examples/subscribing-example-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "deliveryapp",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"ably": "^1.2.1",
"ably-asset-tracking": "file:../../",
"dotenv": "^8.2.0",
"ejs": "^3.1.5",
"express": "^4.17.1"
},
"engines": {
"node": "12.x"
}
}
64 changes: 64 additions & 0 deletions examples/subscribing-example-app/public/Coordinate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
export class Coordinate {
constructor(lat, lng, bearing = 0) {
this.lat = lat;
this.lng = lng;
this.bearing = bearing;
}

get latitude() {
return this.lat;
}

get longitude() {
return this.lng;
}

get compassDirection() {
return Coordinate.bearingToCompass(this.bearing);
}

toGeoJson() {
return [this.lng, this.lat];
}

static fromGeoJson(coords, bearing = 0) {
return new Coordinate(coords[1], coords[0], bearing);
}

static fromLngLat(lngLatObj, bearing = 0) {
return new Coordinate(lngLatObj.lat, lngLatObj.lng, bearing);
}

static fromMessage(messageData) {
return Coordinate.fromGeoJson(messageData.geometry.coordinates, messageData.properties.bearing);
}

static bearingToCompass(bearing) {
if ((bearing >= 0 && bearing < 23) || (bearing >= 337 && bearing <= 360)) {
return "N";
}
if (bearing >= 23 && bearing < 67) {
return "NE";
}
if (bearing >= 67 && bearing < 113) {
return "E";
}
if (bearing >= 113 && bearing < 158) {
return "SE";
}
if ((bearing >= 158 && bearing < 203) ) {
return "S";
}
if ((bearing >= 203 && bearing < 247) ) {
return "SW";
}
if (bearing >= 247 && bearing < 292) {
return "W";
}
if (bearing >= 292 && bearing < 337) {
return "NW";
}

return null;
}
}
31 changes: 31 additions & 0 deletions examples/subscribing-example-app/public/Google/GoogleMapsMarker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Coordinate } from "../Coordinate.js";

export class GoogleMapsMarker {
constructor(map, markerCoordinate) {
this.map = map;
this.current = markerCoordinate;
this.lastCompassDirection = "N";
this.marker = new google.maps.Marker({ icon: "driverN.png", map: map });
this.map.setZoom(16);
}

getCurrentCoordinate() {
return this.current;
}

updatePosition(targetCoordinate) {
this.marker.setPosition(targetCoordinate);
this.current = targetCoordinate;

const compass = targetCoordinate.compassDirection;

if (compass && compass !== this.lastCompassDirection) {
this.marker.setIcon(`driver${compass}.png`);
this.lastCompassDirection = compass;
}
}

focus() {
this.map.panTo(this.current);
}
}
20 changes: 20 additions & 0 deletions examples/subscribing-example-app/public/Google/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { GoogleMapsMarker } from "./GoogleMapsMarker.js";
import { RiderConnection } from "../RiderConnection.js";
import { Coordinate } from "../Coordinate.js";
import { bindUi } from "../Ui.js";

(async function() {

const position = new Coordinate(0, 0);
const mapElement = document.getElementById("map");
const map = new google.maps.Map(mapElement, { center: position, zoom: 3 });

function createMarker(coordinate) {
return new GoogleMapsMarker(map, coordinate);
}

const riderConnection = new RiderConnection(createMarker);
await riderConnection.connect();

bindUi(riderConnection);
})();
27 changes: 27 additions & 0 deletions examples/subscribing-example-app/public/Mapbox/MapBoxMarker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Coordinate } from "../Coordinate.js";

export class MapBoxMarker {
constructor(map, markerCoordinate) {
this.el = document.createElement('div');
this.el.className = 'marker-mapbox';

this.map = map;
this.marker = new mapboxgl.Marker(this.el)
.setLngLat(markerCoordinate)
.addTo(this.map);
}

getCurrentCoordinate() {
return Coordinate.fromLngLat(this.marker.getLngLat());
}

updatePosition(targetCoordinate) {
this.marker.setLngLat(targetCoordinate);
this.el.setAttribute('compass-direction', targetCoordinate.compassDirection);
}

focus() {
const position = this.getCurrentCoordinate();
this.map.flyTo({center: position, essential: true});
}
}
19 changes: 19 additions & 0 deletions examples/subscribing-example-app/public/Mapbox/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MapBoxMarker } from "./MapBoxMarker.js";
import { RiderConnection } from "../RiderConnection.js";
import { Coordinate } from "../Coordinate.js";
import { bindUi } from "../Ui.js";

(async function() {
const position = new Coordinate(0, 0);
const mapElement = "map";
const map = new mapboxgl.Map({ center: position.toGeoJson(), zoom: 15, container: mapElement, style: 'mapbox://styles/mapbox/streets-v11' });

function createMarker(coordinate) {
return new MapBoxMarker(map, coordinate);
}

const riderConnection = new RiderConnection(createMarker);
await riderConnection.connect();

bindUi(riderConnection);
})();
45 changes: 45 additions & 0 deletions examples/subscribing-example-app/public/RiderConnection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Vehicle } from './Vehicle.js';
import { Coordinate } from './Coordinate.js';

export class RiderConnection {
constructor(createMapSpecificMarker) {
this.createMapSpecificMarker = createMapSpecificMarker;
this.assetSubscriber = new AblyAssetTracking.AssetSubscriber({
ablyOptions: { authUrl: '/api/createTokenRequest' },
onEnhancedLocationUpdate: (message) => {
this.processMessage(message);
},
onStatusUpdate: (status) => {
this.statusUpdateCallback(status);
},
});
this.shouldSnap = false;
}

async connect(channelId) {
if (this.assetSubscriber.assetConnection) {
await this.assetSubscriber.stop();
}

this.assetSubscriber.start(channelId || 'ivan');
}

processMessage(message) {
const locationCoordinate = Coordinate.fromMessage(message);

const riderId = locationCoordinate.id ?? 'default-id';

if (!this.rider) {
const marker = this.createMapSpecificMarker(locationCoordinate);
this.rider = new Vehicle(riderId, true, marker);

marker.focus();
}

this.rider.move(locationCoordinate, this.shouldSnap);
}

onStatusUpdate(callbackFunction) {
this.statusUpdateCallback = callbackFunction;
}
}
42 changes: 42 additions & 0 deletions examples/subscribing-example-app/public/Ui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
export function bindUi(riderConnectionInstance) {

var queryParams = new URLSearchParams(window.location.search);

const updateChannelButton = document.getElementById("updateChannelButton");
const channelIdTextBox = document.getElementById("channelID");
const animationCheckbox = document.getElementById("animation");
const subscriberCount = document.getElementById("subscriberCount");

if (!updateChannelButton || !channelIdTextBox) {
throw new Error("Where has the UI gone? Cannot continue. Can't find ChannelID");
}

animationCheckbox.addEventListener("change", (cbEvent) => {
riderConnectionInstance.shouldSnap = !cbEvent.target.checked;
});

updateChannelButton.addEventListener("click", () => {
const channelValue = channelIdTextBox.value;
if (channelValue.length > 0) {
riderConnectionInstance.connect(channelIdTextBox.value);
}
});

if (queryParams.has("channel")) {
const channelId = queryParams.get("channel");
channelIdTextBox.value = channelId;
riderConnectionInstance.connect(channelId);
}

riderConnectionInstance.onStatusUpdate((status) => { updateDriverStatus(status); });
updateDriverStatus(riderConnectionInstance.driverStatus);
}


function updateDriverStatus(status) {
const driverPresent = "Driver is online";
const noDrivers = "Driver is offline";

const message = status ? driverPresent : noDrivers;
subscriberCount.innerHTML = message;
}
66 changes: 66 additions & 0 deletions examples/subscribing-example-app/public/Vehicle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Coordinate } from "./Coordinate.js";

export class Vehicle {

constructor(id, follow, markerWrapper) {
this.id = id;
this.follow = follow || false;

this.marker = markerWrapper;

this.moveBuffer = [];
this.animationRateMs = 33;
this.animate();

this.movementsSinceLastFocused = 0;
this.numberOfMovementsToFocusAfter = 100;
}

get position() {
return this.marker.getCurrentCoordinate();
}

async move(destinationCoordinate, snapToLocation = false) {
this.movementsSinceLastFocused++;

if (snapToLocation) {
this.moveBuffer = [ destinationCoordinate ];
return;
}

this.moveBuffer = [];

const currentCoordinate = this.marker.getCurrentCoordinate();

var path = turf.lineString([ currentCoordinate.toGeoJson(), destinationCoordinate.toGeoJson() ]);
var pathLength = turf.length(path, { units: 'miles' });

var numSteps = 30; // This is the FPS

for (let step = 0; step <= numSteps; step++) {
const curDistance = step / numSteps * pathLength;
const targetLocation = turf.along(path, curDistance, { units: "miles" });

const targetCoordinate = Coordinate.fromGeoJson(targetLocation.geometry.coordinates, destinationCoordinate.bearing);

this.moveBuffer.push(targetCoordinate);
}
}

async animate() {
if (this.moveBuffer.length === 0) {
window.requestAnimationFrame(() => { this.animate(); });
return;
}

const targetCoordinate = this.moveBuffer.shift();
this.marker.updatePosition(targetCoordinate);

if (this.movementsSinceLastFocused >= this.numberOfMovementsToFocusAfter) {
this.movementsSinceLastFocused = 0;
this.marker.focus();
}

window.requestAnimationFrame(() => { this.animate(); });
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/subscribing-example-app/public/driverN.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/subscribing-example-app/public/driverS.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file added examples/subscribing-example-app/public/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ece1157

Please sign in to comment.