mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
Independent North and South Poles temperature (#972)
* Poles to have Different Temperature (Ref: Axial Tilt suggestion) (#964) * Initial Idea * Changed Names: Currently still only on NorthTemperature reliant, compadible version * Restored Generation of Temperature * Temperature Function found * Version Bump * Scuffed Saving solution * Current Version(without the save changes) * Globe Temperature Display * Individual Regeneration of Temperatures * Fixed Loading and Saving New Maps save a Dummy 0 at settings[17] * Final Version Bump (currently no description for the Update) --------- Co-authored-by: Azgaar <maxganiev@yandex.com> * chore: formatting * refactor: temperature inputs * feat: rework temperature generation alg * style: respore winds button * refactor: update options on load, don't update temperature UI * refactor: no need to keep compatibility here * fix: load temp setting from .map file --------- Co-authored-by: Leo <leonard.krusch@gmx.de>
This commit is contained in:
parent
7b3f897bdb
commit
b3e2aa00e7
9 changed files with 240 additions and 155 deletions
181
index.html
181
index.html
|
|
@ -2346,29 +2346,58 @@
|
|||
|
||||
<div id="dialogs">
|
||||
<div id="worldConfigurator" class="dialog stable" style="display: none">
|
||||
<div>
|
||||
<div style="display: flex">
|
||||
<div id="worldControls">
|
||||
<div>
|
||||
<i data-locked="0" id="lock_temperatureEquator" class="icon-lock-open"></i>
|
||||
<label data-tip="Set temperature at equator">
|
||||
<i>Equator:</i>
|
||||
<input
|
||||
id="temperatureEquatorInput"
|
||||
data-stored="temperatureEquator"
|
||||
type="number"
|
||||
min="-50"
|
||||
max="50"
|
||||
/>°C = <span id="temperatureEquatorF"></span>°F
|
||||
<input id="temperatureEquatorInput" data-stored="temperatureEquator" type="number" min="-50" max="50" />
|
||||
<span>°C = <span id="temperatureEquatorF"></span></span>
|
||||
<input id="temperatureEquatorOutput" data-stored="temperatureEquator" type="range" min="-50" max="50" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<i data-locked="0" id="lock_temperaturePole" class="icon-lock-open"></i>
|
||||
<label data-tip="Set temperature near poles">
|
||||
<i>Poles:</i>
|
||||
<input id="temperaturePoleInput" data-stored="temperaturePole" type="number" min="-50" max="50" />°C =
|
||||
<span id="temperaturePoleF"></span>°F
|
||||
<input id="temperaturePoleOutput" data-stored="temperaturePole" type="range" min="-50" max="50" />
|
||||
<label data-tip="Set the North Pole average yearly temperature">
|
||||
<i data-locked="0" id="lock_temperatureNorthPole" class="icon-lock-open"></i>
|
||||
<i>North Pole:</i>
|
||||
<input
|
||||
id="temperatureNorthPoleInput"
|
||||
data-stored="temperatureNorthPole"
|
||||
type="number"
|
||||
min="-50"
|
||||
max="50"
|
||||
/>
|
||||
<span>°C = <span id="temperatureNorthPoleF"></span></span>
|
||||
<input
|
||||
id="temperatureNorthPoleOutput"
|
||||
data-stored="temperatureNorthPole"
|
||||
type="range"
|
||||
min="-50"
|
||||
max="50"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label data-tip="Set the South Pole average yearly temperature">
|
||||
<i data-locked="0" id="lock_temperatureSouthPole" class="icon-lock-open"></i>
|
||||
<i>South Pole:</i>
|
||||
<input
|
||||
id="temperatureSouthPoleInput"
|
||||
data-stored="temperatureSouthPole"
|
||||
type="number"
|
||||
min="-50"
|
||||
max="50"
|
||||
/>
|
||||
<span>°C = <span id="temperatureSouthPoleF"></span></span>
|
||||
<input
|
||||
id="temperatureSouthPoleOutput"
|
||||
data-stored="temperatureSouthPole"
|
||||
type="range"
|
||||
min="-50"
|
||||
max="50"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
|
|
@ -2424,59 +2453,65 @@
|
|||
<div data-tip="Map coordinates on globe"><i>Coords:</i> <span id="mapCoordinates"></span></div>
|
||||
</div>
|
||||
|
||||
<svg id="globe" width="22em" height="22em" viewBox="-20 -25 240 240">
|
||||
<defs>
|
||||
<linearGradient id="temperatureGradient" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop class="tempGradient90" offset="0%" stop-color="blue" />
|
||||
<stop class="tempGradient60" offset="16.6%" stop-color="green" />
|
||||
<stop class="tempGradient30" offset="33.3%" stop-color="yellow" />
|
||||
<stop class="tempGradient0" offset="50%" stop-color="red" />
|
||||
<stop class="tempGradient30" offset="66.6%" stop-color="yellow" />
|
||||
<stop class="tempGradient60" offset="83.3%" stop-color="green" />
|
||||
<stop class="tempGradient90" offset="100%" stop-color="blue" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="globeNoteLines">
|
||||
<line x1="5" x2="220" y1="0" y2="0" />
|
||||
<line x1="5" x2="220" y1="13" y2="13" />
|
||||
<line x1="5" x2="220" y1="49.5" y2="49.5" />
|
||||
<line x1="-5" x2="220" y1="100" y2="100" />
|
||||
<line x1="5" x2="220" y1="150.5" y2="150.5" />
|
||||
<line x1="5" x2="220" y1="187" y2="187" />
|
||||
<line x1="5" x2="220" y1="200" y2="200" />
|
||||
</g>
|
||||
<g id="globeWindArrows" data-tip="Click to change wind direction" stroke-linejoin="round">
|
||||
<circle cx="210" cy="6" r="12" />
|
||||
<path data-tier="0" d="M210,11 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(225 210 6)" />
|
||||
<circle cx="210" cy="30" r="12" />
|
||||
<path data-tier="1" d="M210,35 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(45 210 30)" />
|
||||
<circle cx="210" cy="75" r="12" />
|
||||
<path data-tier="2" d="M210,80 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(225 210 75)" />
|
||||
<circle cx="210" cy="130" r="12" />
|
||||
<path data-tier="3" d="M210,135 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(315 210 130)" />
|
||||
<circle cx="210" cy="173" r="12" />
|
||||
<path data-tier="4" d="M210,178 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(135 210 173)" />
|
||||
<circle cx="210" cy="194" r="12" />
|
||||
<path data-tier="5" d="M210,199 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(315 210 194)" />
|
||||
</g>
|
||||
<g id="globaAxisLabels">
|
||||
<text x="82%" y="-4%">wind</text>
|
||||
<text x="-8%" y="-4%">latitude</text>
|
||||
</g>
|
||||
<g id="globeLatLabels">
|
||||
<text x="-15" y="5">90°</text>
|
||||
<text x="-15" y="18">60°</text>
|
||||
<text x="-15" y="53">30°</text>
|
||||
<text x="-15" y="103">0°</text>
|
||||
<text x="-15" y="153">30°</text>
|
||||
<text x="-15" y="190">60°</text>
|
||||
<text x="-15" y="204">90°</text>
|
||||
</g>
|
||||
<circle id="globeOutline" cx="100" cy="100" r="100" />
|
||||
<line id="globeEquator" x1="1" x2="199" y1="100" y2="100" />
|
||||
<path id="globeGraticule" />
|
||||
<path id="globeArea" />
|
||||
</svg>
|
||||
<div style="display: flex; flex-direction: column; align-items: flex-end">
|
||||
<svg id="globe" width="22em" viewBox="-20 -25 240 240">
|
||||
<defs>
|
||||
<linearGradient id="temperatureGradient" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop id="grad90" offset="0%" stop-color="blue" />
|
||||
<stop id="grad60" offset="16.6%" stop-color="green" />
|
||||
<stop id="grad30" offset="33.3%" stop-color="yellow" />
|
||||
<stop id="grad0" offset="50%" stop-color="red" />
|
||||
<stop id="grad-30" offset="66.6%" stop-color="yellow" />
|
||||
<stop id="grad-60" offset="83.3%" stop-color="green" />
|
||||
<stop id="grad-90" offset="100%" stop-color="blue" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g id="globeNoteLines">
|
||||
<line x1="5" x2="220" y1="0" y2="0" />
|
||||
<line x1="5" x2="220" y1="13" y2="13" />
|
||||
<line x1="5" x2="220" y1="49.5" y2="49.5" />
|
||||
<line x1="-5" x2="220" y1="100" y2="100" />
|
||||
<line x1="5" x2="220" y1="150.5" y2="150.5" />
|
||||
<line x1="5" x2="220" y1="187" y2="187" />
|
||||
<line x1="5" x2="220" y1="200" y2="200" />
|
||||
</g>
|
||||
<g id="globeWindArrows" data-tip="Click to change wind direction" stroke-linejoin="round">
|
||||
<circle cx="210" cy="6" r="12" />
|
||||
<path data-tier="0" d="M210,11 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(225 210 6)" />
|
||||
<circle cx="210" cy="30" r="12" />
|
||||
<path data-tier="1" d="M210,35 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(45 210 30)" />
|
||||
<circle cx="210" cy="75" r="12" />
|
||||
<path data-tier="2" d="M210,80 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(225 210 75)" />
|
||||
<circle cx="210" cy="130" r="12" />
|
||||
<path data-tier="3" d="M210,135 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(315 210 130)" />
|
||||
<circle cx="210" cy="173" r="12" />
|
||||
<path data-tier="4" d="M210,178 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(135 210 173)" />
|
||||
<circle cx="210" cy="194" r="12" />
|
||||
<path data-tier="5" d="M210,199 v-10 l-3,3 m6,0 l-3,-3" transform="rotate(315 210 194)" />
|
||||
</g>
|
||||
<g id="globaAxisLabels">
|
||||
<text x="82%" y="-4%">wind</text>
|
||||
<text x="-8%" y="-4%">latitude</text>
|
||||
</g>
|
||||
<g id="globeLatLabels">
|
||||
<text x="-15" y="5">90°</text>
|
||||
<text x="-15" y="18">60°</text>
|
||||
<text x="-15" y="53">30°</text>
|
||||
<text x="-15" y="103">0°</text>
|
||||
<text x="-15" y="153">30°</text>
|
||||
<text x="-15" y="190">60°</text>
|
||||
<text x="-15" y="204">90°</text>
|
||||
</g>
|
||||
<circle id="globeOutline" cx="100" cy="100" r="100" />
|
||||
<line id="globeEquator" x1="1" x2="199" y1="100" y2="100" />
|
||||
<path id="globeGraticule" />
|
||||
<path id="globeArea" />
|
||||
</svg>
|
||||
|
||||
<button id="restoreWinds" data-tip="Click to restore default (Earth-based) wind directions">
|
||||
Restore winds
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -7924,14 +7959,14 @@
|
|||
<script src="modules/ui/stylePresets.js?v=1.89.11"></script>
|
||||
|
||||
<script src="modules/ui/general.js?v=1.87.03"></script>
|
||||
<script src="modules/ui/options.js?v=1.89.36"></script>
|
||||
<script src="main.js?v=1.89.32"></script>
|
||||
<script src="modules/ui/options.js?v=1.90.00"></script>
|
||||
<script src="main.js?v=1.90.00"></script>
|
||||
|
||||
<script defer src="modules/relief-icons.js"></script>
|
||||
<script defer src="modules/ui/style.js"></script>
|
||||
<script defer src="modules/ui/editors.js?v=1.89.35"></script>
|
||||
<script defer src="modules/ui/tools.js?v=1.89.38"></script>
|
||||
<script defer src="modules/ui/world-configurator.js"></script>
|
||||
<script defer src="modules/ui/tools.js?v=1.90.00"></script>
|
||||
<script defer src="modules/ui/world-configurator.js?v=1.90.00"></script>
|
||||
<script defer src="modules/ui/heightmap-editor.js?v=1.89.06"></script>
|
||||
<script defer src="modules/ui/provinces-editor.js?v=1.89.00"></script>
|
||||
<script defer src="modules/ui/biomes-editor.js"></script>
|
||||
|
|
@ -7967,8 +8002,8 @@
|
|||
<script defer src="libs/rgbquant.min.js"></script>
|
||||
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
||||
|
||||
<script defer src="modules/io/save.js?v=1.89.29"></script>
|
||||
<script defer src="modules/io/load.js?v=1.89.30"></script>
|
||||
<script defer src="modules/io/save.js?v=1.90.00"></script>
|
||||
<script defer src="modules/io/load.js?v=1.90.00"></script>
|
||||
<script defer src="modules/io/cloud.js"></script>
|
||||
<script defer src="modules/io/export.js?v=1.89.36"></script>
|
||||
<script defer src="modules/io/formats.js"></script>
|
||||
|
|
|
|||
63
main.js
63
main.js
|
|
@ -5,8 +5,8 @@
|
|||
// set debug options
|
||||
const PRODUCTION = location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1";
|
||||
const DEBUG = localStorage.getItem("debug");
|
||||
const INFO = DEBUG || !PRODUCTION;
|
||||
const TIME = DEBUG || !PRODUCTION;
|
||||
const INFO = true;
|
||||
const TIME = true;
|
||||
const WARN = true;
|
||||
const ERROR = true;
|
||||
|
||||
|
|
@ -179,13 +179,17 @@ function onZoom() {
|
|||
const onZoomDebouced = debounce(onZoom, 50);
|
||||
const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", onZoomDebouced);
|
||||
|
||||
// default options
|
||||
// default options, based on Earth data
|
||||
let options = {
|
||||
pinNotes: false,
|
||||
showMFCGMap: true,
|
||||
winds: [225, 45, 225, 315, 135, 315],
|
||||
temperatureEquator: 27,
|
||||
temperatureNorthPole: -30,
|
||||
temperatureSouthPole: -15,
|
||||
stateLabelsMode: "auto"
|
||||
};
|
||||
|
||||
let mapCoordinates = {}; // map coordinates on globe
|
||||
let populationRate = +document.getElementById("populationRateInput").value;
|
||||
let distanceScale = +document.getElementById("distanceScaleInput").value;
|
||||
|
|
@ -467,7 +471,7 @@ function applyDefaultBiomesSystem() {
|
|||
const biomesMartix = [
|
||||
// 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([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, 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])
|
||||
|
|
@ -968,7 +972,7 @@ function defineMapSize() {
|
|||
|
||||
const part = grid.features.some(f => f.land && f.border); // if land goes over map borders
|
||||
const max = part ? 80 : 100; // max size
|
||||
const lat = () => gauss(P(0.5) ? 40 : 60, 15, 25, 75); // latitude shift
|
||||
const lat = () => gauss(P(0.5) ? 40 : 60, 20, 25, 75); // latitude shift
|
||||
|
||||
if (!part) {
|
||||
if (template === "Pangea") return [100, 50];
|
||||
|
|
@ -1003,30 +1007,49 @@ function calculateMapCoordinates() {
|
|||
mapCoordinates = {latT, latN, latS, lonT: lon * 2, lonW: -lon, lonE: lon};
|
||||
}
|
||||
|
||||
// temperature model
|
||||
// temperature model, trying to follow real-world data
|
||||
// based on http://www-das.uwyo.edu/~geerts/cwx/notes/chap16/Image64.gif
|
||||
function calculateTemperatures() {
|
||||
TIME && console.time("calculateTemperatures");
|
||||
const cells = grid.cells;
|
||||
cells.temp = new Int8Array(cells.i.length); // temperature array
|
||||
|
||||
const tEq = +temperatureEquatorInput.value;
|
||||
const tPole = +temperaturePoleInput.value;
|
||||
const tDelta = tEq - tPole;
|
||||
const int = d3.easePolyInOut.exponent(0.5); // interpolation function
|
||||
const {temperatureEquator, temperatureNorthPole, temperatureSouthPole} = options;
|
||||
const tropics = [16, -20]; // tropics zone
|
||||
const tropicalGradient = 0.15;
|
||||
|
||||
d3.range(0, cells.i.length, grid.cellsX).forEach(function (r) {
|
||||
const y = grid.points[r][1];
|
||||
const lat = Math.abs(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT); // [0; 90]
|
||||
const initTemp = tEq - int(lat / 90) * tDelta;
|
||||
for (let i = r; i < r + grid.cellsX; i++) {
|
||||
cells.temp[i] = minmax(initTemp - convertToFriendly(cells.h[i]), -128, 127);
|
||||
const tempNorthTropic = temperatureEquator - tropics[0] * tropicalGradient;
|
||||
const northernGradient = (tempNorthTropic - temperatureNorthPole) / (90 - tropics[0]);
|
||||
|
||||
const tempSouthTropic = temperatureEquator + tropics[1] * tropicalGradient;
|
||||
const southernGradient = (tempSouthTropic - temperatureSouthPole) / (90 + tropics[1]);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// temperature decreases by 6.5 degree C per 1km
|
||||
function convertToFriendly(h) {
|
||||
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 exponent = +heightExponentInput.value;
|
||||
const height = Math.pow(h - 18, exponent);
|
||||
return rn((height / 1000) * 6.5);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,8 +108,6 @@ function getSettings() {
|
|||
urbanization: urbanization,
|
||||
mapSize: mapSizeOutput.value,
|
||||
latitudeO: latitudeOutput.value,
|
||||
temperatureEquator: temperatureEquatorOutput.value,
|
||||
temperaturePole: temperaturePoleOutput.value,
|
||||
prec: precOutput.value,
|
||||
options: options,
|
||||
mapName: mapName.value,
|
||||
|
|
|
|||
|
|
@ -218,10 +218,13 @@ async function parseLoadedData(data) {
|
|||
if (settings[13]) urbanization = urbanizationInput.value = urbanizationOutput.value = settings[13];
|
||||
if (settings[14]) mapSizeInput.value = mapSizeOutput.value = minmax(settings[14], 1, 100);
|
||||
if (settings[15]) latitudeInput.value = latitudeOutput.value = minmax(settings[15], 0, 100);
|
||||
if (settings[16]) temperatureEquatorInput.value = temperatureEquatorOutput.value = settings[16];
|
||||
if (settings[17]) temperaturePoleInput.value = temperaturePoleOutput.value = settings[17];
|
||||
if (settings[18]) precInput.value = precOutput.value = settings[18];
|
||||
|
||||
if (settings[19]) options = JSON.parse(settings[19]);
|
||||
// setting 16 and 17 (temperature) are part of options now
|
||||
if (settings[16]) options.temperatureEquator = Number(settings[16]);
|
||||
if (settings[17]) options.temperatureNorthPole = options.temperatureSouthPole = Number(settings[17]);
|
||||
|
||||
if (settings[20]) mapName.value = settings[20];
|
||||
if (settings[21]) hideLabels.checked = +settings[21];
|
||||
if (settings[22]) stylePreset.value = settings[22];
|
||||
|
|
@ -231,6 +234,9 @@ async function parseLoadedData(data) {
|
|||
|
||||
void (function applyOptionsToUI() {
|
||||
stateLabelsModeInput.value = options.stateLabelsMode;
|
||||
yearInput.value = options.year;
|
||||
eraInput.value = options.era;
|
||||
shapeRendering.value = viewbox.attr("shape-rendering") || "geometricPrecision";
|
||||
})();
|
||||
|
||||
void (function parseConfiguration() {
|
||||
|
|
@ -586,11 +592,6 @@ async function parseLoadedData(data) {
|
|||
if (rulers && layerIsOn("toggleRulers")) rulers.draw();
|
||||
if (layerIsOn("toggleGrid")) drawGrid();
|
||||
|
||||
// set options
|
||||
yearInput.value = options.year;
|
||||
eraInput.value = options.era;
|
||||
shapeRendering.value = viewbox.attr("shape-rendering") || "geometricPrecision";
|
||||
|
||||
if (window.restoreDefaultEvents) restoreDefaultEvents();
|
||||
focusOn(); // based on searchParams focus on point, cell or burg
|
||||
invokeActiveZooming();
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ function getMapData() {
|
|||
urbanization,
|
||||
mapSizeOutput.value,
|
||||
latitudeOutput.value,
|
||||
temperatureEquatorOutput.value,
|
||||
temperaturePoleOutput.value,
|
||||
0, // previously used for temperatureEquatorOutput.value
|
||||
0, // previously used for tempNorthOutput.value
|
||||
precOutput.value,
|
||||
JSON.stringify(options),
|
||||
mapName.value,
|
||||
|
|
|
|||
|
|
@ -559,11 +559,10 @@ function applyStoredOptions() {
|
|||
if (key.slice(0, 5) === "style") applyOption(stylePreset, key, key.slice(5));
|
||||
}
|
||||
|
||||
if (stored("winds"))
|
||||
options.winds = localStorage
|
||||
.getItem("winds")
|
||||
.split(",")
|
||||
.map(w => +w);
|
||||
if (stored("winds")) options.winds = localStorage.getItem("winds").split(",").map(Number);
|
||||
if (stored("temperatureEquator")) options.temperatureEquator = +localStorage.getItem("temperatureEquator");
|
||||
if (stored("temperatureNorthPole")) options.temperatureNorthPole = +localStorage.getItem("temperatureNorthPole");
|
||||
if (stored("temperatureSouthPole")) options.temperatureSouthPole = +localStorage.getItem("temperatureSouthPole");
|
||||
if (stored("military")) options.military = JSON.parse(stored("military"));
|
||||
|
||||
if (stored("tooltipSize")) changeTooltipSize(stored("tooltipSize"));
|
||||
|
|
@ -607,13 +606,10 @@ function randomizeOptions() {
|
|||
if (randomize || !locked("culturesSet")) randomizeCultureSet();
|
||||
|
||||
// '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);
|
||||
const tMax = 30,
|
||||
tMin = -30; // temperature extremes
|
||||
if (randomize || !locked("temperatureEquator"))
|
||||
temperatureEquatorOutput.value = temperatureEquatorInput.value = rand(tMax - 10, tMax);
|
||||
if (randomize || !locked("temperaturePole"))
|
||||
temperaturePoleOutput.value = temperaturePoleInput.value = rand(tMin, tMin + 30);
|
||||
|
||||
// 'Units Editor' settings
|
||||
const US = navigator.language === "en-US";
|
||||
|
|
@ -1072,8 +1068,7 @@ function toggle3dOptions() {
|
|||
document.getElementById("options3dGlobeResolution").addEventListener("change", changeResolution);
|
||||
// document.getElementById("options3dMeshWireframeMode").addEventListener("change",toggleWireframe3d);
|
||||
document.getElementById("options3dSunColor").addEventListener("input", changeSunColor);
|
||||
document.getElementById("options3dSubdivide").addEventListener("change",toggle3dSubdivision);
|
||||
|
||||
document.getElementById("options3dSubdivide").addEventListener("change", toggle3dSubdivision);
|
||||
|
||||
function updateValues() {
|
||||
const globe = document.getElementById("canvas3d").dataset.type === "viewGlobe";
|
||||
|
|
@ -1113,7 +1108,7 @@ function toggle3dOptions() {
|
|||
ThreeD.setLightness(this.value / 100);
|
||||
}
|
||||
|
||||
function changeSunColor(){
|
||||
function changeSunColor() {
|
||||
ThreeD.setSunColor(options3dSunColor.value);
|
||||
}
|
||||
|
||||
|
|
@ -1134,7 +1129,7 @@ function toggle3dOptions() {
|
|||
ThreeD.toggleLabels();
|
||||
}
|
||||
|
||||
function toggle3dSubdivision(){
|
||||
function toggle3dSubdivision() {
|
||||
ThreeD.toggle3dSubdivision();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
function editWorld() {
|
||||
if (customization) return;
|
||||
|
||||
$("#worldConfigurator").dialog({
|
||||
title: "Configure World",
|
||||
resizable: false,
|
||||
|
|
@ -8,8 +9,7 @@ function editWorld() {
|
|||
"Whole World": () => applyWorldPreset(100, 50),
|
||||
Northern: () => applyWorldPreset(33, 25),
|
||||
Tropical: () => applyWorldPreset(33, 50),
|
||||
Southern: () => applyWorldPreset(33, 75),
|
||||
"Restore Winds": restoreDefaultWinds
|
||||
Southern: () => applyWorldPreset(33, 75)
|
||||
},
|
||||
open: function () {
|
||||
const buttons = $(this).dialog("widget").find(".ui-dialog-buttonset > button");
|
||||
|
|
@ -17,7 +17,6 @@ function editWorld() {
|
|||
buttons[1].addEventListener("mousemove", () => tip("Click to set map size to cover the Northern latitudes"));
|
||||
buttons[2].addEventListener("mousemove", () => tip("Click to set map size to cover the Tropical latitudes"));
|
||||
buttons[3].addEventListener("mousemove", () => tip("Click to set map size to cover the Southern latitudes"));
|
||||
buttons[4].addEventListener("mousemove", () => tip("Click to restore default wind directions"));
|
||||
},
|
||||
close: function () {
|
||||
$(this).dialog("destroy");
|
||||
|
|
@ -25,28 +24,56 @@ function editWorld() {
|
|||
});
|
||||
|
||||
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 path = d3.geoPath(projection);
|
||||
|
||||
updateInputValues();
|
||||
updateGlobeTemperature();
|
||||
updateGlobePosition();
|
||||
|
||||
if (modules.editWorld) return;
|
||||
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("#globeGraticule").attr("d", round(path(d3.geoGraticule()()))); // globe graticule
|
||||
updateWindDirections();
|
||||
|
||||
byId("restoreWinds").addEventListener("click", restoreDefaultWinds);
|
||||
|
||||
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) {
|
||||
if (el) {
|
||||
document.getElementById(el.dataset.stored + "Input").value = el.value;
|
||||
document.getElementById(el.dataset.stored + "Output").value = el.value;
|
||||
if (el.dataset.stored) lock(el.dataset.stored);
|
||||
if (el?.dataset.stored) {
|
||||
const stored = el.dataset.stored;
|
||||
byId(stored + "Input").value = el.value;
|
||||
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();
|
||||
|
|
@ -65,11 +92,11 @@ function editWorld() {
|
|||
if (layerIsOn("toggleBiomes")) drawBiomes();
|
||||
if (layerIsOn("toggleCoordinates")) drawCoordinates();
|
||||
if (layerIsOn("toggleRivers")) drawRivers();
|
||||
if (document.getElementById("canvas3d")) setTimeout(ThreeD.update(), 500);
|
||||
if (byId("canvas3d")) setTimeout(ThreeD.update(), 500);
|
||||
}
|
||||
|
||||
function updateGlobePosition() {
|
||||
const size = +document.getElementById("mapSizeOutput").value;
|
||||
const size = +byId("mapSizeOutput").value;
|
||||
const eqD = ((graphHeight / 2) * 100) / size;
|
||||
|
||||
calculateMapCoordinates();
|
||||
|
|
@ -77,12 +104,12 @@ function editWorld() {
|
|||
const scale = +distanceScaleInput.value;
|
||||
const unit = distanceUnitInput.value;
|
||||
const meridian = toKilometer(eqD * 2 * scale);
|
||||
document.getElementById("mapSize").innerHTML = `${graphWidth}x${graphHeight}`;
|
||||
document.getElementById("mapSizeFriendly").innerHTML = `${rn(graphWidth * scale)}x${rn(graphHeight * scale)} ${unit}`;
|
||||
document.getElementById("meridianLength").innerHTML = rn(eqD * 2);
|
||||
document.getElementById("meridianLengthFriendly").innerHTML = `${rn(eqD * 2 * scale)} ${unit}`;
|
||||
document.getElementById("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("mapSize").innerHTML = `${graphWidth}x${graphHeight}`;
|
||||
byId("mapSizeFriendly").innerHTML = `${rn(graphWidth * scale)}x${rn(graphHeight * scale)} ${unit}`;
|
||||
byId("meridianLength").innerHTML = rn(eqD * 2);
|
||||
byId("meridianLengthFriendly").innerHTML = `${rn(eqD * 2 * scale)} ${unit}`;
|
||||
byId("meridianLengthEarth").innerHTML = meridian ? " = " + rn(meridian / 200) + "%🌏" : "";
|
||||
byId("mapCoordinates").innerHTML = `${lat(mc.latN)} ${Math.abs(rn(mc.lonW))}°W; ${lat(mc.latS)} ${rn(mc.lonE)}°E`;
|
||||
|
||||
function toKilometer(v) {
|
||||
if (unit === "km") return v;
|
||||
|
|
@ -104,15 +131,24 @@ function editWorld() {
|
|||
globe.select("#globeArea").attr("d", round(path(area.outline()))); // map area
|
||||
}
|
||||
|
||||
// update temperatures on globe (visual-only)
|
||||
function updateGlobeTemperature() {
|
||||
const tEq = +document.getElementById("temperatureEquatorOutput").value;
|
||||
document.getElementById("temperatureEquatorF").innerHTML = rn((tEq * 9) / 5 + 32);
|
||||
const tPole = +document.getElementById("temperaturePoleOutput").value;
|
||||
document.getElementById("temperaturePoleF").innerHTML = rn((tPole * 9) / 5 + 32);
|
||||
globe.selectAll(".tempGradient90").attr("stop-color", clr(1 - (tPole - tMin) / (tMax - tMin)));
|
||||
globe.selectAll(".tempGradient60").attr("stop-color", clr(1 - (tEq - ((tEq - tPole) * 2) / 3 - tMin) / (tMax - tMin)));
|
||||
globe.selectAll(".tempGradient30").attr("stop-color", clr(1 - (tEq - ((tEq - tPole) * 1) / 3 - tMin) / (tMax - tMin)));
|
||||
globe.select(".tempGradient0").attr("stop-color", clr(1 - (tEq - tMin) / (tMax - tMin)));
|
||||
const tEq = options.temperatureEquator;
|
||||
const tNP = options.temperatureNorthPole;
|
||||
const tSP = options.temperatureSouthPole;
|
||||
|
||||
const scale = d3.scaleSequential(d3.interpolateSpectral);
|
||||
const getColor = value => scale(1 - value);
|
||||
const [tMin, tMax] = [-25, 30]; // temperature extremes
|
||||
const tDelta = tMax - tMin;
|
||||
|
||||
globe.select("#grad90").attr("stop-color", getColor((tNP - tMin) / tDelta));
|
||||
globe.select("#grad60").attr("stop-color", getColor((tEq - ((tEq - tNP) * 2) / 3 - tMin) / tDelta));
|
||||
globe.select("#grad30").attr("stop-color", getColor((tEq - ((tEq - tNP) * 1) / 4 - tMin) / tDelta));
|
||||
globe.select("#grad0").attr("stop-color", getColor((tEq - tMin) / tDelta));
|
||||
globe.select("#grad-30").attr("stop-color", getColor((tEq - ((tEq - tSP) * 1) / 4 - 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() {
|
||||
|
|
@ -146,8 +182,8 @@ function editWorld() {
|
|||
}
|
||||
|
||||
function applyWorldPreset(size, lat) {
|
||||
document.getElementById("mapSizeInput").value = document.getElementById("mapSizeOutput").value = size;
|
||||
document.getElementById("latitudeInput").value = document.getElementById("latitudeOutput").value = lat;
|
||||
byId("mapSizeInput").value = byId("mapSizeOutput").value = size;
|
||||
byId("latitudeInput").value = byId("latitudeOutput").value = lat;
|
||||
lock("mapSize");
|
||||
lock("latitude");
|
||||
updateWorld();
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ const temperatureConversionMap = {
|
|||
"°Rø": temp => rn((temp * 21) / 40 + 7.5) + "°Rø"
|
||||
};
|
||||
|
||||
function convertTemperature(temp) {
|
||||
const scale = temperatureScale.value || "°C";
|
||||
function convertTemperature(temp, scale = temperatureScale.value || "°C") {
|
||||
return temperatureConversionMap[scale](temp);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
// version and caching control
|
||||
|
||||
const version = "1.89.39"; // generator version, update each time
|
||||
const version = "1.90.00"; // generator version, update each time
|
||||
|
||||
{
|
||||
document.title += " v" + version;
|
||||
|
|
@ -29,17 +28,16 @@ const version = "1.89.39"; // generator version, update each time
|
|||
|
||||
<ul>
|
||||
<strong>Latest changes:</strong>
|
||||
<li>North and South Poles temperature can be set independently</li>
|
||||
<li>More than 70 new heraldic charges</li>
|
||||
<li>Multi-color heraldic charges support</li>
|
||||
<li>New 3D scene options</li>
|
||||
<li>New 3D scene options and improvements</li>
|
||||
<li>Autosave feature (in Options)</li>
|
||||
<li>Google translation support (in Options)</li>
|
||||
<li>Religions can be edited and redrawn like cultures</li>
|
||||
<li>Lock states, provinces, cultures, and religions from regeneration</li>
|
||||
<li>Heightmap brushes: linear edit option</li>
|
||||
<li>Data Charts screen</li>
|
||||
<li>Сultures and religions can have multiple parents in hierarchy tree</li>
|
||||
<li>Heightmap selection screen</li>
|
||||
</ul>
|
||||
|
||||
<p>Join our <a href="${discord}" target="_blank">Discord server</a> and <a href="${reddit}" target="_blank">Reddit community</a> to ask questions, share maps, discuss the Generator and Worlbuilding, report bugs and propose new features.</p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue