From 62a1072a659bfc18495ff8cfc88f64df143aed72 Mon Sep 17 00:00:00 2001 From: Pyro Nicampt <81565698+PyroNicampt@users.noreply.github.com> Date: Sat, 28 Dec 2024 22:01:42 -0600 Subject: [PATCH] Implement main Points of Interest system --- index.html | 99 ++++++++++++--------- index.js | 251 ++++++++++++++++++++++++++++++++++++++++++++-------- legend.js | 41 +++++---- poi_dv.json | 48 +++++----- style.css | 9 ++ 5 files changed, 332 insertions(+), 116 deletions(-) diff --git a/index.html b/index.html index f8415b6..b65dcc0 100644 --- a/index.html +++ b/index.html @@ -18,10 +18,10 @@
- + - + - + - + 1 - + 2 - + 3 - + 4 - + 5 - + 6 - + 7 - + 8 - + 9 - + 10 - + 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -196,13 +215,13 @@
-
+
Welcome to the WIP community map of Derail Valley, a resource for documenting and displaying all tracks and points of interest.
Hover over tracks and objects for detailed information.
-
+

Key


diff --git a/index.js b/index.js index 20a1e35..e64c00e 100644 --- a/index.js +++ b/index.js @@ -58,6 +58,14 @@ map.appendChild(map_rails); //map_markers.setAttribute('id', 'map_markers'); //map.appendChild(map_markers); const map_markers = document.getElementById('mapMarkers'); +const poiLayers = { + container: document.createElementNS(svgns, 'g'), + + stations: document.createElementNS(svgns, 'g'), + service: document.createElementNS(svgns, 'g'), + features: document.createElementNS(svgns, 'g'), + landmarks: document.createElementNS(svgns, 'g') +}; let mapData = []; let trackNameCounting = {}; @@ -68,8 +76,17 @@ let markers = []; let currentMapNav = {}; let previousMapScale = -1; +let MapMatrix = {}; + document.addEventListener('DOMContentLoaded', async () => { + let dynamicStyles = []; + for(let i=0; i= scaleCullThresholds[i].scale ? 'initial' : 'none') + styleRoot.style.setProperty(`--minZoomCull_state_${i}`, navData.scale >= scaleCullThresholds[i].scale ? 'initial' : 'none'); + styleRoot.style.setProperty(`--maxZoomCull_state_${i}`, navData.scale <= scaleCullThresholds[i].scale ? 'initial' : 'none'); } } previousMapScale = navData.scale; @@ -182,6 +215,17 @@ function establishDimensions(){ } let width = maxX-minX; let height = maxY-minY; + MapMatrix = { + x1: minX, + x2: maxX, + y1: minY, + y2: maxY, + width: width, + height: height, + fixY: yIn => { + return minY+maxY-yIn; + } + } map.setAttribute('viewBox', `${minX-padding} ${minY-padding} ${width+2*padding} ${height+2*padding}`); map_markers.setAttribute('viewBox', map.getAttribute('viewBox')); updateMapview({ @@ -211,7 +255,7 @@ function fillSvg(){ } } sortTracks(); - setTrackColorMode(); + setTrackColorMode('Grade'); drawMarkers(); } @@ -241,11 +285,11 @@ function drawTracks(bezierData){ bezierData.isPoint = true; } for(let i=0; i+1 { + let finalColor = '#aaa'; + if(curve.isYard && curve.yardDesignation) finalColor = '#4bf'; + else if(curve.isYard) finalColor = '#4fb'; + else if(curve.isPoint) finalColor = '#fb4'; + else if(curve.isTurntable) finalColor = '#b4f'; + + section.element.setAttribute('stroke', finalColor); + } + break; + case 'Grade': modeFunction = section => { - if(!section.element) return; section.element.setAttribute('stroke', Config.gradeColors['grade_'+section.gradeClass]); }; break; + default: + modeFunction = section => { + section.element.setAttribute('stroke', '#fff'); + } + break; } if(modeFunction !== null){ for(let curve of mapData){ for(let section of curve.points){ - modeFunction(section); + if(!section.element) continue; + modeFunction(section, curve); } } } @@ -396,43 +455,157 @@ function setTrackColorMode(mode){ /** Create the signage */ function drawMarkers(){ + const signage_container = document.createElementNS(svgns, 'g'); const gradeSigns = document.createElementNS(svgns, 'g'); - gradeSigns.setAttribute('id', 'grade_signs'); - map_markers.appendChild(gradeSigns); const speedSigns = document.createElementNS(svgns, 'g'); - speedSigns.setAttribute('id', 'speed_signs'); - map_markers.appendChild(speedSigns); + + signage_container.setAttribute('id', 'signage_container'); + gradeSigns.setAttribute('id', 'signage_grade'); + speedSigns.setAttribute('id', 'signage_speed'); + + map_markers.appendChild(signage_container); + signage_container.appendChild(gradeSigns); + signage_container.appendChild(speedSigns); + for(const markerData of markers){ //if(markerData.skip) continue; - let marker = document.createElementNS(svgns, 'g'); + let markerElement = document.createElementNS(svgns, 'g'); let markerImg = document.createElementNS(svgns, 'use'); - let title = document.createElementNS(svgns, 'title'); - marker.appendChild(markerImg); - marker.appendChild(title); - marker.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z})`); + let markerTooltip = document.createElementNS(svgns, 'title'); + markerElement.appendChild(markerImg); + markerElement.appendChild(markerTooltip); + markerElement.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z})`); + markerImg.classList.add('fixedScale'); // Grade signs if(markerData.type == 'grade'){ markerImg.setAttribute('href', '#gradeArrow'); - markerImg.classList.add('sign', 'gradeSign'); - markerImg.setAttribute('fill', Config.gradeColors['grade_'+markerData.gradeClass]) + markerImg.setAttribute('fill', Config.gradeColors['grade_'+markerData.gradeClass]); const tanLen = Math.sqrt(markerData.tangent.x*markerData.tangent.x + markerData.tangent.z*markerData.tangent.z) * Math.sign(markerData.tangent.y); const rot = Math.atan2(markerData.tangent.x/tanLen, -markerData.tangent.z/tanLen) * (180/Math.PI); - marker.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z}) rotate(${rot})`); - title.innerHTML = `${Math.round(markerData.value*1000)/10}% Grade\nSection Length: ${markerData.sectionLength.toFixed(1)} meters`; - gradeSigns.appendChild(marker); + markerElement.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z}) rotate(${rot})`); + markerTooltip.innerHTML = `${Math.round(markerData.value*1000)/10}% Grade\nSection Length: ${markerData.sectionLength.toFixed(1)} meters`; + gradeSigns.appendChild(markerElement); // Speed Signs }else if(markerData.type == 'speed'){ markerImg.setAttribute('href', `#speedSign_${Math.round(markerData.value/10)}`); - markerImg.classList.add('sign', 'speedSign'); - title.innerHTML = `${Math.round(markerData.value)} km/h\nSection Length: ${markerData.sectionLength.toFixed(1)} meters`; - /*let offset = Vector.normalize({x:markerData.tangent.z, y:0, z:-markerData.tangent.x}); - marker.setAttribute('transform', `translate(${markerData.position.x + offset.x*100} ${markerData.position.z + offset.z*50})`);*/ - marker.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z})`); - speedSigns.appendChild(marker); + markerTooltip.innerHTML = `${Math.round(markerData.value)} km/h\nSection Length: ${markerData.sectionLength.toFixed(1)} meters`; + markerElement.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z})`); + speedSigns.appendChild(markerElement); } if(markerData.cullLevel){ - marker.classList.add(`cullThreshold_${Math.min(scaleCullThresholds.length-1, markerData.cullLevel)}`); + markerElement.classList.add(`minZoomCull_${Math.min(scaleCullThresholds.length-1, markerData.cullLevel)}`); + } + } +} + +function addPoi(poi, level = 0){ + let poiElement = document.createElementNS(svgns, 'g'); + let poiDisplay = document.createElementNS(svgns, 'g'); + let poiIcon = document.createElementNS(svgns, poi.type == 'station' ? 'text' : 'use'); + let poiTooltip = document.createElementNS(svgns, 'title'); + poiElement.appendChild(poiDisplay); + poiDisplay.appendChild(poiIcon); + poiElement.appendChild(poiTooltip); + poiElement.setAttribute('transform', `translate(${poi.position.x} ${MapMatrix.fixY(poi.position.z)})`); + poiElement.classList.add('poi'); + poiDisplay.classList.add('fixedScale'); + if(level > 0) poiElement.classList.add('minZoomCull_2'); + switch(poi.type){ + case 'station': + poiDisplay.classList.remove('fixedScale'); + poiElement.setAttribute('fill', poi.color ?? '#fff'); + poiTooltip.innerHTML = poi.name; + poiIcon.innerHTML = poi.shorthand; + poiIcon.setAttribute('style', `font-size:400px; stroke:${poi.stroke ?? '#000'}; stroke-width:40px; paint-order:stroke; text-anchor:middle;`); + poiLayers.stations.prepend(poiElement); + break; + case 'office': + poiIcon.setAttribute('href', '#mrk_office'); + if(poi.military){ + poiDisplay.setAttribute('fill', '#978e47'); + poiTooltip.innerHTML = 'Military Office'; + }else if(poi.museum){ + poiDisplay.setAttribute('fill', '#b44'); + poiTooltip.innerHTML = 'Museum Office'; + }else{ + poiDisplay.setAttribute('fill', '#c4693e'); + poiTooltip.innerHTML = 'Station Office'; + } + poiLayers.service.prepend(poiElement); + break; + case 'coal': + poiIcon.setAttribute('href', '#mrk_coal'); + poiDisplay.setAttribute('fill', '#202020'); + poiTooltip.innerHTML = 'Coal Tower'; + poiLayers.service.prepend(poiElement); + break; + case 'water': + poiIcon.setAttribute('href', '#mrk_water'); + poiDisplay.setAttribute('fill', '#3fa5ff'); + poiTooltip.innerHTML = 'Water Tower'; + poiLayers.service.prepend(poiElement); + break; + case 'garage': + poiIcon.setAttribute('href', '#mrk_garage'); + poiDisplay.setAttribute('fill', '#8b5dd7'); + poiTooltip.innerHTML = poi.name ?? 'Unknown Garage'; + poiLayers.service.prepend(poiElement); + poiElement.classList.add('minZoomCull_1'); + break; + case 'landmark': + poiIcon.setAttribute('href', '#mrk_landmark'); + poiDisplay.setAttribute('fill', '#af5757'); + poiTooltip.innerHTML = poi.name ?? 'Unknown Landmark'; + poiLayers.service.prepend(poiElement); + poiElement.classList.add('minZoomCull_1'); + break; + case 'shop': + poiIcon.setAttribute('href', '#mrk_shop'); + poiDisplay.setAttribute('fill', '#4f54e9'); + poiTooltip.innerHTML = 'Shop'; + poiLayers.service.prepend(poiElement); + poiElement.classList.add('minZoomCull_1'); + break; + case 'service': + let serviceTypes = []; + if(poi.repair) serviceTypes.push('Repair'); + if(poi.diesel) serviceTypes.push('Diesel'); + if(poi.charger) serviceTypes.push('Charger'); + + if(serviceTypes.length == 0){ + poiIcon.setAttribute('href', '#mrk_service'); + poiDisplay.setAttribute('fill', '#239a96'); + poiTooltip.innerHTML = 'Unknown Service'; + }else{ + poiIcon.setAttribute('href', '#mrk_service_'+serviceTypes[0].toLowerCase()); + poiDisplay.setAttribute('fill', '#239a96'); + let bumpOffset = -200*(serviceTypes.length-1); + poiIcon.setAttribute('transform', `translate(${bumpOffset} 0)`); + poiTooltip.innerHTML = serviceTypes[0]; + for(let i=1; i 1){ + let bgrect = document.createElementNS(svgns, 'rect'); + bgrect.setAttribute('width', 400*(serviceTypes.length-1)); + bgrect.setAttribute('height', 400); + bgrect.setAttribute('transform', `translate(${-200*(serviceTypes.length-1)} -200)`); + poiDisplay.prepend(bgrect); + } + } + poiLayers.service.prepend(poiElement); + break; + } + if(poi.children){ + for(let child of poi.children){ + addPoi(child, level+1); } } } \ No newline at end of file diff --git a/legend.js b/legend.js index d107a6f..fd43b4a 100644 --- a/legend.js +++ b/legend.js @@ -9,7 +9,7 @@ let settingEntries = [ id: 'toggle_signage', state: true, func: state =>{ - document.getElementById('mapMarkers').style.display = state ? 'unset' : 'none'; + document.getElementById('signage_container').style.display = state ? 'unset' : 'none'; }, children: [ { @@ -17,7 +17,7 @@ let settingEntries = [ id: 'toggle_speedSigns', state: true, func: state =>{ - document.getElementById('speed_signs').style.display = state ? 'unset' : 'none'; + document.getElementById('signage_speed').style.display = state ? 'unset' : 'none'; }, }, { @@ -25,7 +25,7 @@ let settingEntries = [ id: 'toggle_gradeSigns', state: true, func: state =>{ - document.getElementById('grade_signs').style.display = state ? 'unset' : 'none'; + document.getElementById('signage_grade').style.display = state ? 'unset' : 'none'; }, } ], @@ -117,27 +117,34 @@ function populateKey(){ }else if(i >= 0){ gradeValue += ` - ${getGradeValue(i+1)}%`; } - let gradeIcon = document.createElement('svg'); - gradeIcon.classList.add('inlineSvg'); - gradeIcon.setAttribute('viewBox', '-50 -50 100 100'); - gradeIcon.innerHTML = ``; - addKeyEntry(gradeIcon, ` ${gradeValue} Grade`); + addKeyEntry(``, ` ${gradeValue} Grade`); } - let speedSignIcon = document.createElement('svg'); - speedSignIcon.classList.add('inlineSvg'); - speedSignIcon.setAttribute('viewBox', '-50 -50 100 100'); - speedSignIcon.innerHTML = ``; - addKeyEntry(speedSignIcon, ' Speed Limit'); + addKeyEntry('', ' Speed Limit'); + addKeyEntry('', ' Station Office'); + addKeyEntry('', ' Shop'); + addKeyEntry('', ' Coal Tower'); + addKeyEntry('', ' Water Tower'); + addKeyEntry('', ' Landmark'); + addKeyEntry('', ' Garage'); + addKeyEntry('', ' Repair Service'); + addKeyEntry('', ' Diesel Refuel'); + addKeyEntry('', ' Electric Charger'); } /** * Add an entry to the map key. - * @param {Element} keyImage - * @param {string} keyLabel + * @param {string} keyImageHTML + * @param {string} keyLabel */ -function addKeyEntry(keyImage, keyLabel){ +function addKeyEntry(keyImageHTML, keyLabel){ let keyDiv = document.createElement('div'); - if(keyImage) keyDiv.appendChild(keyImage); + if(keyImageHTML){ + let keyImage = document.createElement('svg'); + keyImage.innerHTML = keyImageHTML; + keyImage.classList.add('inlineSvg'); + keyImage.setAttribute('viewBox', '-150 -150 300 300'); + keyDiv.appendChild(keyImage); + } keyDiv.innerHTML += keyLabel; legendKey.appendChild(keyDiv); } \ No newline at end of file diff --git a/poi_dv.json b/poi_dv.json index 8fbaa92..79cc817 100644 --- a/poi_dv.json +++ b/poi_dv.json @@ -4,7 +4,7 @@ "type":"station", "shorthand":"CME", "color":"#958177", - "position":{"x":15622.98,"y":204.2502,"z":11220.5}, + "position":{"x":15622.98,"y":204.2502,"z":10620.5}, "children":[ { "type":"office", @@ -31,7 +31,7 @@ "type":"station", "shorthand":"CMS", "color":"#6f6a58", - "position":{"x":8531.313,"y":156.2595,"z":3448.419}, + "position":{"x":9251.313,"y":156.2595,"z":3408.419}, "children":[ { "type":"office", @@ -53,7 +53,7 @@ "type":"station", "shorthand":"CP", "color":"#824e4a", - "position":{"x":2064.521,"y":145.1,"z":9031.848}, + "position":{"x":2064.521,"y":145.1,"z":8231.848}, "children":[ { "type":"office", @@ -74,7 +74,7 @@ "type":"station", "shorthand":"CS", "color":"#dfd7dc", - "position":{"x":9985.819,"y":134.6823,"z":1388.548}, + "position":{"x":9785.819,"y":134.6823,"z":1488.548}, "children":[ { "type":"office", @@ -100,6 +100,10 @@ "type":"water", "position":{"x":10249.08,"y":134.7365,"z":1468.002} }, + { + "type":"water", + "position":{"x":10050.59,"y":134.7859,"z":1370.713} + }, { "name":"Olaf's Garage", "type":"garage", @@ -112,7 +116,7 @@ "type":"station", "shorthand":"CW", "color":"#f1cdbb", - "position": {"x":1956,"y":122,"z":5692}, + "position": {"x":1456,"y":122,"z":5692}, "children":[ { "type":"office", @@ -141,7 +145,7 @@ "type":"station", "shorthand":"FF", "color":"#b2d1ff", - "position":{"x":9435.343,"y":119.1784,"z":13504.95}, + "position":{"x":9035.343,"y":119.1784,"z":13504.95}, "children":[ { "type":"office", @@ -169,7 +173,7 @@ "type":"station", "shorthand":"FM", "color":"#ffda62", - "position":{"x":6027.609,"y":123.8593,"z":6704.711}, + "position":{"x":6027.609,"y":123.8593,"z":7074.711}, "children":[ { "type":"office", @@ -186,7 +190,7 @@ "type":"station", "shorthand":"FRC", "color":"#d3e075", - "position":{"x":5727.74,"y":144.9063,"z":8757.236}, + "position":{"x":6427.74,"y":144.9063,"z":8757.236}, "children":[ { "type":"office", @@ -203,7 +207,7 @@ "type":"station", "shorthand":"FRS", "color":"#8db16c", - "position":{"x":5340.794,"y":175.1235,"z":3787.574}, + "position":{"x":5890.794,"y":175.1235,"z":3787.574}, "children":[ { "type":"office", @@ -221,7 +225,7 @@ "type":"station", "shorthand":"GF", "color":"#ff9db9", - "position":{"x":13002.78,"y":140.2193,"z":10995.55}, + "position":{"x":13202.78,"y":140.2193,"z":10495.55}, "children":[ { "type":"office", @@ -254,7 +258,7 @@ "type":"station", "shorthand":"HB", "color":"#ff9db9", - "position":{"x":13066.07,"y":113.082,"z":3596.37}, + "position":{"x":13066.07,"y":113.082,"z":3876.37}, "children":[ { "type":"office", @@ -292,7 +296,7 @@ "type":"station", "shorthand":"IME", "color":"#ff836f", - "position":{"x":15041.38,"y":248.062,"z":15341.35}, + "position":{"x":15041.38,"y":248.062,"z":15741.35}, "children":[ { "type":"office", @@ -319,7 +323,7 @@ "type":"station", "shorthand":"IMW", "color":"#dc6f54", - "position":{"x":2103.091,"y":133.5531,"z":13359.38}, + "position":{"x":2163.091,"y":133.5531,"z":13759.38}, "children":[ { "type":"office", @@ -345,7 +349,7 @@ "type":"station", "shorthand":"MB", "color":"#d6ac71", - "position":{"x":12524,"y":215.3452,"z":14749.98}, + "position":{"x":12524,"y":215.3452,"z":14349.98}, "children":[ { "type":"office", @@ -364,7 +368,7 @@ "type":"station", "shorthand":"MF", "color":"#ffad6d", - "position":{"x":2348.254,"y":159.2693,"z":10823.74}, + "position":{"x":2848.254,"y":159.2693,"z":10523.74}, "children":[ { "type":"office", @@ -401,7 +405,7 @@ "type":"station", "shorthand":"OR", "color":"#cf6884", - "position":{"x":6404.917,"y":143.8076,"z":11133.96}, + "position":{"x":6934.917,"y":143.8076,"z":11133.96}, "children":[ { "type":"office", @@ -423,7 +427,7 @@ "type":"station", "shorthand":"OWC", "color":"#7b6f6e", - "position":{"x":4866.821,"y":122.9323,"z":6291.179}, + "position":{"x":4466.821,"y":122.9323,"z":6651.179}, "children":[ { "type":"office", @@ -446,7 +450,7 @@ "type":"station", "shorthand":"OWN", "color":"#8b715e", - "position":{"x":11570.04,"y":122.3343,"z":11554.65}, + "position":{"x":11570.04,"y":122.3343,"z":11954.65}, "children":[ { "type":"office", @@ -465,7 +469,7 @@ "type":"station", "shorthand":"SM", "color":"#ac9da2", - "position": {"x":7821,"y":131,"z":7277}, + "position": {"x":8321,"y":131,"z":6707}, "children":[ { "type":"office", @@ -485,6 +489,10 @@ { "type":"water", "position":{"x":7981.461,"y":131.77,"z":7392.4} + }, + { + "type":"water", + "position":{"x":7998.145,"y":131.7769,"z":7477.136} } ] }, @@ -493,7 +501,7 @@ "type":"station", "shorthand":"SW", "color":"#ffce98", - "position":{"x":1364.217,"y":147.2043,"z":2194.633}, + "position":{"x":964.217,"y":147.2043,"z":1794.633}, "children":[ { "type":"office", diff --git a/style.css b/style.css index 3656613..cde804e 100644 --- a/style.css +++ b/style.css @@ -9,6 +9,8 @@ --cullThreshold_state_4: none; --cullThreshold_state_5: none; --cullThreshold_state_6: none; + + --absScale: 1; } html, body, #map, #mapContainer, h1, h2, h3, h4, h5{ @@ -77,6 +79,9 @@ a:visited{ #legendKey{ font-size: 15px; + display: flex; + flex-flow: column wrap; + max-height: 350px; } #footer{ @@ -115,4 +120,8 @@ a:visited{ width: 1em; height: 1em; vertical-align: -0.1em; +} + +.poi{ + font-variation-settings: "wght" 700; } \ No newline at end of file