Skip to content

Commit

Permalink
fix: add support for OSM
Browse files Browse the repository at this point in the history
  • Loading branch information
AsoDesu committed Jan 12, 2024
1 parent f3eddfa commit d864257
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 108 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
}

group = "dev.asodesu"
version = "0.0.4"
version = "0.0.5"

java {
sourceCompatibility = JavaVersion.VERSION_17
Expand Down
39 changes: 39 additions & 0 deletions frontend/src/lib/components/GoogleMaps.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script lang="ts">
import { GoogleMapsAdapter } from "$lib/maps/GoogleMapsAdapter";
import type { MapAdapter } from "$lib/maps/MapAdapter";
import { createEventDispatcher, onMount } from "svelte";
const dispatch = createEventDispatcher();
// @ts-ignore
export let mapAdapter: MapAdapter = null;
let container: HTMLDivElement;
export let mapInfo: any;
export let zoom = 17;
export let center: number[];
//@ts-ignore
window.initMap = () => {
mapAdapter = new GoogleMapsAdapter(container, mapInfo, center, zoom);
dispatch("ready", mapAdapter);
};
</script>

<svelte:head>
<script
defer
async
src="https://maps.googleapis.com/maps/api/js?key={mapInfo.apiKey}&callback=initMap"
>
</script>
</svelte:head>

<div class="full-screen" bind:this={container}></div>

<style>
.full-screen {
width: 100vw;
height: 100vh;
}
</style>
49 changes: 49 additions & 0 deletions frontend/src/lib/components/LeafletMaps.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script>
// @ts-nocheck
import { LeafletMapsAdapter } from "$lib/maps/LeaftletMapsAdapter";
import { createEventDispatcher, onMount } from "svelte";
const dispatch = createEventDispatcher();
/**
* @type {HTMLDivElement}
*/
let container;
/**
* @type {MapAdapter}
*/
export let mapAdapter = null;
/**
* @type {number[]}
*/
export let center;
const ready = () => {
mapAdapter = new LeafletMapsAdapter(container, center, 17)
dispatch("ready", mapAdapter);
};
</script>

<svelte:head>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
<script
src="https://unpkg.com/[email protected]/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
on:load={ready}
crossorigin=""
></script>
</svelte:head>

<style>
.full-screen {
width: 100vw;
height: 100vh;
}
</style>

<div class="full-screen" bind:this={container}></div>
26 changes: 0 additions & 26 deletions frontend/src/lib/components/Map.svelte

This file was deleted.

41 changes: 41 additions & 0 deletions frontend/src/lib/maps/GoogleMapsAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { Service } from "$lib/stagecoachTypes";
import { MapAdapter } from "./MapAdapter";

export class GoogleMapsAdapter extends MapAdapter {
map: google.maps.Map;
marker: any;

constructor(
container: HTMLDivElement,
mapOptions: any,
startPos: number[],
scale: number
) {
super();

this.map = new google.maps.Map(container, {
zoom: scale,
center: this.adaptLatLng(startPos),
mapId: mapOptions.mapId,
});
}

async setupMarker(pos: number[], markerElement: HTMLElement) {
//@ts-ignore
const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");

this.marker = new AdvancedMarkerElement({
position: this.adaptLatLng(pos),
map: this.map,
content: markerElement,
});
}

setMarkerPosition(pos: number[]) {
this.marker.position = this.adaptLatLng(pos)
}

adaptLatLng([lat, lng]: number[]): google.maps.LatLng {
return new google.maps.LatLng(lat, lng);
}
}
37 changes: 37 additions & 0 deletions frontend/src/lib/maps/LeaftletMapsAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// @ts-nocheck
import { MapAdapter } from "./MapAdapter";

export class LeafletMapsAdapter extends MapAdapter {
map
marker

/**
* @param {any} container
* @param {any} startPos
* @param {number} scale
*/
constructor(container, startPos, scale) {
super();

this.map = L.map(container).setView(startPos, scale);
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 19,
attribution:
'&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
}).addTo(this.map);
}

setupMarker(pos, markerElement) {
let marker = L.divIcon({ html: markerElement })
this.marker = L.marker(pos, { icon: marker }).addTo(this.map);
}

setMarkerPosition(pos) {
let newPos = this.adaptLatLng(pos)
this.marker.setLatLng(newPos)
}

adaptLatLng(pos) {
return L.latLng(pos[0], pos[1])
}
}
4 changes: 4 additions & 0 deletions frontend/src/lib/maps/MapAdapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class MapAdapter {
setupMarker(pos: number[], markerElement: HTMLElement) {}
setMarkerPosition(pos: number[]) {}
}
9 changes: 7 additions & 2 deletions frontend/src/lib/stagecoach.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { Service } from "./stagecoachTypes"

const BASE_URL = "/api/stagecoach"
const BASE_URL = "http://localhost:8080"

export function fetchVehicleInfo(fleetNo: string): Promise<Service> {
return fetch(`${BASE_URL}/vehicle/${fleetNo}`)
return fetch(`${BASE_URL}/api/stagecoach/vehicle/${fleetNo}`)
.then(res => res.json())
}

