13 Commits

Author SHA1 Message Date
Râu Cao
1dc218ca8a 1.7.0 2022-09-14 18:50:38 +02:00
Râu Cao
bfd9b4fdf6 Add riders to map 2022-09-14 18:50:02 +02:00
Râu Cao
67707b7ded 1.6.0 2022-09-14 10:18:29 +02:00
Râu Cao
9c96037e32 Add legacy routes 2022-09-14 10:17:55 +02:00
Râu Cao
fc4c63b519 1.5.0 2022-09-13 07:55:53 +02:00
Râu Cao
fe1c9f6300 Adjust for multiple tracked POIs 2022-09-13 07:55:09 +02:00
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
12 changed files with 229151 additions and 52845 deletions

182553
data/legacy-route.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

11
dist/assets/index.2d0ee7b9.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

4
dist/index.html vendored
View File

@@ -6,11 +6,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Road2Bitcoin Live Map</title>
<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.098b1da4.js"></script>
<script defer data-domain="r2b22.kip.pe" src="https://plausible.io/js/plausible.js"></script>
<script type="module" crossorigin src="/assets/index.2d0ee7b9.js"></script>
<link rel="stylesheet" href="/assets/index.eed9f443.css">
</head>
<body>
<div id="map"><div id="popup"></div></div>
<div id="people"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
</body>

View File

@@ -6,9 +6,11 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Road2Bitcoin Live Map</title>
<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>
<body>
<div id="map"><div id="popup"></div></div>
<div id="people"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
<script type="module" src="./main.js"></script>
</body>

229
main.js
View File

