9 Commits

Author SHA1 Message Date
Râu Cao
0d66bc1266 1.4.0 2022-09-11 12:31:26 +02:00
Râu Cao
ba3982d9a6 Add plausible analytics script 2022-09-11 12:30:52 +02:00
Râu Cao
f2cc9a9783 1.3.0 2022-09-09 20:29:41 +02:00
Râu Cao
0c1aeebdf7 Load current tour status from server 2022-09-09 20:29:18 +02:00
Râu Cao
3324a57206 Update route 2022-09-09 20:29:00 +02:00
Râu Cao
cf8e6882f8 1.2.1 2022-09-08 09:49:18 +02:00
Râu Cao
6c4959deda Hackety hack, no time 2022-09-08 09:48:51 +02:00
Râu Cao
e00b5576e6 1.2.0 2022-09-06 21:09:39 +02:00
Râu Cao
e06b9d5109 MVP 2022-09-06 21:09:06 +02:00
9 changed files with 46582 additions and 52826 deletions

11
dist/assets/index.148d1b99.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3
dist/index.html vendored
View File

@@ -6,7 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Road2Bitcoin Live Map</title> <title>Road2Bitcoin Live Map</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css">
<script type="module" crossorigin src="/assets/index.b64a86a4.js"></script> <script defer data-domain="r2b22.kip.pe" src="https://plausible.io/js/plausible.js"></script>
<script type="module" crossorigin src="/assets/index.148d1b99.js"></script>
<link rel="stylesheet" href="/assets/index.eed9f443.css"> <link rel="stylesheet" href="/assets/index.eed9f443.css">
</head> </head>
<body> <body>

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Road2Bitcoin Live Map</title> <title>Road2Bitcoin Live Map</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css">
<script defer data-domain="r2b22.kip.pe" src="https://plausible.io/js/plausible.js"></script>
</head> </head>
<body> <body>
<div id="map"><div id="popup"></div></div> <div id="map"><div id="popup"></div></div>

453
main.js
View File

