General Improvements

- Added map legend
- Added marker toggles
- Added links
- Improved culling level switching
This commit is contained in:
Pyro Nicampt committed 2024-12-22 00:34:21 -06:00
1 parent 347e6a6068
commit 891fd69ab6
4 files changed
+196 -47

No files matched your search

+59 -2
View File
@@ -5,6 +5,7 @@
<link href="style.css" rel="stylesheet" type="text/css" media="all"> <link href="style.css" rel="stylesheet" type="text/css" media="all">
<title>Derail Valley Community Map</title> <title>Derail Valley Community Map</title>
<script type="module" src="index.js"></script> <script type="module" src="index.js"></script>
<script type="module" src="legend.js"></script>
</head> </head>
<body> <body>
<div id="mapContainer"> <div id="mapContainer">
@@ -22,6 +23,18 @@
--grade_7: #c33577; --grade_7: #c33577;
--grade_8: #a3008d; --grade_8: #a3008d;
--grade_9: #690097; --grade_9: #690097;
--signScale: 1;
--cullThreshold_state_0: none;
--cullThreshold_state_1: none;
--cullThreshold_state_2: none;
--cullThreshold_state_3: none;
--cullThreshold_state_4: none;
--cullThreshold_state_5: none;
--cullThreshold_state_6: none;
}
.sign{
transform: scale(var(--signScale));
} }
.sign, .rail, .signText{ .sign, .rail, .signText{
cursor: default; cursor: default;
@@ -104,6 +117,27 @@
.gradeSign.grade_9{ .gradeSign.grade_9{
fill: var(--grade_9); fill: var(--grade_9);
} }
.cullThreshold_0{
display: var(--cullThreshold_state_0);
}
.cullThreshold_1{
display: var(--cullThreshold_state_1);
}
.cullThreshold_2{
display: var(--cullThreshold_state_2);
}
.cullThreshold_3{
display: var(--cullThreshold_state_3);
}
.cullThreshold_4{
display: var(--cullThreshold_state_4);
}
.cullThreshold_5{
display: var(--cullThreshold_state_5);
}
.cullThreshold_6{
display: var(--cullThreshold_state_6);
}
</style> </style>
<style id="zoomStyle"></style> <style id="zoomStyle"></style>
<defs> <defs>
@@ -163,15 +197,38 @@
</defs> </defs>
</svg> </svg>
</div> </div>
<div id="headerbar"> <div id="topleft">
<div id="headerbar" class="panel orange">
<div> <div>
DV Community Map DV Community Map
</div> </div>
</div> </div>
<div id="footer"> <div id="legend" style="display: flex;">
<div style="display:flex; flex-direction:column; width: 400px;">
<div class="panel">
Welcome to the WIP community map of <a href="https://www.derailvalley.com/" style="white-space:nowrap;">Derail Valley</a>, a resource for documenting and displaying all tracks and points of interest.
<hr>
Hover over tracks and objects for detailed information.
</div>
<div id="settingsPanel" class="panel">
<h3>Map Settings</h3>
<hr>
</div>
<div class="panel">
<a href="https://github.com/PyroNicampt/DV-Community-Map">Source</a> &#8226;
<a href="https://github.com/PyroNicampt/DV-Community-Map/issues">Issue Tracker</a> &#8226;
<a href="https://derailvalley.wiki.gg/wiki/Derail_Valley_Wiki">DV Wiki</a>
</div>
</div>
<div id="legendButton" class="panel orange" style="height: fit-content;"><svg height="25" viewBox="0 0 32 32"><path fill="currentColor" d="M31 16 20 31l-16 0L15 16 4 1l16 0Z"/></svg></div>
</div>
</div>
<div id="footer" class="orange">
Map v0.1 alpha Map v0.1 alpha
<br> <br>
Updated for Game Build 99.3 Updated for Game Build 99.3
<br>
This tool is a fan work, Derail Valley owned by Altfuture
</div> </div>
</body> </body>
</html> </html>
+19 -38
View File
@@ -11,7 +11,7 @@ const bezierCurvatureResolution = 80;
const padding = 500; const padding = 500;
const zoomFactor = 1.2; const zoomFactor = 1.2;
const trackWidth = { const trackWidth = {
base: 90, base: 110,
min: 3, min: 3,
max: 90, max: 90,
} }
@@ -20,28 +20,20 @@ const signSize = {
min: 0.05, min: 0.05,
max: 2.4 max: 2.4
} }
const zoomThresholds = [ const scaleCullThresholds = [
{zoom:1, distance:500}, {scale:1, distance:500},
{zoom:1.25, distance:200}, {scale:1.25, distance:200},
{zoom:1.5, distance:130}, {scale:1.5, distance:130},
{zoom:2.5, distance:80}, {scale:2.5, distance:80},
{zoom:5, distance:40}, {scale:5, distance:40},
{zoom:20, distance:20}, {scale:20, distance:20},
{zoom:60, distance:10}, {scale:60, distance:10},
]; ];
const scaleCullThresholds = {
[1.0]: 500,
[1.25]: 200,
[1.5]: 130,
[2.5]: 80,
[5]: 40,
[20]: 20,
[60]: 10
}
// CODE // CODE
const map = document.getElementById('map'); const map = document.getElementById('map');
const map_container = document.getElementById('mapContainer'); const map_container = document.getElementById('mapContainer');
const styleRoot = document.querySelector(':root');
const svgns = map.getAttribute('xmlns'); const svgns = map.getAttribute('xmlns');
const map_rails = document.createElementNS(svgns, 'g'); const map_rails = document.createElementNS(svgns, 'g');
@@ -133,23 +125,18 @@ function updateMapview(navData = {x:0, y:0, scale:1}){
map.style.transform = `translate(${-navData.x}px, ${-navData.y}px) scale(${navData.scale})`; map.style.transform = `translate(${-navData.x}px, ${-navData.y}px) scale(${navData.scale})`;
if(navData.scale !== previousMapScale){ if(navData.scale !== previousMapScale){
let dirtyScale = previousMapScale < 0; let dirtyScale = previousMapScale < 0;
for(const cullThreshold in scaleCullThresholds){ for(const cullThreshold of scaleCullThresholds){
if(dirtyScale || (previousMapScale < cullThreshold && navData.scale > cullThreshold) || (previousMapScale > cullThreshold && navData.scale < cullThreshold)){ if(dirtyScale || (previousMapScale < cullThreshold.scale && navData.scale > cullThreshold.scale) || (previousMapScale > cullThreshold.scale && navData.scale < cullThreshold.scale)){
dirtyScale = true; dirtyScale = true;
break; break;
} }
} }
map_rails.setAttribute('stroke-width', Utils.clamp(trackWidth.base/navData.scale, trackWidth.min, trackWidth.max)); map_rails.setAttribute('stroke-width', Utils.clamp(trackWidth.base/navData.scale, trackWidth.min, trackWidth.max));
styleRoot.style.setProperty('--signScale', Utils.clamp(signSize.base/navData.scale, signSize.min, signSize.max));
if(dirtyScale){ if(dirtyScale){
let zoomThresholdStyles = ''; for(let i=0; i<scaleCullThresholds.length; i++){
for(let i=0; i<zoomThresholds.length; i++){ styleRoot.style.setProperty(`--cullThreshold_state_${i}`, navData.scale >= scaleCullThresholds[i].scale ? 'initial' : 'none')
zoomThresholdStyles += `\n.zoomThreshold_${i}{display:${navData.scale > zoomThresholds[i].zoom ? 'unset' : 'none'}}`;
} }
map.getElementById('zoomStyle').innerHTML = `
.sign{
transform: scale(${Utils.clamp(signSize.base/navData.scale, signSize.min, signSize.max)});
}${zoomThresholdStyles}
`;
} }
previousMapScale = navData.scale; previousMapScale = navData.scale;
} }
@@ -322,7 +309,7 @@ function cleanMarkers(){
/** Create the signage */ /** Create the signage */
function drawMarkers(){ function drawMarkers(){
const gradeSigns = document.createElementNS(svgns, 'g'); const gradeSigns = document.createElementNS(svgns, 'g');
gradeSigns.setAttribute('id', 'grade_Signs'); gradeSigns.setAttribute('id', 'grade_signs');
map_markers.appendChild(gradeSigns); map_markers.appendChild(gradeSigns);
const speedSigns = document.createElementNS(svgns, 'g'); const speedSigns = document.createElementNS(svgns, 'g');
speedSigns.setAttribute('id', 'speed_signs'); speedSigns.setAttribute('id', 'speed_signs');
@@ -332,29 +319,23 @@ function drawMarkers(){
let marker = document.createElementNS(svgns, 'g'); let marker = document.createElementNS(svgns, 'g');
let markerImg = document.createElementNS(svgns, 'use'); let markerImg = document.createElementNS(svgns, 'use');
let title = document.createElementNS(svgns, 'title'); let title = document.createElementNS(svgns, 'title');
let text = document.createElementNS(svgns, 'text');
marker.appendChild(markerImg); marker.appendChild(markerImg);
marker.appendChild(text);
marker.appendChild(title); marker.appendChild(title);
marker.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z})`); marker.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z})`);
// Grade signs // Grade signs
if(markerData.type == 'grade'){ if(markerData.type == 'grade'){
markerImg.setAttribute('href', '#gradeArrow'); markerImg.setAttribute('href', '#gradeArrow');
markerImg.classList.add('sign', 'gradeSign'); markerImg.classList.add('sign', 'gradeSign');
text.classList.add('signText', 'gradeSign');
if(markerData.class) markerImg.classList.add(markerData.class); if(markerData.class) markerImg.classList.add(markerData.class);
const tanLen = Math.sqrt(markerData.tangent.x*markerData.tangent.x + markerData.tangent.z*markerData.tangent.z) * Math.sign(markerData.tangent.y); 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); 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})`); marker.setAttribute('transform', `translate(${markerData.position.x} ${markerData.position.z}) rotate(${rot})`);
text.setAttribute('transform', `rotate(${-rot})`);
title.innerHTML = `${Math.round(markerData.value*1000)/10}%`; title.innerHTML = `${Math.round(markerData.value*1000)/10}%`;
text.innerHTML = `${Math.round(markerData.value*1000)/10}`;
gradeSigns.appendChild(marker); gradeSigns.appendChild(marker);
// Speed Signs // Speed Signs
}else if(markerData.type == 'speed'){ }else if(markerData.type == 'speed'){
markerImg.setAttribute('href', `#speedSign_${Math.round(markerData.value/10)}`); markerImg.setAttribute('href', `#speedSign_${Math.round(markerData.value/10)}`);
markerImg.classList.add('sign', 'speedSign'); markerImg.classList.add('sign', 'speedSign');
text.classList.add('signText', 'speedSign');
title.innerHTML = `${Math.round(markerData.value)} km/h`; title.innerHTML = `${Math.round(markerData.value)} km/h`;
/*let offset = Vector.normalize({x:markerData.tangent.z, y:0, z:-markerData.tangent.x}); /*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 + offset.x*100} ${markerData.position.z + offset.z*50})`);*/
@@ -362,10 +343,10 @@ function drawMarkers(){
speedSigns.appendChild(marker); speedSigns.appendChild(marker);
} }
for(let i=zoomThresholds.length-1; i>= 0; i--){ for(let i=scaleCullThresholds.length-1; i>= 0; i--){
if(markerData.nearestDist < zoomThresholds[i].distance || i==0){ if(markerData.nearestDist < scaleCullThresholds[i].distance || i==0){
title.innerHTML += `\n${markerData.nearestDist}`; title.innerHTML += `\n${markerData.nearestDist}`;
marker.classList.add(`zoomThreshold_${i}`); marker.classList.add(`cullThreshold_${i}`);
break; break;
} }
} }
+86
View File
@@ -0,0 +1,86 @@
'use strict';
let settingEntries = [
{
label: 'Signage',
id: 'toggle_signage',
state: true,
func: state =>{
document.getElementById('map_markers').style.display = state ? 'unset' : 'none';
},
children: [
{
label: 'Speed Signs',
id: 'toggle_speedSigns',
state: true,
func: state =>{
document.getElementById('speed_signs').style.display = state ? 'unset' : 'none';
},
},
{
label: 'Grade Arrows',
id: 'toggle_gradeSigns',
state: true,
func: state =>{
document.getElementById('grade_signs').style.display = state ? 'unset' : 'none';
},
}
],
},
{
label: 'Track Color',
id: 'radio_trackColor',
options: [
'None',
'Grade',
],
default: 1,
},
];
document.addEventListener('DOMContentLoaded', async () => {
const settingsPanel = document.getElementById('settingsPanel');
for(let thisSetting of settingEntries){
addSettingEntry(thisSetting, settingsPanel);
}
});
function addSettingEntry(thisSetting, parent, indent=0){
thisSetting.divContainer = document.createElement('div');
thisSetting.divContainer.innerHTML = '&nbsp;'.repeat(indent);
thisSetting.inputElement = document.createElement('input');
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.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 =>{
thisSetting.func(e.target.checked);
if(thisSetting.children){
for(const child of thisSetting.children){
document.getElementById(child.id).parentElement.style.display = e.target.checked ? '' : 'none';
}
}
});
}
break;
default:
thisSetting.divContainer.remove();
return;
}
if(thisSetting.children){
for(let child of thisSetting.children){
addSettingEntry(child, parent, indent+1);
}
}
}
+32 -7
View File
@@ -10,16 +10,42 @@ html, body{
width: 100vw; width: 100vw;
font-family: "Noto Sans"; font-family: "Noto Sans";
font-variation-settings: "wght" 400; font-variation-settings: "wght" 400;
color: #e9e9e9;
}
a{
color: #85c4f7;
}
a:visited{
color: #559bd4;
}
.orange{
color: #e79830;
}
#topleft{
position:fixed;
top: 0px;
left: 0px;
pointer-events: none;
}
.panel{
width: fit-content;
border: 2px solid #b3b3b396;
background: linear-gradient(120deg, #2c3f58, #191e2e);
text-shadow: 2px 2px 5px #0003;
margin: 5px;
padding: 8px 13px;
border-radius: 10px;
pointer-events: all;
} }
#headerbar{ #headerbar{
position:fixed;
width: fit-content;
font-size: 30px;
background: linear-gradient(120deg, #3d5779, #121522); background: linear-gradient(120deg, #3d5779, #121522);
border: 2px solid #b3b3b396; font-size: 30px;
border-left: 0px; border-left: 0px;
color: #e79830;
font-variation-settings: "wght" 500; font-variation-settings: "wght" 500;
padding: 10px 30px 10px 30px; padding: 10px 30px 10px 30px;
margin: 10px 0px; margin: 10px 0px;
@@ -31,8 +57,7 @@ html, body{
width: fit-content; width: fit-content;
right: 10px; right: 10px;
bottom: 5px; bottom: 5px;
font-size: 10px; font-size: 12px;
color: #e79830;
text-align: right; text-align: right;
} }