@@ -7,13 +7,15 @@ import Point from 'ol/geom/Point';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {Circle as CircleStyle, Fill, Icon, Stroke, Style} from 'ol/style';
import {OSM, Vector as VectorSource} from 'ol/source';
import {useGeographic, fromLonLat} from 'ol/proj';
import geojsonRoute from './geo/route.json'
import geojsonPOI from './geo/poi.json'
import {useGeographic} from 'ol/proj';
import geojsonRoute from './data/r2b22-route.json'
import geojsonPOI from './data/r2b22-poi.json';
import geojsonLegacy from './data/legacy-route.json';
useGeographic();
const styles = {
async function main() {
const styles = {
lineOrange: new Style({
stroke: new Stroke({
color: '#FF9900',
@@ -54,75 +56,89 @@ const styles = {
}),
})
})
}
}
//
// Route
//
//
// Route
//
const lastStageFinished = 1;
const stagesCompleted = geojsonRoute.features.slice(0, lastStageFinished);
const stagesAhead = geojsonRoute.features.slice(lastStageFinished);
const vectorSourceStagesCompleted = new VectorSource();
const vectorSourceStagesAhead = new VectorSource();
const tourStatus = await fetch('https://r2b22.kip.pe/status.json').then(res => res.json());
for (const stage of stagesCompleted) {
const lastStageFinished = tourStatus.lastStageFinished;
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) {
}
for (const stage of stagesAhead) {
vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage));
}
}
const stagesCompletedLayer = new VectorLayer({
const stagesCompletedLayer = new VectorLayer({
source: vectorSourceStagesCompleted,
style: styles.lineOrange
});
});
const stagesAheadLayer = new VectorLayer({
const stagesAheadLayer = new VectorLayer({
source: vectorSourceStagesAhead,
style: styles.lineGrey
});
});
//
// Points of Interest
//
//
// Points of Interest
//
const vectorSourcePOI = new VectorSource({
const vectorSourcePOI = new VectorSource({
features: new GeoJSON().readFeatures(geojsonPOI),
});
});
const poiLayer = new VectorLayer({
const poiLayer = new VectorLayer({
source: vectorSourcePOI,
style: styles.circleBlack,
});
});
const vectorSourceTrackedPoints = new VectorSource();
const vectorSourceTrackedPoints = new VectorSource();
const vanFeature= new Feature({
const vanFeature= new Feature({
geometry: new Point([8.918618, 44.407408]),
name: 'Support Van',
trackable: true
});
});
vectorSourceTrackedPoints.addFeature(vanFeature);
vectorSourceTrackedPoints.addFeature(vanFeature);
const trackedPointsLayer = new VectorLayer({
const trackedPointsLayer = new VectorLayer({
source: vectorSourceTrackedPoints,
style: styles.iconVan
});
});
//
// Map initialization
//
//
// Legacy routes
//
const view = new View({
const vectorSourceLegacy = new VectorSource();
vectorSourceLegacy.addFeatures(new GeoJSON().readFeatures(geojsonLegacy));
const legacyLayer = new VectorLayer({
source: vectorSourceLegacy,
style: styles.lineOrange
});
//
// Map initialization
//
const view = new View({
center: [10.6, 46.9],
zoom: 6.6
})
})
window.view = view;
window.view = view;
const map = new Map({
const map = new Map({
target: 'map',
layers: [
new TileLayer({
@@ -130,45 +146,46 @@ const map = new Map({
}),
stagesCompletedLayer,
stagesAheadLayer,
legacyLayer,
poiLayer,
trackedPointsLayer
],
view: view
});
});
//
// Center map on current/next stage
//
//
// Center map on current/next stage
//
setTimeout(() => {
setTimeout(() => {
const nextStageFeature = new GeoJSON().readFeature(stagesAhead[0]);
view.fit(nextStageFeature.getGeometry(), {
maxZoom: 10,
duration: 1000
});
}, 3000);
}, 3000);
//
// Popups
//
const popupEl = document.getElementById('popup');
//
// Popups
//
const popupEl = document.getElementById('popup');
const popup = new Overlay({
const popup = new Overlay({
element: popupEl,
positioning: 'bottom-center',
stopEvent: false,
});
map.addOverlay(popup);
});
map.addOverlay(popup);
let popover;
function disposePopover() {
let popover;
function disposePopover() {
if (popover) {
popover.dispose();
popover = undefined;
}
}
}
function createPopoverHtml(feature) {
function createPopoverHtml(feature) {
const container = document.createElement('div');
const title = document.createElement('div');
title.textContent = feature.get('name');
@@ -183,10 +200,10 @@ function createPopoverHtml(feature) {
// linkParent.append(followLink);
// container.append(linkParent);
// }
}
}
// display popup on click
map.on('click', function (evt) {
// display popup on click
map.on('click', function (evt) {
const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
return feature;
});
@@ -201,69 +218,69 @@ map.on('click', function (evt) {
content: createPopoverHtml(feature)
});
popover.show();
});
});
// change mouse cursor when over marker
map.on('pointermove', function (evt) {
// 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);
// Close the popup when the map is moved
map.on('movestart', disposePopover);
//
// Tracking
//
//
// Tracking
//
const updateInterval = 10000;
const peopleOverlays = {};
const updateInterval = 5000;
let followedFeature = vanFeature;
let followedZoomed = false;
// let followedFeature = null;
function createParticipantHTML (name) {
if (document.getElementById(`user-${name}`)) return;
const el = document.createElement('img');
el.src = `https://r2b22.kip.pe/avatars/${name}.png`;
el.id = `user-${name}`;
el.style = 'width: 40px; height: 40px; border-radius: 20px;';
document.getElementById('people').append(el);
}
function startFollowing(feature, followLink) {
followedFeature = feature;
followLink.textContent = 'Stop following';
// followLink.removeEventListener('click', startFollowing);
followLink.addEventListener('click', stopFollowing(feature, followLink));
}
function createParticipantOverlay (name) {
if (peopleOverlays[name]) return;
const overlayElement = new Overlay({
stopEvent: false,
positioning: 'center-center',
element: document.getElementById(`user-${name}`)
});
peopleOverlays[name] = overlayElement;
map.addOverlay(overlayElement);
}
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) {
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);
// console.debug(data);
const vanData = data.find(i => i.name == 'satoshithevan');
const vanCoords = [vanData.lon, vanData.lat];
vanFeature.getGeometry().setCoordinates(vanCoords);
// let zoomLevel;
// if (!followedZoomed) {
// zoomLevel = 13;
// followedZoomed = true;
// }
// if (followedFeature) {
// view.animate({
// center: followedFeature.getGeometry().getCoordinates(),
// duration: 500,
// zoom: zoomLevel
// });
// }
for (const item of data) {
if (!tourStatus.participants.includes(item.name)) continue;
createParticipantHTML(item.name);
createParticipantOverlay(item.name);
const overlay = peopleOverlays[item.name];
overlay.setPosition([item.lon, item.lat]);
}
});
if (startInterval) {
setInterval(updateData, updateInterval);
}
}
updateData(true);
}
updateData(true);
main();

4
package-lock.json generated
View File

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

View File

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

View File

@@ -4,6 +4,7 @@ html, body {
margin: 0;
height: 100%;
}
#map {
position: absolute;
top: 0;