diff --git a/website/src/lib/assets/colors.ts b/website/src/lib/assets/colors.ts index 3a4254d3..af17331f 100644 --- a/website/src/lib/assets/colors.ts +++ b/website/src/lib/assets/colors.ts @@ -25,40 +25,137 @@ export const surfaceColors: { [key: string]: string } = { "stone": "#ffd991", }; +export function getSurfaceColor(surface: string): string { + return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing; +} + export const highwayColors: { [key: string]: string } = { "missing": "#d1d1d1", - "residential": "#73b2ff", - "service": "#b3b3cc", - "track": "#946f43", - "unclassified": "#e0e0e0", - "footway": "#a3c989", - "tertiary": "#ffdd7f", - "path": "#a3c989", - "secondary": "#ffd75f", - "primary": "#ff6e5c", - "cycleway": "#ffbb6e", - "trunk": "#ff5e4d", - "living_street": "#9de2ff", "motorway": "#ff4d33", - "motorway_link": "#ff947f", - "steps": "#8d91a2", - "road": "#e0e0e0", - "pedestrian": "#c1c8e4", + "motorway_link": "#ff4d33", + "trunk": "#ff5e4d", "trunk_link": "#ff947f", - "primary_link": "#ff8d7b", - "secondary_link": "#ffcb66", - "tertiary_link": "#ffdd8b", + "primary": "#ff6e5c", + "primary_link": "#ff6e5c", + "secondary": "#ff8d7b", + "secondary_link": "#ff8d7b", + "tertiary": "#ffd75f", + "tertiary_link": "#ffd75f", + "unclassified": "#f1f2a5", + "road": "#f1f2a5", + "residential": "#73b2ff", + "living_street": "#73b2ff", + "service": "#9c9cd9", + "track": "#a8e381", + "footway": "#a8e381", + "path": "#a8e381", + "pedestrian": "#a8e381", + "cycleway": "#9de2ff", "construction": "#e09a4a", - "bridleway": "#a3c989", - "platform": "#c4c4c4", - "proposed": "#e0e0e0", + "bridleway": "#946f43", "raceway": "#ff0000", - "rest_area": "#73b2ff", - "abandoned": "#e0e0e0", - "services": "#ffe066", - "corridor": "#c4c4c4", - "bus_stop": "#ffe6e6", - "busway": "#ffe6e6", - "elevator": "#c4c4c4", - "via_ferrata": "#8d91a2" -}; + "rest_area": "#9c9cd9", + "services": "#9c9cd9", + "corridor": "#474747", + "elevator": "#474747", + "steps": "#474747", + "bus_stop": "#8545a3", + "busway": "#8545a3", + "via_ferrata": "#474747" +}; + +export const sacScaleColors: { [key: string]: string } = { + "hiking": "#007700", + "mountain_hiking": "#1843ad", + "demanding_mountain_hiking": "#ffff00", + "alpine_hiking": "#ff9233", + "demanding_alpine_hiking": "#ff0000", + "difficult_alpine_hiking": "#000000", +}; + +export const mtbScaleColors: { [key: string]: string } = { + "0-": "#007700", + "0": "#007700", + "0+": "#007700", + "1-": "#1843ad", + "1": "#1843ad", + "1+": "#1843ad", + "2-": "#ffff00", + "2": "#ffff00", + "2+": "#ffff00", + "3": "#ff0000", + "4": "#00ff00", + "5": "#000000", + "6": "#b105eb", +}; + +function createPattern(backgroundColor: string, sacScaleColor: string | undefined, mtbScaleColor: string | undefined, size: number = 16, lineWidth: number = 4) { + let canvas = document.createElement('canvas'); + canvas.width = size; + canvas.height = size; + let ctx = canvas.getContext('2d'); + if (ctx) { + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, size, size); + ctx.lineWidth = lineWidth; + + const halfSize = size / 2; + const halfLineWidth = lineWidth / 2; + if (sacScaleColor) { + ctx.strokeStyle = sacScaleColor; + ctx.beginPath(); + ctx.moveTo(halfSize - halfLineWidth, - halfLineWidth); + ctx.lineTo(size + halfLineWidth, halfSize + halfLineWidth); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(- halfLineWidth, halfSize - halfLineWidth); + ctx.lineTo(halfSize + halfLineWidth, size + halfLineWidth); + ctx.stroke(); + } + if (mtbScaleColor) { + ctx.strokeStyle = mtbScaleColor; + ctx.beginPath(); + ctx.moveTo(halfSize - halfLineWidth, size + halfLineWidth); + ctx.lineTo(size + halfLineWidth, halfSize - halfLineWidth); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(- halfLineWidth, halfSize + halfLineWidth); + ctx.lineTo(halfSize + halfLineWidth, - halfLineWidth); + ctx.stroke(); + } + } + return ctx?.createPattern(canvas, 'repeat') || backgroundColor; +} + +const patterns: Record = {}; +export function getHighwayColor(highway: string, sacScale: string | undefined, mtbScale: string | undefined) { + let backgroundColor = highwayColors[highway] ? highwayColors[highway] : highwayColors.missing; + let sacScaleColor = sacScale ? sacScaleColors[sacScale] : undefined; + let mtbScaleColor = mtbScale ? mtbScaleColors[mtbScale] : undefined; + if (sacScale || mtbScale) { + let patternId = `${backgroundColor}-${[sacScale, mtbScale].filter(x => x).join('-')}`; + if (!patterns[patternId]) { + patterns[patternId] = createPattern(backgroundColor, sacScaleColor, mtbScaleColor); + } + return patterns[patternId]; + } + return backgroundColor; +} + +const maxSlope = 20; +export function getSlopeColor(slope: number): string { + if (slope > maxSlope) { + slope = maxSlope; + } else if (slope < -maxSlope) { + slope = -maxSlope; + } + + let v = slope / maxSlope; + v = 1 / (1 + Math.exp(-6 * v)); + v = v - 0.5; + + let hue = ((0.5 - v) * 120).toString(10); + let lightness = 90 - Math.abs(v) * 70; + + return `hsl(${hue},70%,${lightness}%)`; +} \ No newline at end of file diff --git a/website/src/lib/components/ElevationProfile.svelte b/website/src/lib/components/ElevationProfile.svelte index d0b04966..6e444253 100644 --- a/website/src/lib/components/ElevationProfile.svelte +++ b/website/src/lib/components/ElevationProfile.svelte @@ -19,7 +19,7 @@ ChartNoAxesColumn, Construction } from 'lucide-svelte'; - import { surfaceColors, highwayColors } from '$lib/assets/colors'; + import { getSlopeColor, getSurfaceColor, getHighwayColor } from '$lib/assets/colors'; import { _, locale } from 'svelte-i18n'; import { getCadenceWithUnits, @@ -443,33 +443,20 @@ chart.update(); } - let maxSlope = 20; function slopeFillCallback(context) { - let slope = context.p0.raw.slope.segment; - if (slope > maxSlope) { - slope = maxSlope; - } else if (slope < -maxSlope) { - slope = -maxSlope; - } - - let v = slope / maxSlope; - v = 1 / (1 + Math.exp(-6 * v)); - v = v - 0.5; - - let hue = ((0.5 - v) * 120).toString(10); - let lightness = 90 - Math.abs(v) * 70; - - return ['hsl(', hue, ',70%,', lightness, '%)'].join(''); + return getSlopeColor(context.p0.raw.slope.segment); } function surfaceFillCallback(context) { - let surface = context.p0.raw.extensions.surface; - return surfaceColors[surface] ? surfaceColors[surface] : surfaceColors.missing; + return getSurfaceColor(context.p0.raw.extensions.surface); } function highwayFillCallback(context) { - let highway = context.p0.raw.extensions.highway; - return highwayColors[highway] ? highwayColors[highway] : highwayColors.missing; + return getHighwayColor( + context.p0.raw.extensions.highway, + context.p0.raw.extensions.sac_scale, + context.p0.raw.extensions['mtb:scale'] + ); } $: if (chart) {