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