@@ -13,240 +13,263 @@ import geojsonPOI from './geo/poi.json'
useGeographic(); useGeographic();
const styles = { async function main() {
lineOrange: new Style({ const styles = {
stroke: new Stroke({ lineOrange: new Style({
color: '#FF9900',
// lineDash: [8],
width: 5,
}),
}),
lineGrey: new Style({
stroke: new Stroke({
color: '#555555',
// lineDash: [8],
width: 5,
}),
}),
iconStop: new Style({
image: new Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '/img/icon.png',
}),
}),
iconVan: new Style({
image: new Icon({
anchor: [0.5, 16],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: '/img/van-100px.png',
}),
}),
circleBlack: new Style({
image: new CircleStyle({
radius: 7,
fill: new Fill({color: '#FF9900'}),
stroke: new Stroke({ stroke: new Stroke({
color: 'white', color: '#FF9900',
width: 2, // lineDash: [8],
width: 5,
}), }),
})
})
}
//
// Route
//
const lastStageFinished = 4;
const stagesCompleted = geojsonRoute.features.slice(0, lastStageFinished);
const stagesAhead = geojsonRoute.features.slice(lastStageFinished);
const vectorSourceStagesCompleted = new VectorSource();
const vectorSourceStagesAhead = new VectorSource();
for (const stage of stagesCompleted) {
vectorSourceStagesCompleted.addFeature(new GeoJSON().readFeature(stage));
}
for (const stage of stagesAhead) {
vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage));
}
const stagesCompletedLayer = new VectorLayer({
source: vectorSourceStagesCompleted,
style: styles.lineOrange
});
const stagesAheadLayer = new VectorLayer({
source: vectorSourceStagesAhead,
style: styles.lineGrey
});
//
// Points of Interest
//
const vectorSourcePOI = new VectorSource({
features: new GeoJSON().readFeatures(geojsonPOI),
});
const poiLayer = new VectorLayer({
source: vectorSourcePOI,
style: styles.circleBlack,
});
const vectorSourceTrackedPoints = new VectorSource();
const vanFeature= new Feature({
geometry: new Point([8.918618, 44.407408]),
name: 'Support Van',
trackable: true
});
vectorSourceTrackedPoints.addFeature(vanFeature);
const trackedPointsLayer = new VectorLayer({
source: vectorSourceTrackedPoints,
style: styles.iconVan
});
//
// Map initialization
//
const view = new View({
center: [10.6, 46.9],
zoom: 6.6
})
window.view = view;
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
}), }),
stagesCompletedLayer, lineGrey: new Style({
stagesAheadLayer, stroke: new Stroke({
poiLayer, color: '#555555',
trackedPointsLayer // lineDash: [8],
], width: 5,
view: view }),
}); }),
iconStop: new Style({
// image: new Icon({
// Popups anchor: [0.5, 46],
// anchorXUnits: 'fraction',
const popupEl = document.getElementById('popup'); anchorYUnits: 'pixels',
src: '/img/icon.png',
const popup = new Overlay({ }),
element: popupEl, }),
positioning: 'bottom-center', iconVan: new Style({
stopEvent: false, image: new Icon({
}); anchor: [0.5, 16],
map.addOverlay(popup); anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
let popover; src: '/img/van-100px.png',
function disposePopover() { }),
if (popover) { }),
popover.dispose(); circleBlack: new Style({
popover = undefined; image: new CircleStyle({
} radius: 7,
} fill: new Fill({color: '#FF9900'}),
stroke: new Stroke({
function createPopoverHtml(feature) { color: 'white',
const container = document.createElement('div'); width: 2,
container.className = 'popover-content'; }),
const title = document.createElement('div'); })
title.textContent = feature.get('name'); })
container.append(title);
if (feature.get('trackable')) {
const linkParent = document.createElement('div');
const followLink = document.createElement('a');
followLink.textContent = "Follow";
followLink.addEventListener('click', console.log(feature, followLink));
// followLink.addEventListener('click', startFollowing(feature, followLink));
linkParent.append(followLink);
container.append(linkParent);
} }
return container.innerHTML; //
} // Route
//
// display popup on click const tourStatus = await fetch('https://r2b22.kip.pe/status.json').then(res => res.json());
map.on('click', function (evt) {
const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) { const lastStageFinished = tourStatus.lastStageFinished;
return feature; const stagesCompleted = geojsonRoute.features.slice(0, lastStageFinished);
const stagesAhead = geojsonRoute.features.slice(lastStageFinished);
const vectorSourceStagesCompleted = new VectorSource();
const vectorSourceStagesAhead = new VectorSource();
for (const stage of stagesCompleted) {
vectorSourceStagesCompleted.addFeature(new GeoJSON().readFeature(stage));
}
for (const stage of stagesAhead) {
vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage));
}
const stagesCompletedLayer = new VectorLayer({
source: vectorSourceStagesCompleted,
style: styles.lineOrange
}); });
disposePopover();
if (!feature) { const stagesAheadLayer = new VectorLayer({
return; source: vectorSourceStagesAhead,
} style: styles.lineGrey
popup.setPosition(evt.coordinate);
popover = new bootstrap.Popover(popupEl, {
placement: 'top',
html: true,
content: createPopoverHtml(feature)
}); });
popover.show();
});
// change mouse cursor when over marker //
map.on('pointermove', function (evt) { // Points of Interest
map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel) //
? 'pointer'
: '';
});
// Close the popup when the map is moved const vectorSourcePOI = new VectorSource({
map.on('movestart', disposePopover); features: new GeoJSON().readFeatures(geojsonPOI),
});
const poiLayer = new VectorLayer({
source: vectorSourcePOI,
style: styles.circleBlack,
});
// const vectorSourceTrackedPoints = new VectorSource();
// Tracking
//
const updateInterval = 5000; const vanFeature= new Feature({
let followedFeature = vanFeature; geometry: new Point([8.918618, 44.407408]),
// let followedFeature = null; name: 'Support Van',
trackable: true
});
function startFollowing(feature, followLink) { vectorSourceTrackedPoints.addFeature(vanFeature);
followedFeature = feature;
followLink.textContent = 'Stop following';
// followLink.removeEventListener('click', startFollowing);
followLink.addEventListener('click', stopFollowing(feature, followLink));
}
function stopFollowing(feature, followLink) { const trackedPointsLayer = new VectorLayer({
followedFeature = null; source: vectorSourceTrackedPoints,
followLink.textContent = 'Stop following'; style: styles.iconVan
// followLink.removeEventListener('click', stopFollowing); });
followLink.addEventListener('click', startFollowing(feature, followLink));
}
function updateData(startInterval=false) { //
fetch('https://r2b22.kip.pe/last.json') // Map initialization
.then(response => response.json()) //
.then(data => {
console.log(data);
const coords = [data.lon, data.lat];
vanFeature.getGeometry().setCoordinates(coords);
if (followedFeature) { const view = new View({
view.animate({ center: [10.6, 46.9],
center: followedFeature.getGeometry().getCoordinates(), zoom: 6.6
duration: 500, })
zoom: 13
}); window.view = view;
}
const map = new Map({
target: 'map',
layers: [
new TileLayer({
source: new OSM()
}),
stagesCompletedLayer,
stagesAheadLayer,
poiLayer,
trackedPointsLayer
],
view: view
});
//
// Center map on current/next stage
//
setTimeout(() => {
const nextStageFeature = new GeoJSON().readFeature(stagesAhead[0]);
view.fit(nextStageFeature.getGeometry(), {
maxZoom: 10,
duration: 1000
}); });
}, 3000);
if (startInterval) { //
setInterval(updateData, updateInterval); // Popups
//
const popupEl = document.getElementById('popup');
const popup = new Overlay({
element: popupEl,
positioning: 'bottom-center',
stopEvent: false,
});
map.addOverlay(popup);
let popover;
function disposePopover() {
if (popover) {
popover.dispose();
popover = undefined;
}
} }
function createPopoverHtml(feature) {
const container = document.createElement('div');
const title = document.createElement('div');
title.textContent = feature.get('name');
container.append(title);
return container.innerHTML;
// if (feature.get('trackable')) {
// const linkParent = document.createElement('div');
// const followLink = document.createElement('a');
// followLink.textContent = 'Follow';
// followLink.href = '#';
// followLink.addEventListener('click', startFollowing(feature, followLink));
// linkParent.append(followLink);
// container.append(linkParent);
// }
}
// display popup on click
map.on('click', function (evt) {
const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
return feature;
});
disposePopover();
if (!feature) {
return;
}
popup.setPosition(evt.coordinate);
popover = new bootstrap.Popover(popupEl, {
placement: 'top',
html: true,
content: createPopoverHtml(feature)
});
popover.show();
});
// change mouse cursor when over marker
map.on('pointermove', function (evt) {
map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel)
? 'pointer'
: '';
});
// Close the popup when the map is moved
map.on('movestart', disposePopover);
//
// Tracking
//
const updateInterval = 5000;
// let followedFeature = vanFeature;
// let followedZoomed = false;
// let followedFeature = null;
function startFollowing(feature, followLink) {
followedFeature = feature;
followLink.textContent = 'Stop following';
// followLink.removeEventListener('click', startFollowing);
followLink.addEventListener('click', stopFollowing(feature, followLink));
}
function stopFollowing(feature, followLink) {
followedFeature = null;
followedZoomed = false;
followLink.textContent = 'Stop following';
// followLink.removeEventListener('click', stopFollowing);
followLink.addEventListener('click', startFollowing(feature, followLink));
}
function updateData(startInterval=false) {
fetch('https://r2b22.kip.pe/last.json')
.then(response => response.json())
.then(data => {
console.log(data);
const coords = [data.lon, data.lat];
vanFeature.getGeometry().setCoordinates(coords);
// let zoomLevel;
// if (!followedZoomed) {
// zoomLevel = 13;
// followedZoomed = true;
// }
// if (followedFeature) {
// view.animate({
// center: followedFeature.getGeometry().getCoordinates(),
// duration: 500,
// zoom: zoomLevel
// });
// }
});
if (startInterval) {
setInterval(updateData, updateInterval);
}
}
updateData(true);
} }
updateData(true); main();

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "ol-vite", "name": "ol-vite",
"version": "1.1.0", "version": "1.4.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ol-vite", "name": "ol-vite",
"version": "1.1.0", "version": "1.4.0",
"dependencies": { "dependencies": {
"ol": "latest" "ol": "latest"
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "map", "name": "map",
"version": "1.1.0", "version": "1.4.0",
"scripts": { "scripts": {
"start": "vite", "start": "vite",
"build": "vite build", "build": "vite build",