strava heatmap layers (nakarte proxy)

This commit is contained in:
vcoppe
2024-06-06 18:11:03 +02:00
parent 41d5fa4efc
commit 16bdf9fdbe
6 changed files with 238 additions and 6 deletions

View File

@@ -386,6 +386,62 @@ export const overlays: { [key: string]: AnySourceData; } = {
maxzoom: 18,
attribution: '&copy; <a href="https://www.waymarkedtrails.org" target="_blank">Waymarked Trails</a>'
},
stravaHeatmapRun: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapTrailRun: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapHike: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapRide: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapGravel: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapMTB: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapWater: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
stravaHeatmapWinter: {
type: 'raster',
tiles: [],
tileSize: 1024,
maxzoom: 15,
attribution: '&copy; <a href="https://www.strava.com" target="_blank">Strava</a>'
},
};
export const opacities: { [key: string]: number; } = {
@@ -452,6 +508,16 @@ export const overlayTree: LayerTreeType = {
cyclOSM: {
cyclOSMlite: true,
},
strava: {
stravaHeatmapRun: true,
stravaHeatmapTrailRun: true,
stravaHeatmapHike: true,
stravaHeatmapRide: true,
stravaHeatmapGravel: true,
stravaHeatmapMTB: true,
stravaHeatmapWater: true,
stravaHeatmapWinter: true,
},
waymarked_trails: {
waymarkedTrailsHiking: true,
waymarkedTrailsCycling: true,
@@ -487,6 +553,16 @@ export const defaultOverlays = {
cyclOSM: {
cyclOSMlite: false,
},
strava: {
stravaHeatmapRun: false,
stravaHeatmapTrailRun: false,
stravaHeatmapHike: false,
stravaHeatmapRide: false,
stravaHeatmapGravel: false,
stravaHeatmapMTB: false,
stravaHeatmapWater: false,
stravaHeatmapWinter: false,
},
waymarked_trails: {
waymarkedTrailsHiking: false,
waymarkedTrailsCycling: false,
@@ -568,6 +644,16 @@ export const defaultOverlayTree: LayerTreeType = {
cyclOSM: {
cyclOSMlite: true,
},
strava: {
stravaHeatmapRun: true,
stravaHeatmapTrailRun: true,
stravaHeatmapHike: true,
stravaHeatmapRide: true,
stravaHeatmapGravel: true,
stravaHeatmapMTB: true,
stravaHeatmapWater: true,
stravaHeatmapWinter: true,
},
waymarked_trails: {
waymarkedTrailsHiking: true,
waymarkedTrailsCycling: true,
@@ -591,4 +677,16 @@ export const defaultOverlayTree: LayerTreeType = {
}
},
}
}
export const stravaHeatmapServers = ['https://proxy.nakarte.me/https/heatmap-external-a.strava.com/tiles-auth']; //['https://heatmap-external-a.strava.com/tiles-auth', 'https://heatmap-external-b.strava.com/tiles-auth', 'https://heatmap-external-c.strava.com/tiles-auth'];
export const stravaHeatmapActivityIds: { [key: string]: string } = {
stravaHeatmapRun: 'sport_Run',
stravaHeatmapTrailRun: 'sport_TrailRun',
stravaHeatmapHike: 'sport_Hike',
stravaHeatmapRide: 'sport_Ride',
stravaHeatmapGravel: 'sport_GravelRide',
stravaHeatmapMTB: 'sport_MountainBikeRide',
stravaHeatmapWater: 'water',
stravaHeatmapWinter: 'winter',
}

View File

@@ -5,15 +5,75 @@
import { ScrollArea } from '$lib/components/ui/scroll-area/index.js';
import * as Sheet from '$lib/components/ui/sheet';
import * as Accordion from '$lib/components/ui/accordion';
import { Label } from '$lib/components/ui/label';
import * as Select from '$lib/components/ui/select';
import { basemapTree, overlayTree } from '$lib/assets/layers';
import { settings } from '$lib/db';
import { _ } from 'svelte-i18n';
import { writable, get } from 'svelte/store';
import { map, setStravaHeatmapURLs } from '$lib/stores';
const { selectedBasemapTree, selectedOverlayTree } = settings;
const { selectedBasemapTree, selectedOverlayTree, stravaHeatmapColor, currentOverlays } =
settings;
export let open: boolean;
const heatmapColors = [
{ value: '', label: '' },
{ value: 'blue', label: $_('layers.color.blue') },
{ value: 'bluered', label: $_('layers.color.bluered') },
{ value: 'gray', label: $_('layers.color.gray') },
{ value: 'hot', label: $_('layers.color.hot') },
{ value: 'orange', label: $_('layers.color.orange') },
{ value: 'purple', label: $_('layers.color.purple') }
];
let selectedHeatmapColor = writable(heatmapColors[0]);
$: if ($selectedHeatmapColor !== heatmapColors[0]) {
stravaHeatmapColor.set($selectedHeatmapColor.value);
// remove and add the heatmap layers
let m = get(map);
if (m) {
let currentStravaLayers = [];
for (let layer of Object.keys(overlayTree.overlays.world.strava)) {
if (m.getLayer(layer)) {
m.removeLayer(layer);
currentStravaLayers.push(layer);
}
if (m.getSource(layer)) {
m.removeSource(layer);
}
}
if (currentStravaLayers.length > 0) {
currentOverlays.update(($currentOverlays) => {
for (let layer of currentStravaLayers) {
$currentOverlays.overlays.world.strava[layer] = false;
}
return $currentOverlays;
});
currentOverlays.update(($currentOverlays) => {
for (let layer of currentStravaLayers) {
$currentOverlays.overlays.world.strava[layer] = true;
}
return $currentOverlays;
});
}
}
}
$: if ($stravaHeatmapColor) {
setStravaHeatmapURLs();
if ($stravaHeatmapColor !== get(selectedHeatmapColor).value) {
let toSelect = heatmapColors.find(({ value }) => value === $stravaHeatmapColor);
if (toSelect) {
selectedHeatmapColor.set(toSelect);
}
}
}
</script>
<Sheet.Root bind:open>
@@ -55,7 +115,21 @@
</Accordion.Item>
<Accordion.Item value="item-3">
<Accordion.Trigger>{$_('layers.heatmap')}</Accordion.Trigger>
<Accordion.Content></Accordion.Content>
<Accordion.Content>
<div class="flex flex-row items-center justify-between gap-4">
<Label>{$_('menu.color')}</Label>
<Select.Root bind:selected={$selectedHeatmapColor} class="grow">
<Select.Trigger class="w-full">
<Select.Value placeholder="Theme" />
</Select.Trigger>
<Select.Content>
{#each heatmapColors as { value, label }}
<Select.Item {value}>{label}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
</div>
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-4">
<Accordion.Trigger>{$_('layers.pois')}</Accordion.Trigger>

View File

@@ -16,7 +16,7 @@ export function anySelectedLayer(node: LayerTreeType) {
}
export function getLayers(node: LayerTreeType, layers: { [key: string]: boolean } = {}): { [key: string]: boolean } {
Object.keys(node).find((id) => {
Object.keys(node).forEach((id) => {
if (typeof node[id] == "boolean") {
layers[id] = node[id];
} else {

View File

@@ -97,6 +97,7 @@ export const settings = {
selectedOverlayTree: dexieSettingStore('selectedOverlayTree', defaultOverlayTree),
directionMarkers: dexieSettingStore('directionMarkers', false),
distanceMarkers: dexieSettingStore('distanceMarkers', false),
stravaHeatmapColor: dexieSettingStore('stravaHeatmapColor', 'bluered'),
fileOrder: dexieSettingStore<string[]>('fileOrder', []),
};

View File

@@ -5,10 +5,11 @@ import { GPXFile, buildGPX, parseGPX, GPXStatistics, type Coordinates } from 'gp
import { tick } from 'svelte';
import { _ } from 'svelte-i18n';
import type { GPXLayer } from '$lib/components/gpx-layer/GPXLayer';
import { dbUtils, fileObservers } from './db';
import { dbUtils, fileObservers, settings } from './db';
import { applyToOrderedSelectedItemsFromFile, selectFile, selection } from '$lib/components/file-list/Selection';
import { ListFileItem, ListWaypointItem, ListWaypointsItem } from '$lib/components/file-list/FileList';
import type { RoutingControls } from '$lib/components/toolbar/tools/routing/RoutingControls';
import { overlayTree, overlays, stravaHeatmapActivityIds, stravaHeatmapServers } from '$lib/assets/layers';
export const map = writable<mapboxgl.Map | null>(null);
export const selectFiles = writable<{ [key: string]: (fileId?: string) => void }>({});
@@ -237,4 +238,44 @@ export function exportFile(file: GPXFile) {
a.download = file.metadata.name + '.gpx';
a.click();
URL.revokeObjectURL(url);
}
let stravaCookies: any = null;
function refreshStravaCookies() {
if (stravaCookies === null) {
return fetch('https://s.gpx.studio')
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Failed to fetch Strava cookies');
}
})
.then(data => {
stravaCookies = data;
console.log('Strava cookies:', stravaCookies);
});
} else {
return Promise.resolve();
}
}
export function setStravaHeatmapURLs() {
refreshStravaCookies().then(() => {
overlays.stravaHeatmapRun.tiles = [];
overlays.stravaHeatmapTrailRun.tiles = [];
overlays.stravaHeatmapHike.tiles = [];
overlays.stravaHeatmapRide.tiles = [];
overlays.stravaHeatmapGravel.tiles = [];
overlays.stravaHeatmapMTB.tiles = [];
overlays.stravaHeatmapWater.tiles = [];
overlays.stravaHeatmapWinter.tiles = [];
for (let activity of Object.keys(overlayTree.overlays.world.strava)) {
overlays[activity].tiles = [];
for (let server of stravaHeatmapServers) {
overlays[activity].tiles.push(`${server}/${stravaHeatmapActivityIds[activity]}/${get(settings.stravaHeatmapColor)}/{z}/{x}/{y}@2x.png?Signature=${stravaCookies['CloudFront-Signature']}&Key-Pair-Id=${stravaCookies['CloudFront-Key-Pair-Id']}&Policy=${stravaCookies['CloudFront-Policy']}`);
}
}
});
}

View File

@@ -38,7 +38,8 @@
"donate": "Donate",
"ctrl": "Ctrl",
"click": "Click",
"drag": "Drag"
"drag": "Drag",
"color": "Color"
},
"toolbar": {
"routing": {
@@ -116,7 +117,7 @@
"settings_help": "Select the map layers you want to show in the interface, add custom ones, and adjust their settings.",
"selection": "Layer selection",
"custom_layers": "Custom layers",
"heatmap": "Heatmap",
"heatmap": "Strava Heatmap",
"pois": "Points of interest",
"label": {
"basemaps": "Basemaps",
@@ -160,6 +161,15 @@
"ignFrCadastre": "IGN Cadastre",
"ignSlope": "IGN Slope",
"ignSkiTouring": "IGN Ski Touring",
"strava": "Strava",
"stravaHeatmapRun": "Running",
"stravaHeatmapTrailRun": "Trail Running",
"stravaHeatmapHike": "Hiking",
"stravaHeatmapRide": "Cycling",
"stravaHeatmapGravel": "Gravel Cycling",
"stravaHeatmapMTB": "MTB",
"stravaHeatmapWater": "Water",
"stravaHeatmapWinter": "Winter",
"waymarked_trails": "Waymarked Trails",
"waymarkedTrailsHiking": "Hiking",
"waymarkedTrailsCycling": "Cycling",
@@ -167,6 +177,14 @@
"waymarkedTrailsSkating": "Skating",
"waymarkedTrailsHorseRiding": "Horse Riding",
"waymarkedTrailsWinter": "Winter"
},
"color": {
"blue": "Blue",
"bluered": "Blue Red",
"gray": "Gray",
"hot": "Hot",
"purple": "Purple",
"orange": "Orange"
}
},
"chart": {