export function fetchMapInfo(): Promise<any> {
return fetch(`${BASE_URL}/api/maps/info`)
.then(res => res.json())
}
93 changes: 33 additions & 60 deletions frontend/src/routes/map/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,67 +1,45 @@
<script lang="ts">
import { browser } from "$app/environment";
import { page } from "$app/stores";
import Map from "$lib/components/Map.svelte";
import { fetchVehicleInfo } from "$lib/stagecoach";
import type { MapAdapter } from "$lib/maps/MapAdapter";
import { fetchMapInfo, fetchVehicleInfo } from "$lib/stagecoach";
import type { Service } from "$lib/stagecoachTypes";
import { busService } from "$lib/stores";
import { lerp } from "$lib/utils";
import RouteDisplay from "./components/RouteDisplay.svelte";
let map: google.maps.Map;
let marker: any;
import GoogleMaps from '$lib/components/GoogleMaps.svelte'
import LeaftletMaps from '$lib/components/LeafletMaps.svelte'
let mapInfo: any = null
let map: MapAdapter;
let bus = $page.url.searchParams.get("bus") as string;
let ready = false;
let centre: google.maps.LatLng;
//@ts-ignore
window.initMap = async () => {
if (!browser) return;
let service = await fetchVehicleInfo(bus);
$busService = service;
let lat = +service.latitude;
let lng = +service.longitude;
centre = new google.maps.LatLng(lat, lng);
ready = true;
};
$: ready && createMarker(map);
let interval = setInterval(updateMarker, 5000);
async function fetchBusInfo() {
fetchMapInfo().then(data => mapInfo = data)
fetchVehicleInfo(bus).then(data => $busService = data)
}
fetchBusInfo()
async function createMarker(bindMap: google.maps.Map) {
//@ts-ignore
const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
async function ready(event: CustomEvent) {
let adapter = event.detail as MapAdapter;
let div = document.createElement("div");
div.innerHTML =
'<div style="position:relative; height: 48px;width: 38px;"><img src="https://www.stagecoachbus.com/assets/img/bus_position_icon.svg" style="position:relative; left: 0; top: 0;"/><div style="position:absolute; bottom: 0; left: 0; text-align: center; width:100%; padding-bottom: 2px;"><span class="text-white" style="font-size: x-small;">' +
$busService.serviceNumber +
"</span></div></div>";
marker = new AdvancedMarkerElement({
position: getServiceLatLng($busService),
map: bindMap,
content: div,
});
let markerPos = getServiceLatLng($busService)
adapter.setupMarker(markerPos, div);
}
let interval = setInterval(updateMarker, 5000);
async function updateMarker() {
if (marker == null || !ready) return;
if (map == null) return;
let newServiceData = await fetchVehicleInfo(bus);
let lastPos = getServiceLatLng($busService);
let newPos = getServiceLatLng(newServiceData);
console.log(
{ lat: lastPos.lat(), lng: lastPos.lng() },
{ lat: newPos.lat(), lng: newPos.lng() }
);
if (!document.hidden) {
if (lastPos == null || isNaN(lastPos.lng()) || isNaN(lastPos.lat())) {
marker.position = newPos;
return;
}
// interpolation time!
let interpolationTime = 750;
let frame = 0;
Expand All @@ -72,37 +50,32 @@
return;
}
let t = frame / interpolationTime;
let lng = lerp(lastPos.lng(), newPos.lng(), t);
let lat = lerp(lastPos.lat(), newPos.lat(), t);
marker.position = new google.maps.LatLng(lat, lng);
let lng = lerp(lastPos[1], newPos[1], t);
let lat = lerp(lastPos[0], newPos[0], t);
map.setMarkerPosition([lat, lng]);
frame += 10;
}, 10);
} else {
marker.position = newPos
map.setMarkerPosition(newPos);
}
$busService = newServiceData;
}
function getServiceLatLng(service: Service): google.maps.LatLng {
function getServiceLatLng(service: Service): number[] {
let lat = +service.latitude;
let lng = +service.longitude;
return new google.maps.LatLng(lat, lng);
return [lat, lng];
}
</script>

<svelte:head>
<script
defer
async
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCY8515BQmgpPTeKBOj109D2X0ZHHLxBM0&callback=initMap"
>
</script>
</svelte:head>

{#if ready}
<div class="w-screen h-screen absolute">
<Map center={centre} bind:map />
</div>
{/if}
<div class="w-screen h-screen absolute">
{#if (mapInfo == null || $busService == null)}
Loading map...
{:else if (mapInfo.type == "google")}
<GoogleMaps on:ready={ready} bind:mapAdapter={map} mapInfo={mapInfo} center={getServiceLatLng($busService)} />
{:else if (mapInfo.type == "osm")}
<LeaftletMaps on:ready={ready} bind:mapAdapter={map} center={getServiceLatLng($busService)} />
{/if}
</div>
16 changes: 0 additions & 16 deletions frontend/src/routes/map/components/RouteDisplay.svelte

This file was deleted.

Loading

0 comments on commit d864257

Please sign in to comment.