From bf72b68d8ac0c70cc5c1e0e9fb8feadd7ff29697 Mon Sep 17 00:00:00 2001 From: Pyro Nicampt <81565698+PyroNicampt@users.noreply.github.com> Date: Fri, 3 Jan 2025 18:39:29 -0600 Subject: [PATCH] Add Track Colorization --- config.js | 16 +++++++++++ index.html | 3 ++ index.js | 68 +++++++++++++++++++++++++++++++++++++------- js/utillib.js | 6 ++++ legend.js | 78 ++++++++++++++++++++++++++++++++++++++++----------- style.css | 15 +++++++++- 6 files changed, 158 insertions(+), 28 deletions(-) diff --git a/config.js b/config.js index f69936d..6e99844 100644 --- a/config.js +++ b/config.js @@ -1,4 +1,5 @@ 'use strict'; +import {Color} from './js/colorlib.js'; export const gradeColors = { grade_flat: '#fff', @@ -13,3 +14,18 @@ export const gradeColors = { grade_8: '#a3008d', grade_9: '#690097', } + +export const speedGradient = [ + new Color('#370065'), + new Color('#79146e'), + new Color('#d53354'), + new Color('#fa8256'), + new Color('#fbffb2'), +] + +export const altitudeGradient = [ + new Color('#340042'), + new Color('#235f7b'), + new Color('#51c34e'), + new Color('#fce51e'), +] \ No newline at end of file diff --git a/index.html b/index.html index 7183ddd..1e92fa6 100644 --- a/index.html +++ b/index.html @@ -239,6 +239,9 @@

Key


+
+ Track Colors: +

Map Settings

diff --git a/index.js b/index.js index 2852191..ccc5eff 100644 --- a/index.js +++ b/index.js @@ -288,6 +288,8 @@ function establishDimensions(){ x2: maxX, y1: minY, y2: maxY, + minAlt: minAlt, + maxAlt: maxAlt, width: width, height: height, fixY: yIn => { @@ -503,8 +505,11 @@ function sortTracks(){ } } -function setTrackColorMode(mode){ - let modeFunction = null; +export function setTrackColorMode(mode){ + let modeFunction; + const keyElement = document.getElementById('legendKeyColors'); + let gradientString = ''; + keyElement.innerHTML = ''; switch(mode){ case 'Track Type': modeFunction = (section, curve) => { @@ -515,30 +520,73 @@ function setTrackColorMode(mode){ else if(curve.isTurntable) finalColor = '#b4f'; section.element.setAttribute('stroke', finalColor); - } + }; + keyElement.innerHTML = ` + Designated Yard + Other Yard + Point + Turntable + Other Tracks`; break; case 'Grade': modeFunction = section => { section.element.setAttribute('stroke', Config.gradeColors['grade_'+section.gradeClass]); }; + for(let grade in Config.gradeColors){ + keyElement.innerHTML += `${(Utils.classToGrade(grade.replace('grade_',''))*100).toFixed(1)}%`; + } + break; + case 'Altitude': + modeFunction = section => { + section.element.setAttribute('stroke', Color.blendGradient(Config.altitudeGradient, (section.position.y-MapMatrix.minAlt)/(MapMatrix.maxAlt-MapMatrix.minAlt)).hex); + } + gradientString = 'linear-gradient(to right'; + for(let col of Config.altitudeGradient) gradientString += ', '+col.hex; + gradientString += ')'; + + keyElement.innerHTML = ` +
+
${Math.floor(MapMatrix.minAlt)}m
+
+
${Math.ceil(MapMatrix.maxAlt)}m
+
+ `; + break; + case 'Speed': + modeFunction = section => { + section.element.setAttribute('stroke', Color.blendGradient(Config.speedGradient, (section.postedSpeed+10)/110).hex); + }; + + gradientString = 'linear-gradient(to right'; + for(let col of Config.speedGradient) gradientString += ', '+col.hex; + gradientString += ')'; + keyElement.innerHTML = ` +
+
10 kmh
+
+
120 kmh
+
+ `; break; case 'Track Random': modeFunction = (section, curve) => { - section.element.setAttribute('stroke', curve.randomColor); - } + section.element.setAttribute('stroke', curve.randomColor.hex); + }; + keyElement.innerHTML = 'Random per continuous track section'; break; - case 'Section Random': + case 'Curve Random': modeFunction = section => { - section.element.setAttribute('stroke', section.randomColor); - } + section.element.setAttribute('stroke', section.randomColor.hex); + }; + keyElement.innerHTML = 'Random per individual track bezier curve'; break; default: modeFunction = section => { section.element.setAttribute('stroke', '#fff'); - } + }; break; } - if(modeFunction !== null){ + if(modeFunction != null){ for(let curve of mapData){ for(let section of curve.points){ if(!section.element) continue; diff --git a/js/utillib.js b/js/utillib.js index f74ac3e..04b0f4f 100644 --- a/js/utillib.js +++ b/js/utillib.js @@ -26,6 +26,12 @@ export function gradeToClass(grade){ return 'flat'; } +export function classToGrade(className){ + let classNum = Math.min(Math.max(Number(className), 0), gradeIncrements.length-1); + if(Number.isNaN(classNum)) return 0; + return gradeIncrements[gradeIncrements.length-1-classNum]; +} + /** * Outputs an easy to read time interval between `date1` and `date2` * @param {Date} date diff --git a/legend.js b/legend.js index 01e8e7e..5f1cb08 100644 --- a/legend.js +++ b/legend.js @@ -2,8 +2,27 @@ import * as Utils from './js/utillib.js'; import * as Config from './config.js'; +import { Color } from './js/colorlib.js'; +import { setTrackColorMode } from './index.js'; let settingEntries = [ + { + label: 'Color Mode', + id: 'dropdown_trackColor', + options: [ + 'None', + 'Grade', + 'Altitude', + 'Speed', + 'Track Type', + 'Track Random', + 'Curve Random', + ], + default: 'Grade', + func: state =>{ + setTrackColorMode(state); + } + }, { label: 'Signage', id: 'toggle_signage', @@ -56,15 +75,6 @@ let settingEntries = [ }, ] }, - { - label: 'Track Color', - id: 'radio_trackColor', - options: [ - 'None', - 'Grade', - ], - default: 1, - }, ]; const legendKey = document.getElementById('legendKey'); @@ -93,21 +103,15 @@ document.addEventListener('DOMContentLoaded', async () => { function addSettingEntry(thisSetting, parent, indent=0){ thisSetting.divContainer = document.createElement('div'); - thisSetting.inputElement = document.createElement('input'); - thisSetting.inputElement.style.margin = `0 0.5em 0 ${indent}em`; thisSetting.labelElement = document.createElement('label'); - parent.appendChild(thisSetting.divContainer); - thisSetting.divContainer.appendChild(thisSetting.inputElement); thisSetting.divContainer.appendChild(thisSetting.labelElement); - + let settingType = thisSetting.id.split('_')[0]; switch(settingType){ case 'toggle': + thisSetting.inputElement = document.createElement('input'); thisSetting.inputElement.type = 'checkbox'; - thisSetting.inputElement.id = thisSetting.id; thisSetting.inputElement.checked = thisSetting.state; - thisSetting.labelElement.innerHTML = thisSetting.label; - thisSetting.labelElement.htmlFor = thisSetting.id; if(thisSetting.func){ thisSetting.inputElement.addEventListener('input', e =>{ @@ -120,10 +124,50 @@ function addSettingEntry(thisSetting, parent, indent=0){ }); } break; + case 'dropdown': + thisSetting.inputElement = document.createElement('select'); + for(let inputEntry of thisSetting.options){ + let optionElement = document.createElement('option'); + if(typeof(inputEntry) == 'object'){ + optionElement.value = inputEntry[0]; + optionElement.innerHTML = inputEntry[1]; + }else{ + optionElement.value = inputEntry; + optionElement.innerHTML = inputEntry; + } + if(inputEntry == thisSetting.default) optionElement.selected = true; + thisSetting.inputElement.appendChild(optionElement); + } + if(thisSetting.func){ + thisSetting.inputElement.addEventListener('change', e =>{ + thisSetting.func(e.target.value); + }) + } + break; + case 'slider': + thisSetting.inputElement = document.createElement('input'); + thisSetting.inputElement.type = 'range'; + thisSetting.inputElement.min = thisSetting.min ?? 0; + thisSetting.inputElement.max = thisSetting.max ?? 100; + thisSetting.inputElement.step = thisSetting.step ?? 1; + if(thisSetting.func){ + thisSetting.inputElement.addEventListener('input', e => { + thisSetting.func(e.target.value); + }); + } + break; default: thisSetting.divContainer.remove(); return; } + parent.appendChild(thisSetting.divContainer); + thisSetting.labelElement.innerHTML = thisSetting.label; + thisSetting.labelElement.htmlFor = thisSetting.id; + thisSetting.inputElement.id = thisSetting.id; + + thisSetting.inputElement.style.margin = `0 0.5em 0 ${indent}em`; + thisSetting.divContainer.prepend(thisSetting.inputElement); + if(thisSetting.children){ for(let child of thisSetting.children){ addSettingEntry(child, parent, indent+1); diff --git a/style.css b/style.css index 8c0e54f..f6ca653 100644 --- a/style.css +++ b/style.css @@ -90,6 +90,10 @@ a:visited{ columns: 2; } +#legendKeyColors{ + overflow-wrap:break-word; +} + #legend{ transition: transform 400ms cubic-bezier(0.445, 0.050, 0.550, 0.950); display: flex; @@ -143,10 +147,19 @@ a:visited{ background: linear-gradient(#444, #333); } -.inlineSvg { +.colorKey, .gradientKey{ + border:1px #858585 solid; + border-radius: 4px; + display: inline-block; + margin: 2px 1px; + padding: 1px 3px; +} + +.inlineSvg, .colorKey>span{ width: 1em; height: 1em; vertical-align: -0.1em; + display: inline-block; } .poi{