25 Commits

Author SHA1 Message Date
Râu Cao bedb066407 1.10.1 2022-09-17 09:38:35 +02:00
Râu Cao 27c7067c04 Link logo to main page 2022-09-17 09:37:59 +02:00
Râu Cao 6ee5254780 1.10.0 2022-09-16 12:16:54 +02:00
Râu Cao 8bd7535163 Add donation widget 2022-09-16 12:16:25 +02:00
Râu Cao 7a1e4232f4 1.9.1 2022-09-16 11:05:42 +02:00
Râu Cao cf2c5c0021 Add logo 2022-09-16 11:05:18 +02:00
Râu Cao e74e460480 1.9.0 2022-09-15 10:02:34 +02:00
Râu Cao 0cb10203c7 Only show riders when tracking timestamp is newer than 3 hours ago 2022-09-15 10:02:15 +02:00
Râu Cao a8c0aefbd6 1.8.0 2022-09-14 19:05:41 +02:00
Râu Cao 9c18cc19b7 Add popover for rider markers 2022-09-14 19:05:15 +02:00
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
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
17 changed files with 229205 additions and 52831 deletions
+182553
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
.ol-box{box-sizing:border-box;border-radius:2px;border:1.5px solid rgb(179,197,219);background-color:#fff6}.ol-mouse-position{top:8px;right:8px;position:absolute}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px;padding:2px;position:absolute}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width;transition:all .25s}.ol-scale-singlebar-even{background-color:#000}.ol-scale-singlebar-odd{background-color:#fff}.ol-scale-bar{position:absolute;bottom:8px;left:8px}.ol-scale-step-marker{width:1px;height:15px;background-color:#000;float:right;z-index:10}.ol-scale-step-text{position:absolute;bottom:-5px;font-size:12px;z-index:11;color:#000;text-shadow:-2px 0 #FFFFFF,0 2px #FFFFFF,2px 0 #FFFFFF,0 -2px #FFFFFF}.ol-scale-text{position:absolute;font-size:14px;text-align:center;bottom:25px;color:#000;text-shadow:-2px 0 #FFFFFF,0 2px #FFFFFF,2px 0 #FFFFFF,0 -2px #FFFFFF}.ol-scale-singlebar{position:relative;height:10px;z-index:9;box-sizing:border-box;border:1px solid black}.ol-unsupported{display:none}.ol-viewport,.ol-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.ol-viewport canvas{all:unset}.ol-selectable{-webkit-touch-callout:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ol-grabbing{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.ol-grab{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.ol-control{position:absolute;background-color:#fff6;border-radius:4px;padding:2px}.ol-control:hover{background-color:#fff9}.ol-zoom{top:.5em;left:.5em}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s}.ol-zoom-extent{top:4.643em;left:.5em}.ol-full-screen{right:.5em;top:.5em}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-weight:700;text-decoration:none;font-size:inherit;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:#003c8880;border:none;border-radius:2px}.ol-control button::-moz-focus-inner{border:none;padding:0}.ol-zoom-extent button{line-height:1.4em}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform}.ol-touch .ol-control button{font-size:1.5em}.ol-touch .ol-zoom-extent{top:5.5em}.ol-control button:hover,.ol-control button:focus{text-decoration:none;background-color:#003c88b3}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em);display:flex;flex-flow:row-reverse;align-items:center}.ol-attribution a{color:#003c88b3;text-decoration:none}.ol-attribution ul{margin:0;padding:1px .5em;color:#000;text-shadow:0 0 2px #fff;font-size:12px}.ol-attribution li{display:inline;list-style:none}.ol-attribution li:not(:last-child):after{content:" "}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle}.ol-attribution button{flex-shrink:0}.ol-attribution.ol-collapsed ul{display:none}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em}.ol-attribution.ol-uncollapsible button{display:none}.ol-zoomslider{top:4.5em;left:.5em;height:200px}.ol-zoomslider button{position:relative;height:10px}.ol-touch .ol-zoomslider{top:5.5em}.ol-overviewmap{left:.5em;bottom:.5em}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0}.ol-overviewmap .ol-overviewmap-map,.ol-overviewmap button{display:block}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px}.ol-overviewmap:not(.ol-collapsed) button{bottom:2px;left:2px;position:absolute}.ol-overviewmap.ol-collapsed .ol-overviewmap-map,.ol-overviewmap.ol-uncollapsible button{display:none}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7)}.ol-overviewmap .ol-overviewmap-box:hover{cursor:move}html,body{margin:0;height:100%}#map{position:absolute;top:0;bottom:0;width:100%} .ol-box{box-sizing:border-box;border-radius:2px;border:1.5px solid rgb(179,197,219);background-color:#fff6}.ol-mouse-position{top:8px;right:8px;position:absolute}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px;padding:2px;position:absolute}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width;transition:all .25s}.ol-scale-singlebar-even{background-color:#000}.ol-scale-singlebar-odd{background-color:#fff}.ol-scale-bar{position:absolute;bottom:8px;left:8px}.ol-scale-step-marker{width:1px;height:15px;background-color:#000;float:right;z-index:10}.ol-scale-step-text{position:absolute;bottom:-5px;font-size:12px;z-index:11;color:#000;text-shadow:-2px 0 #FFFFFF,0 2px #FFFFFF,2px 0 #FFFFFF,0 -2px #FFFFFF}.ol-scale-text{position:absolute;font-size:14px;text-align:center;bottom:25px;color:#000;text-shadow:-2px 0 #FFFFFF,0 2px #FFFFFF,2px 0 #FFFFFF,0 -2px #FFFFFF}.ol-scale-singlebar{position:relative;height:10px;z-index:9;box-sizing:border-box;border:1px solid black}.ol-unsupported{display:none}.ol-viewport,.ol-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}.ol-viewport canvas{all:unset}.ol-selectable{-webkit-touch-callout:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ol-grabbing{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.ol-grab{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.ol-control{position:absolute;background-color:#fff6;border-radius:4px;padding:2px}.ol-control:hover{background-color:#fff9}.ol-zoom{top:.5em;left:.5em}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s}.ol-zoom-extent{top:4.643em;left:.5em}.ol-full-screen{right:.5em;top:.5em}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-weight:700;text-decoration:none;font-size:inherit;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:#003c8880;border:none;border-radius:2px}.ol-control button::-moz-focus-inner{border:none;padding:0}.ol-zoom-extent button{line-height:1.4em}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform}.ol-touch .ol-control button{font-size:1.5em}.ol-touch .ol-zoom-extent{top:5.5em}.ol-control button:hover,.ol-control button:focus{text-decoration:none;background-color:#003c88b3}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em);display:flex;flex-flow:row-reverse;align-items:center}.ol-attribution a{color:#003c88b3;text-decoration:none}.ol-attribution ul{margin:0;padding:1px .5em;color:#000;text-shadow:0 0 2px #fff;font-size:12px}.ol-attribution li{display:inline;list-style:none}.ol-attribution li:not(:last-child):after{content:" "}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle}.ol-attribution button{flex-shrink:0}.ol-attribution.ol-collapsed ul{display:none}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em}.ol-attribution.ol-uncollapsible button{display:none}.ol-zoomslider{top:4.5em;left:.5em;height:200px}.ol-zoomslider button{position:relative;height:10px}.ol-touch .ol-zoomslider{top:5.5em}.ol-overviewmap{left:.5em;bottom:.5em}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0}.ol-overviewmap .ol-overviewmap-map,.ol-overviewmap button{display:block}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px}.ol-overviewmap:not(.ol-collapsed) button{bottom:2px;left:2px;position:absolute}.ol-overviewmap.ol-collapsed .ol-overviewmap-map,.ol-overviewmap.ol-uncollapsible button{display:none}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7)}.ol-overviewmap .ol-overviewmap-box:hover{cursor:move}html,body{margin:0;height:100%}#map{position:absolute;top:0;bottom:0;width:100%}img#logo{position:absolute;top:10px;right:10px;width:256px;height:auto}lightning-widget{display:block;position:absolute;bottom:10px;left:10px;width:200px}@media only screen and (max-width: 600px){lightning-widget{display:block;position:absolute;right:10px;width:auto}}
-11
View File
File diff suppressed because one or more lines are too long
+11
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+11 -2
View File
@@ -6,12 +6,21 @@
<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>
<link rel="stylesheet" href="/assets/index.eed9f443.css"> <script type="module" crossorigin src="/assets/index.b6f9bc24.js"></script>
<link rel="stylesheet" href="/assets/index.a04fc84d.css">
</head> </head>
<body> <body>
<div id="map"><div id="popup"></div></div> <div id="map"><div id="popup"></div></div>
<div id="people"></div>
<a href="https://teamsatoshi.org/wiki/Road2Bitcoin_2022" title="Road2Bitcoin 2022"><img id="logo" src="/img/r2b-logo.png"></a>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script>
<lightning-widget name=""
accent="#e01b24"
to="team-satoshi@kosmos.org"
image="" />
<script src="/js/lightning-widget.js"></script>
</body> </body>
</html> </html>
+2
View File
File diff suppressed because one or more lines are too long
+9
View File
@@ -6,10 +6,19 @@
<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>
<div id="people"></div>
<a href="https://teamsatoshi.org/wiki/Road2Bitcoin_2022" title="Road2Bitcoin 2022"><img id="logo" src="/img/r2b-logo.png"></a>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"></script> <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> <script type="module" src="./main.js"></script>
<lightning-widget name=""
accent="#e01b24"
to="team-satoshi@kosmos.org"
image="" />
<script src="/js/lightning-widget.js"></script>
</body> </body>
</html> </html>
+149 -107
View File
@@ -7,13 +7,15 @@ import Point from 'ol/geom/Point';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer'; import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {Circle as CircleStyle, Fill, Icon, Stroke, Style} from 'ol/style'; import {Circle as CircleStyle, Fill, Icon, Stroke, Style} from 'ol/style';
import {OSM, Vector as VectorSource} from 'ol/source'; import {OSM, Vector as VectorSource} from 'ol/source';
import {useGeographic, fromLonLat} from 'ol/proj'; import {useGeographic} from 'ol/proj';
import geojsonRoute from './geo/route.json' import geojsonRoute from './data/r2b22-route.json'
import geojsonPOI from './geo/poi.json' import geojsonPOI from './data/r2b22-poi.json';
import geojsonLegacy from './data/legacy-route.json';
useGeographic(); useGeographic();
const styles = { async function main() {
const styles = {
lineOrange: new Style({ lineOrange: new Style({
stroke: new Stroke({ stroke: new Stroke({
color: '#FF9900', color: '#FF9900',
@@ -54,75 +56,88 @@ const styles = {
}), }),
}) })
}) })
} }
// //
// Route // Route
// //
const lastStageFinished = 4; const tourStatus = await fetch('https://r2b22.kip.pe/status.json').then(res => res.json());
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) { 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)); vectorSourceStagesCompleted.addFeature(new GeoJSON().readFeature(stage));
} }
for (const stage of stagesAhead) { for (const stage of stagesAhead) {
vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage)); vectorSourceStagesAhead.addFeature(new GeoJSON().readFeature(stage));
} }
const stagesCompletedLayer = new VectorLayer({ const stagesCompletedLayer = new VectorLayer({
source: vectorSourceStagesCompleted, source: vectorSourceStagesCompleted,
style: styles.lineOrange style: styles.lineOrange
}); });
const stagesAheadLayer = new VectorLayer({ const stagesAheadLayer = new VectorLayer({
source: vectorSourceStagesAhead, source: vectorSourceStagesAhead,
style: styles.lineGrey style: styles.lineGrey
}); });
// //
// Points of Interest // Points of Interest
// //
const vectorSourcePOI = new VectorSource({ const vectorSourcePOI = new VectorSource({
features: new GeoJSON().readFeatures(geojsonPOI), features: new GeoJSON().readFeatures(geojsonPOI),
}); });
const poiLayer = new VectorLayer({ const poiLayer = new VectorLayer({
source: vectorSourcePOI, source: vectorSourcePOI,
style: styles.circleBlack, 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]), geometry: new Point([8.918618, 44.407408]),
name: 'Support Van', name: 'Support Van'
trackable: true });
});
vectorSourceTrackedPoints.addFeature(vanFeature); vectorSourceTrackedPoints.addFeature(vanFeature);
const trackedPointsLayer = new VectorLayer({ const trackedPointsLayer = new VectorLayer({
source: vectorSourceTrackedPoints, source: vectorSourceTrackedPoints,
style: styles.iconVan 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], center: [10.6, 46.9],
zoom: 6.6 zoom: 6.6
}) })
window.view = view; window.view = view;
const map = new Map({ const map = new Map({
target: 'map', target: 'map',
layers: [ layers: [
new TileLayer({ new TileLayer({
@@ -130,61 +145,60 @@ const map = new Map({
}), }),
stagesCompletedLayer, stagesCompletedLayer,
stagesAheadLayer, stagesAheadLayer,
legacyLayer,
poiLayer, poiLayer,
trackedPointsLayer trackedPointsLayer
], ],
view: view view: view
}); });
// //
// Popups // Center map on current/next stage
// //
const popupEl = document.getElementById('popup');
const popup = new Overlay({ setTimeout(() => {
const nextStageFeature = new GeoJSON().readFeature(stagesAhead[0]);
view.fit(nextStageFeature.getGeometry(), {
maxZoom: 10,
duration: 1000
});
}, 3000);
//
// Popups
//
const popupEl = document.getElementById('popup');
const popup = new Overlay({
element: popupEl, element: popupEl,
positioning: 'bottom-center', positioning: 'bottom-center',
stopEvent: false, stopEvent: false,
}); });
map.addOverlay(popup); map.addOverlay(popup);
let popover; let popover;
function disposePopover() { function disposePopover() {
if (popover) { if (popover) {
popover.dispose(); popover.dispose();
popover = undefined; popover = undefined;
} }
} }
function createPopoverHtml(feature) { function createPopoverHtml(feature) {
const container = document.createElement('div'); const container = document.createElement('div');
container.className = 'popover-content';
const title = document.createElement('div'); const title = document.createElement('div');
title.textContent = feature.get('name'); title.textContent = feature.get('name');
container.append(title); container.append(title);
return container.innerHTML;
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; // 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) { const feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
return feature; return feature;
}); });
disposePopover(); disposePopover();
if (!feature) { if (!feature) return;
return;
}
popup.setPosition(evt.coordinate); popup.setPosition(evt.coordinate);
popover = new bootstrap.Popover(popupEl, { popover = new bootstrap.Popover(popupEl, {
placement: 'top', placement: 'top',
@@ -192,61 +206,89 @@ map.on('click', function (evt) {
content: createPopoverHtml(feature) content: createPopoverHtml(feature)
}); });
popover.show(); popover.show();
}); });
// change mouse cursor when over marker // change mouse cursor when over marker
map.on('pointermove', function (evt) { map.on('pointermove', function (evt) {
map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel) map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel)
? 'pointer' ? 'pointer'
: ''; : '';
}); });
// Close the popup when the map is moved // Close the popup when the map is moved
map.on('movestart', disposePopover); map.on('movestart', disposePopover);
//
// Tracking
//
// const updateInterval = 10000;
// Tracking const peopleOverlays = {};
//
const updateInterval = 5000; function createParticipantHTML (name) {
let followedFeature = vanFeature; if (document.getElementById(`user-${name}`)) return;
// let followedFeature = null; 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; cursor: pointer';
document.getElementById('people').append(el);
}
function startFollowing(feature, followLink) { function createParticipantOverlay (name) {
followedFeature = feature; if (peopleOverlays[name]) return;
followLink.textContent = 'Stop following'; const overlayElement = new Overlay({
// followLink.removeEventListener('click', startFollowing); stopEvent: false,
followLink.addEventListener('click', stopFollowing(feature, followLink)); positioning: 'center-center',
} element: document.getElementById(`user-${name}`)
});
peopleOverlays[name] = overlayElement;
map.addOverlay(overlayElement);
}
function stopFollowing(feature, followLink) { function isRecentTimestamp (tst) {
followedFeature = null; // newer than 2 hours ago?
followLink.textContent = 'Stop following'; return (tst * 1000) > (Date.now() - 2*60*60*1000);
// 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') fetch('https://r2b22.kip.pe/last.json')
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
console.log(data); const vanData = data.find(i => i.name == 'satoshithevan');
const coords = [data.lon, data.lat]; const vanCoords = [vanData.lon, vanData.lat];
vanFeature.getGeometry().setCoordinates(coords); vanFeature.getGeometry().setCoordinates(vanCoords);
if (followedFeature) { for (const item of data) {
view.animate({ if (!tourStatus.participants.includes(item.name)) continue;
center: followedFeature.getGeometry().getCoordinates(), if (!isRecentTimestamp(item.tst)) continue;
duration: 500, createParticipantHTML(item.name);
zoom: 13 createParticipantOverlay(item.name);
const overlay = peopleOverlays[item.name];
overlay.setPosition([item.lon, item.lat]);
function clickHandler () {
disposePopover();
popup.setPosition([item.lon, item.lat]);
popover = new bootstrap.Popover(popupEl, {
placement: 'top',
html: true,
content: `Rider: ${item.name}`
}); });
popover.show();
}
const avatarEl = document.getElementById(`user-${item.name}`);
avatarEl.removeEventListener('click', clickHandler);
avatarEl.addEventListener('click', clickHandler);
} }
}); });
if (startInterval) { if (startInterval) {
setInterval(updateData, updateInterval); setInterval(updateData, updateInterval);
} }
}
updateData(true);
} }
updateData(true); main();
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "ol-vite", "name": "ol-vite",
"version": "1.1.0", "version": "1.10.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ol-vite", "name": "ol-vite",
"version": "1.1.0", "version": "1.10.1",
"dependencies": { "dependencies": {
"ol": "latest" "ol": "latest"
}, },
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "map", "name": "map",
"version": "1.1.0", "version": "1.10.1",
"scripts": { "scripts": {
"start": "vite", "start": "vite",
"build": "vite build", "build": "vite build",
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long
+26
View File
@@ -4,9 +4,35 @@ html, body {
margin: 0; margin: 0;
height: 100%; height: 100%;
} }
#map { #map {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
} }
img#logo {
position: absolute;
top: 10px;
right: 10px;
width: 256px;
height: auto;
}
lightning-widget {
display: block;
position: absolute;
bottom: 10px;
left: 10px;
width: 200px;
}
@media only screen and (max-width: 600px) {
lightning-widget {
display: block;
position: absolute;
right: 10px;
width: auto;
}
}