mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 03:51:23 +01:00
feat: rework temperature generation alg
This commit is contained in:
parent
fbb605d01d
commit
42b0cafecd
7 changed files with 128 additions and 96 deletions
27
index.html
27
index.html
|
|
@ -2352,13 +2352,8 @@
|
||||||
<i data-locked="0" id="lock_temperatureEquator" class="icon-lock-open"></i>
|
<i data-locked="0" id="lock_temperatureEquator" class="icon-lock-open"></i>
|
||||||
<label data-tip="Set temperature at equator">
|
<label data-tip="Set temperature at equator">
|
||||||
<i>Equator:</i>
|
<i>Equator:</i>
|
||||||
<input
|
<input id="temperatureEquatorInput" data-stored="temperatureEquator" type="number" min="-50" max="50" />
|
||||||
id="temperatureEquatorInput"
|
<span>°C = <span id="temperatureEquatorF"></span></span>
|
||||||
data-stored="temperatureEquator"
|
|
||||||
type="number"
|
|
||||||
min="-50"
|
|
||||||
max="50"
|
|
||||||
/>°C = <span id="temperatureEquatorF"></span>°F
|
|
||||||
<input id="temperatureEquatorOutput" data-stored="temperatureEquator" type="range" min="-50" max="50" />
|
<input id="temperatureEquatorOutput" data-stored="temperatureEquator" type="range" min="-50" max="50" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -2373,7 +2368,7 @@
|
||||||
min="-50"
|
min="-50"
|
||||||
max="50"
|
max="50"
|
||||||
/>
|
/>
|
||||||
<span>°C = <span id="temperatureNorthPoleF"></span>°F</span>
|
<span>°C = <span id="temperatureNorthPoleF"></span></span>
|
||||||
<input
|
<input
|
||||||
id="temperatureNorthPoleOutput"
|
id="temperatureNorthPoleOutput"
|
||||||
data-stored="temperatureNorthPole"
|
data-stored="temperatureNorthPole"
|
||||||
|
|
@ -2395,7 +2390,7 @@
|
||||||
min="-50"
|
min="-50"
|
||||||
max="50"
|
max="50"
|
||||||
/>
|
/>
|
||||||
<span>°C = <span id="temperatureSouthPoleF"></span>°F</span>
|
<span>°C = <span id="temperatureSouthPoleF"></span></span>
|
||||||
<input
|
<input
|
||||||
id="temperatureSouthPoleOutput"
|
id="temperatureSouthPoleOutput"
|
||||||
data-stored="temperatureSouthPole"
|
data-stored="temperatureSouthPole"
|
||||||
|
|
@ -2461,13 +2456,13 @@
|
||||||
<svg id="globe" width="22em" height="22em" viewBox="-20 -25 240 240">
|
<svg id="globe" width="22em" height="22em" viewBox="-20 -25 240 240">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient id="temperatureGradient" x1="0" x2="0" y1="0" y2="1">
|
<linearGradient id="temperatureGradient" x1="0" x2="0" y1="0" y2="1">
|
||||||
<stop class="tempNorthGradient90" offset="0%" stop-color="blue" />
|
<stop id="grad90" offset="0%" stop-color="blue" />
|
||||||
<stop class="tempNorthGradient60" offset="16.6%" stop-color="green" />
|
<stop id="grad60" offset="16.6%" stop-color="green" />
|
||||||
<stop class="tempNorthGradient30" offset="33.3%" stop-color="yellow" />
|
<stop id="grad30" offset="33.3%" stop-color="yellow" />
|
||||||
<stop class="tempGradient0" offset="50%" stop-color="red" />
|
<stop id="grad0" offset="50%" stop-color="red" />
|
||||||
<stop class="tempSouthGradient30" offset="66.6%" stop-color="yellow" />
|
<stop id="grad-30" offset="66.6%" stop-color="yellow" />
|
||||||
<stop class="tempSouthGradient60" offset="83.3%" stop-color="green" />
|
<stop id="grad-60" offset="83.3%" stop-color="green" />
|
||||||
<stop class="tempSouthGradient90" offset="100%" stop-color="blue" />
|
<stop id="grad-90" offset="100%" stop-color="blue" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
<g id="globeNoteLines">
|
<g id="globeNoteLines">
|
||||||
|
|
|
||||||
68
main.js
68
main.js
|
|
@ -5,8 +5,8 @@
|
||||||
// set debug options
|
// set debug options
|
||||||
const PRODUCTION = location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1";
|
const PRODUCTION = location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1";
|
||||||
const DEBUG = localStorage.getItem("debug");
|
const DEBUG = localStorage.getItem("debug");
|
||||||
const INFO = DEBUG || !PRODUCTION;
|
const INFO = true;
|
||||||
const TIME = DEBUG || !PRODUCTION;
|
const TIME = true;
|
||||||
const WARN = true;
|
const WARN = true;
|
||||||
const ERROR = true;
|
const ERROR = true;
|
||||||
|
|
||||||
|
|
@ -179,15 +179,17 @@ function onZoom() {
|
||||||
const onZoomDebouced = debounce(onZoom, 50);
|
const onZoomDebouced = debounce(onZoom, 50);
|
||||||
const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", onZoomDebouced);
|
const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", onZoomDebouced);
|
||||||
|
|
||||||
// default options
|
// default options, based on Earth data
|
||||||
let options = {
|
let options = {
|
||||||
pinNotes: false,
|
pinNotes: false,
|
||||||
showMFCGMap: true,
|
showMFCGMap: true,
|
||||||
winds: [225, 45, 225, 315, 135, 315],
|
winds: [225, 45, 225, 315, 135, 315],
|
||||||
tempNorthPole: 0,
|
temperatureEquator: 27,
|
||||||
tempSouthPole: 0,
|
temperatureNorthPole: -30,
|
||||||
|
temperatureSouthPole: -15,
|
||||||
stateLabelsMode: "auto"
|
stateLabelsMode: "auto"
|
||||||
};
|
};
|
||||||
|
|
||||||
let mapCoordinates = {}; // map coordinates on globe
|
let mapCoordinates = {}; // map coordinates on globe
|
||||||
let populationRate = +document.getElementById("populationRateInput").value;
|
let populationRate = +document.getElementById("populationRateInput").value;
|
||||||
let distanceScale = +document.getElementById("distanceScaleInput").value;
|
let distanceScale = +document.getElementById("distanceScaleInput").value;
|
||||||
|
|
@ -469,7 +471,7 @@ function applyDefaultBiomesSystem() {
|
||||||
const biomesMartix = [
|
const biomesMartix = [
|
||||||
// hot ↔ cold [>19°C; <-4°C]; dry ↕ wet
|
// hot ↔ cold [>19°C; <-4°C]; dry ↕ wet
|
||||||
new Uint8Array([1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10]),
|
new Uint8Array([1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10]),
|
||||||
new Uint8Array([3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 9, 9, 10, 10, 10]),
|
new Uint8Array([1, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 9, 9, 10, 10, 10]),
|
||||||
new Uint8Array([5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 10, 10, 10]),
|
new Uint8Array([5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 9, 9, 9, 9, 10, 10, 10]),
|
||||||
new Uint8Array([5, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10]),
|
new Uint8Array([5, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10]),
|
||||||
new Uint8Array([7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10])
|
new Uint8Array([7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10])
|
||||||
|
|
@ -1010,29 +1012,43 @@ function calculateTemperatures() {
|
||||||
TIME && console.time("calculateTemperatures");
|
TIME && console.time("calculateTemperatures");
|
||||||
const cells = grid.cells;
|
const cells = grid.cells;
|
||||||
cells.temp = new Int8Array(cells.i.length); // temperature array
|
cells.temp = new Int8Array(cells.i.length); // temperature array
|
||||||
const tEq = +temperatureEquatorInput.value;
|
|
||||||
const tNorthPole = +temperatureNorthPoleInput.value;
|
|
||||||
const tSouthPole = +temperatureSouthPoleInput.value;
|
|
||||||
//Update Settings to match the slider(there may be a better solution)
|
|
||||||
options.tempSouthPole = +tSouthPole;
|
|
||||||
options.tempNorthPole = +tNorthPole;
|
|
||||||
const tNDelta = tEq - tNorthPole;
|
|
||||||
const tSDelta = tEq - tSouthPole;
|
|
||||||
const int = d3.easePolyInOut.exponent(0.5); // interpolation function
|
|
||||||
|
|
||||||
d3.range(0, cells.i.length, grid.cellsX).forEach(function (r) {
|
const {temperatureEquator, temperatureNorthPole, temperatureSouthPole} = options;
|
||||||
const y = grid.points[r][1];
|
const tropics = [16, -20]; // tropics zone
|
||||||
const lat = (mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT); // [-90; 90]
|
const tropicalGradient = 0.15;
|
||||||
const initTemp = tEq - (Math.max(rn(lat / 90, 2), 0) * tNDelta - Math.min(rn(lat / 90, 2), 0) * tSDelta);
|
|
||||||
for (let i = r; i < r + grid.cellsX; i++) {
|
const tempNorthTropic = temperatureEquator - tropics[0] * tropicalGradient;
|
||||||
cells.temp[i] = minmax(initTemp - convertToFriendly(cells.h[i]), -128, 127);
|
const northernGradient = (tempNorthTropic - temperatureNorthPole) / (90 - tropics[0]);
|
||||||
}
|
|
||||||
});
|
const tempSouthTropic = temperatureEquator + tropics[1] * tropicalGradient;
|
||||||
|
const southernGradient = (tempSouthTropic - temperatureSouthPole) / (90 + tropics[1]);
|
||||||
|
|
||||||
// temperature decreases by 6.5 degree C per 1km
|
|
||||||
function convertToFriendly(h) {
|
|
||||||
if (h < 20) return 0;
|
|
||||||
const exponent = +heightExponentInput.value;
|
const exponent = +heightExponentInput.value;
|
||||||
|
|
||||||
|
for (let rowCellId = 0; rowCellId < cells.i.length; rowCellId += grid.cellsX) {
|
||||||
|
const [, y] = grid.points[rowCellId];
|
||||||
|
const rowLatitude = mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT; // [90; -90]
|
||||||
|
const tempSeaLevel = calculateSeaLevelTemp(rowLatitude);
|
||||||
|
DEBUG && console.info(`${rn(rowLatitude)}° sea temperature: ${rn(tempSeaLevel)}°C`);
|
||||||
|
|
||||||
|
for (let cellId = rowCellId; cellId < rowCellId + grid.cellsX; cellId++) {
|
||||||
|
const tempAltitudeDrop = getAltitudeTemperatureDrop(cells.h[cellId]);
|
||||||
|
cells.temp[cellId] = minmax(tempSeaLevel - tempAltitudeDrop, -128, 127);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateSeaLevelTemp(latitude) {
|
||||||
|
const isTropical = latitude <= 16 && latitude >= -20;
|
||||||
|
if (isTropical) return temperatureEquator - Math.abs(latitude) * tropicalGradient;
|
||||||
|
|
||||||
|
return latitude > 0
|
||||||
|
? tempNorthTropic - (latitude - tropics[0]) * northernGradient
|
||||||
|
: tempSouthTropic + (latitude - tropics[1]) * southernGradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
// temperature drops by 6.5°C per 1km of altitude
|
||||||
|
function getAltitudeTemperatureDrop(h) {
|
||||||
|
if (h < 20) return 0;
|
||||||
const height = Math.pow(h - 18, exponent);
|
const height = Math.pow(h - 18, exponent);
|
||||||
return rn((height / 1000) * 6.5);
|
return rn((height / 1000) * 6.5);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -639,7 +639,7 @@ export function resolveVersionConflicts(version) {
|
||||||
|
|
||||||
if (version < 1.89) {
|
if (version < 1.89) {
|
||||||
//May need a major bump
|
//May need a major bump
|
||||||
options.tempNorthPole = +temperatureNorthPoleInput.value;
|
options.temperatureNorthPole = +temperatureNorthPoleInput.value;
|
||||||
options.tempSouthPole = +temperatureNorthPoleInput.value;
|
options.temperatureSouthPole = +temperatureNorthPoleInput.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -589,8 +589,8 @@ async function parseLoadedData(data) {
|
||||||
// set options
|
// set options
|
||||||
yearInput.value = options.year;
|
yearInput.value = options.year;
|
||||||
eraInput.value = options.era;
|
eraInput.value = options.era;
|
||||||
temperatureNorthPoleOutput.value = temperatureNorthPoleInput.value = options.tempNorthPole;
|
temperatureNorthPoleOutput.value = temperatureNorthPoleInput.value = options.temperatureNorthPole;
|
||||||
temperatureSouthPoleOutput.value = temperatureSouthPoleInput.value = options.tempSouthPole;
|
temperatureSouthPoleOutput.value = temperatureSouthPoleInput.value = options.temperatureSouthPole;
|
||||||
shapeRendering.value = viewbox.attr("shape-rendering") || "geometricPrecision";
|
shapeRendering.value = viewbox.attr("shape-rendering") || "geometricPrecision";
|
||||||
|
|
||||||
if (window.restoreDefaultEvents) restoreDefaultEvents();
|
if (window.restoreDefaultEvents) restoreDefaultEvents();
|
||||||
|
|
|
||||||
|
|
@ -559,11 +559,10 @@ function applyStoredOptions() {
|
||||||
if (key.slice(0, 5) === "style") applyOption(stylePreset, key, key.slice(5));
|
if (key.slice(0, 5) === "style") applyOption(stylePreset, key, key.slice(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stored("winds"))
|
if (stored("winds")) options.winds = localStorage.getItem("winds").split(",").map(Number);
|
||||||
options.winds = localStorage
|
if (stored("temperatureEquator")) options.temperatureEquator = +localStorage.getItem("temperatureEquator");
|
||||||
.getItem("winds")
|
if (stored("temperatureNorthPole")) options.temperatureNorthPole = +localStorage.getItem("temperatureNorthPole");
|
||||||
.split(",")
|
if (stored("temperatureSouthPole")) options.temperatureSouthPole = +localStorage.getItem("temperatureSouthPole");
|
||||||
.map(w => +w);
|
|
||||||
if (stored("military")) options.military = JSON.parse(stored("military"));
|
if (stored("military")) options.military = JSON.parse(stored("military"));
|
||||||
|
|
||||||
if (stored("tooltipSize")) changeTooltipSize(stored("tooltipSize"));
|
if (stored("tooltipSize")) changeTooltipSize(stored("tooltipSize"));
|
||||||
|
|
@ -607,15 +606,10 @@ function randomizeOptions() {
|
||||||
if (randomize || !locked("culturesSet")) randomizeCultureSet();
|
if (randomize || !locked("culturesSet")) randomizeCultureSet();
|
||||||
|
|
||||||
// 'Configure World' settings
|
// 'Configure World' settings
|
||||||
|
if (randomize || !locked("temperatureEquator")) options.temperatureEquator = gauss(25, 7, 20, 35, 0);
|
||||||
|
if (randomize || !locked("temperatureNorthPole")) options.temperatureNorthPole = gauss(-25, 7, -40, 10, 0);
|
||||||
|
if (randomize || !locked("temperatureSouthPole")) options.temperatureSouthPole = gauss(-15, 7, -40, 10, 0);
|
||||||
if (randomize || !locked("prec")) precInput.value = precOutput.value = gauss(100, 40, 5, 500);
|
if (randomize || !locked("prec")) precInput.value = precOutput.value = gauss(100, 40, 5, 500);
|
||||||
const tMax = 30,
|
|
||||||
tMin = -30; // temperature extremes
|
|
||||||
if (randomize || !locked("temperatureEquator"))
|
|
||||||
temperatureEquatorOutput.value = temperatureEquatorInput.value = rand(tMax - 10, tMax);
|
|
||||||
if (randomize || !locked("temperatureNorthPole"))
|
|
||||||
temperatureNorthPoleOutput.value = temperatureNorthPoleInput.value = rand(tMin, tMin + 30);
|
|
||||||
if (randomize || !locked("temperatureSouthPole"))
|
|
||||||
temperatureSouthPoleOutput.value = temperatureSouthPoleInput.value = rand(tMin, tMin + 30);
|
|
||||||
|
|
||||||
// 'Units Editor' settings
|
// 'Units Editor' settings
|
||||||
const US = navigator.language === "en-US";
|
const US = navigator.language === "en-US";
|
||||||
|
|
@ -1074,8 +1068,7 @@ function toggle3dOptions() {
|
||||||
document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution);
|
document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution);
|
||||||
// document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d);
|
// document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d);
|
||||||
document.getElementById("options3dSunColor").addEventListener("input", changeSunColor);
|
document.getElementById("options3dSunColor").addEventListener("input", changeSunColor);
|
||||||
document.getElementById("options3dSubdivide").addEventListener("change",toggle3dSubdivision);
|
document.getElementById("options3dSubdivide").addEventListener("change", toggle3dSubdivision);
|
||||||
|
|
||||||
|
|
||||||
function updateValues() {
|
function updateValues() {
|
||||||
const globe = document.getElementById("canvas3d").dataset.type === "viewGlobe";
|
const globe = document.getElementById("canvas3d").dataset.type === "viewGlobe";
|
||||||
|
|
@ -1115,7 +1108,7 @@ function toggle3dOptions() {
|
||||||
ThreeD.setLightness(this.value / 100);
|
ThreeD.setLightness(this.value / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeSunColor(){
|
function changeSunColor() {
|
||||||
ThreeD.setSunColor(options3dSunColor.value);
|
ThreeD.setSunColor(options3dSunColor.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1136,7 +1129,7 @@ function toggle3dOptions() {
|
||||||
ThreeD.toggleLabels();
|
ThreeD.toggleLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle3dSubdivision(){
|
function toggle3dSubdivision() {
|
||||||
ThreeD.toggle3dSubdivision();
|
ThreeD.toggle3dSubdivision();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
function editWorld() {
|
function editWorld() {
|
||||||
if (customization) return;
|
if (customization) return;
|
||||||
|
|
||||||
$("#worldConfigurator").dialog({
|
$("#worldConfigurator").dialog({
|
||||||
title: "Configure World",
|
title: "Configure World",
|
||||||
resizable: false,
|
resizable: false,
|
||||||
|
|
@ -25,28 +26,54 @@ function editWorld() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const globe = d3.select("#globe");
|
const globe = d3.select("#globe");
|
||||||
const clr = d3.scaleSequential(d3.interpolateSpectral);
|
|
||||||
const tMax = 30,
|
|
||||||
tMin = -25; // temperature extremes
|
|
||||||
const projection = d3.geoOrthographic().translate([100, 100]).scale(100);
|
const projection = d3.geoOrthographic().translate([100, 100]).scale(100);
|
||||||
const path = d3.geoPath(projection);
|
const path = d3.geoPath(projection);
|
||||||
|
|
||||||
|
updateInputValues();
|
||||||
updateGlobeTemperature();
|
updateGlobeTemperature();
|
||||||
updateGlobePosition();
|
updateGlobePosition();
|
||||||
|
|
||||||
if (modules.editWorld) return;
|
if (modules.editWorld) return;
|
||||||
modules.editWorld = true;
|
modules.editWorld = true;
|
||||||
|
|
||||||
document.getElementById("worldControls").addEventListener("input", e => updateWorld(e.target));
|
byId("worldControls").addEventListener("input", e => updateWorld(e.target));
|
||||||
globe.select("#globeWindArrows").on("click", changeWind);
|
globe.select("#globeWindArrows").on("click", changeWind);
|
||||||
globe.select("#globeGraticule").attr("d", round(path(d3.geoGraticule()()))); // globe graticule
|
globe.select("#globeGraticule").attr("d", round(path(d3.geoGraticule()()))); // globe graticule
|
||||||
updateWindDirections();
|
updateWindDirections();
|
||||||
|
|
||||||
|
function updateInputValues() {
|
||||||
|
byId("temperatureEquatorInput").value = options.temperatureEquator;
|
||||||
|
byId("temperatureEquatorOutput").value = options.temperatureEquator;
|
||||||
|
byId("temperatureEquatorF").innerText = convertTemperature(options.temperatureEquator, "°F");
|
||||||
|
|
||||||
|
byId("temperatureNorthPoleInput").value = options.temperatureNorthPole;
|
||||||
|
byId("temperatureNorthPoleOutput").value = options.temperatureNorthPole;
|
||||||
|
byId("temperatureNorthPoleF").innerText = convertTemperature(options.temperatureNorthPole, "°F");
|
||||||
|
|
||||||
|
byId("temperatureSouthPoleInput").value = options.temperatureSouthPole;
|
||||||
|
byId("temperatureSouthPoleOutput").value = options.temperatureSouthPole;
|
||||||
|
byId("temperatureSouthPoleF").innerText = convertTemperature(options.temperatureSouthPole, "°F");
|
||||||
|
}
|
||||||
|
|
||||||
function updateWorld(el) {
|
function updateWorld(el) {
|
||||||
if (el) {
|
if (el?.dataset.stored) {
|
||||||
document.getElementById(el.dataset.stored + "Input").value = el.value;
|
const stored = el.dataset.stored;
|
||||||
document.getElementById(el.dataset.stored + "Output").value = el.value;
|
byId(stored + "Input").value = el.value;
|
||||||
if (el.dataset.stored) lock(el.dataset.stored);
|
byId(stored + "Output").value = el.value;
|
||||||
|
lock(el.dataset.stored);
|
||||||
|
|
||||||
|
if (stored === "temperatureEquator") {
|
||||||
|
options.temperatureEquator = Number(el.value);
|
||||||
|
byId("temperatureEquatorF").innerText = convertTemperature(options.temperatureEquator, "°F");
|
||||||
|
}
|
||||||
|
if (stored === "temperatureNorthPole") {
|
||||||
|
options.temperatureNorthPole = Number(el.value);
|
||||||
|
byId("temperatureNorthPoleF").innerText = convertTemperature(options.temperatureNorthPole, "°F");
|
||||||
|
}
|
||||||
|
if (stored === "temperatureSouthPole") {
|
||||||
|
options.temperatureSouthPole = Number(el.value);
|
||||||
|
byId("temperatureSouthPoleF").innerText = convertTemperature(options.temperatureSouthPole, "°F");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateGlobeTemperature();
|
updateGlobeTemperature();
|
||||||
|
|
@ -65,11 +92,11 @@ function editWorld() {
|
||||||
if (layerIsOn("toggleBiomes")) drawBiomes();
|
if (layerIsOn("toggleBiomes")) drawBiomes();
|
||||||
if (layerIsOn("toggleCoordinates")) drawCoordinates();
|
if (layerIsOn("toggleCoordinates")) drawCoordinates();
|
||||||
if (layerIsOn("toggleRivers")) drawRivers();
|
if (layerIsOn("toggleRivers")) drawRivers();
|
||||||
if (document.getElementById("canvas3d")) setTimeout(ThreeD.update(), 500);
|
if (byId("canvas3d")) setTimeout(ThreeD.update(), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateGlobePosition() {
|
function updateGlobePosition() {
|
||||||
const size = +document.getElementById("mapSizeOutput").value;
|
const size = +byId("mapSizeOutput").value;
|
||||||
const eqD = ((graphHeight / 2) * 100) / size;
|
const eqD = ((graphHeight / 2) * 100) / size;
|
||||||
|
|
||||||
calculateMapCoordinates();
|
calculateMapCoordinates();
|
||||||
|
|
@ -77,12 +104,12 @@ function editWorld() {
|
||||||
const scale = +distanceScaleInput.value;
|
const scale = +distanceScaleInput.value;
|
||||||
const unit = distanceUnitInput.value;
|
const unit = distanceUnitInput.value;
|
||||||
const meridian = toKilometer(eqD * 2 * scale);
|
const meridian = toKilometer(eqD * 2 * scale);
|
||||||
document.getElementById("mapSize").innerHTML = `${graphWidth}x${graphHeight}`;
|
byId("mapSize").innerHTML = `${graphWidth}x${graphHeight}`;
|
||||||
document.getElementById("mapSizeFriendly").innerHTML = `${rn(graphWidth * scale)}x${rn(graphHeight * scale)} ${unit}`;
|
byId("mapSizeFriendly").innerHTML = `${rn(graphWidth * scale)}x${rn(graphHeight * scale)} ${unit}`;
|
||||||
document.getElementById("meridianLength").innerHTML = rn(eqD * 2);
|
byId("meridianLength").innerHTML = rn(eqD * 2);
|
||||||
document.getElementById("meridianLengthFriendly").innerHTML = `${rn(eqD * 2 * scale)} ${unit}`;
|
byId("meridianLengthFriendly").innerHTML = `${rn(eqD * 2 * scale)} ${unit}`;
|
||||||
document.getElementById("meridianLengthEarth").innerHTML = meridian ? " = " + rn(meridian / 200) + "%🌏" : "";
|
byId("meridianLengthEarth").innerHTML = meridian ? " = " + rn(meridian / 200) + "%🌏" : "";
|
||||||
document.getElementById("mapCoordinates").innerHTML = `${lat(mc.latN)} ${Math.abs(rn(mc.lonW))}°W; ${lat(mc.latS)} ${rn(mc.lonE)}°E`;
|
byId("mapCoordinates").innerHTML = `${lat(mc.latN)} ${Math.abs(rn(mc.lonW))}°W; ${lat(mc.latS)} ${rn(mc.lonE)}°E`;
|
||||||
|
|
||||||
function toKilometer(v) {
|
function toKilometer(v) {
|
||||||
if (unit === "km") return v;
|
if (unit === "km") return v;
|
||||||
|
|
@ -104,22 +131,24 @@ function editWorld() {
|
||||||
globe.select("#globeArea").attr("d", round(path(area.outline()))); // map area
|
globe.select("#globeArea").attr("d", round(path(area.outline()))); // map area
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update temperatures on globe (visual-only)
|
||||||
function updateGlobeTemperature() {
|
function updateGlobeTemperature() {
|
||||||
const tEq = +document.getElementById("temperatureEquatorOutput").value;
|
const tEq = options.temperatureEquator;
|
||||||
document.getElementById("temperatureEquatorF").innerHTML = rn((tEq * 9) / 5 + 32);
|
const tNP = options.temperatureNorthPole;
|
||||||
const tNorthPole = +document.getElementById("temperatureNorthPoleOutput").value;
|
const tSP = options.temperatureSouthPole;
|
||||||
document.getElementById("temperatureNorthPoleF").innerHTML = rn((tNorthPole * 9) / 5 + 32);
|
|
||||||
const tSouthPole = +document.getElementById("temperatureSouthPoleOutput").value;
|
|
||||||
document.getElementById("temperatureSouthPoleF").innerHTML = rn((tSouthPole * 9) / 5 + 32);
|
|
||||||
|
|
||||||
//North to Equator to South
|
const scale = d3.scaleSequential(d3.interpolateSpectral);
|
||||||
globe.select(".tempNorthGradient90").attr("stop-color", clr(1 - (tNorthPole - tMin) / (tMax - tMin)));
|
const getColor = value => scale(1 - value);
|
||||||
globe.select(".tempNorthGradient60").attr("stop-color", clr(1 - (tEq - ((tEq - tNorthPole) * 2) / 3 - tMin) / (tMax - tMin)));
|
const [tMin, tMax] = [-25, 30]; // temperature extremes
|
||||||
globe.select(".tempNorthGradient30").attr("stop-color", clr(1 - (tEq - ((tEq - tNorthPole) * 1) / 3 - tMin) / (tMax - tMin)));
|
const tDelta = tMax - tMin;
|
||||||
globe.select(".tempGradient0").attr("stop-color", clr(1 - (tEq - tMin) / (tMax - tMin)));
|
|
||||||
globe.select(".tempSouthGradient30").attr("stop-color", clr(1 - (tEq - ((tEq - tSouthPole) * 1) / 3 - tMin) / (tMax - tMin)));
|
globe.select("#grad90").attr("stop-color", getColor((tNP - tMin) / tDelta));
|
||||||
globe.select(".tempSouthGradient60").attr("stop-color", clr(1 - (tEq - ((tEq - tSouthPole) * 2) / 3 - tMin) / (tMax - tMin)));
|
globe.select("#grad60").attr("stop-color", getColor((tEq - ((tEq - tNP) * 2) / 3 - tMin) / tDelta));
|
||||||
globe.select(".tempSouthGradient90").attr("stop-color", clr(1 - (tSouthPole - tMin) / (tMax - tMin)));
|
globe.select("#grad30").attr("stop-color", getColor((tEq - ((tEq - tNP) * 1) / 3 - tMin) / tDelta));
|
||||||
|
globe.select("#grad0").attr("stop-color", getColor((tEq - tMin) / tDelta));
|
||||||
|
globe.select("#grad-30").attr("stop-color", getColor((tEq - ((tEq - tSP) * 1) / 3 - tMin) / tDelta));
|
||||||
|
globe.select("#grad-60").attr("stop-color", getColor((tEq - ((tEq - tSP) * 2) / 3 - tMin) / tDelta));
|
||||||
|
globe.select("#grad-90").attr("stop-color", getColor((tSP - tMin) / tDelta));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWindDirections() {
|
function updateWindDirections() {
|
||||||
|
|
@ -153,8 +182,8 @@ function editWorld() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyWorldPreset(size, lat) {
|
function applyWorldPreset(size, lat) {
|
||||||
document.getElementById("mapSizeInput").value = document.getElementById("mapSizeOutput").value = size;
|
byId("mapSizeInput").value = byId("mapSizeOutput").value = size;
|
||||||
document.getElementById("latitudeInput").value = document.getElementById("latitudeOutput").value = lat;
|
byId("latitudeInput").value = byId("latitudeOutput").value = lat;
|
||||||
lock("mapSize");
|
lock("mapSize");
|
||||||
lock("latitude");
|
lock("latitude");
|
||||||
updateWorld();
|
updateWorld();
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ const temperatureConversionMap = {
|
||||||
"°Rø": temp => rn((temp * 21) / 40 + 7.5) + "°Rø"
|
"°Rø": temp => rn((temp * 21) / 40 + 7.5) + "°Rø"
|
||||||
};
|
};
|
||||||
|
|
||||||
function convertTemperature(temp) {
|
function convertTemperature(temp, scale = temperatureScale.value || "°C") {
|
||||||
const scale = temperatureScale.value || "°C";
|
|
||||||
return temperatureConversionMap[scale](temp);
|
return temperatureConversionMap[scale](temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue