Сonfigurable longitude (#1095)

* feat: configurable longitude

* chore: update version

---------

Co-authored-by: Azgaar <azgaar.fmg@yandex.com>
This commit is contained in:
Azgaar 2024-07-12 12:26:03 +02:00 committed by GitHub
parent 075580da1a
commit e9ee6967ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 118 additions and 81 deletions

View file

@ -2248,10 +2248,6 @@ svg.button {
fill: blue;
}
#globeOutline {
fill: url(#temperatureGradient);
}
#globeArea {
fill: white;
fill-opacity: 0.3;
@ -2262,6 +2258,11 @@ svg.button {
stroke-width: 0.2;
}
#globePrimeMeridian {
stroke: blue;
stroke-width: 1.4;
}
#globeEquator {
stroke: red;
stroke-width: 1.4;

View file

@ -138,7 +138,7 @@
}
</style>
<link rel="preload" href="index.css?v=1.97.16" as="style" onload="this.onload=null; this.rel='stylesheet'" />
<link rel="preload" href="index.css?v=1.98.01" as="style" onload="this.onload=null; this.rel='stylesheet'" />
<link rel="preload" href="icons.css" as="style" onload="this.onload=null; this.rel='stylesheet'" />
<link rel="preload" href="libs/jquery-ui.css" as="style" onload="this.onload=null; this.rel='stylesheet'" />
</head>
@ -2534,15 +2534,15 @@
<i data-locked="0" id="lock_mapSize" class="icon-lock-open"></i>
<label data-tip="Set map size relative to the world size">
<i>Map size:</i>
<input id="mapSizeInput" data-stored="mapSize" type="number" min="1" max="100" />%
<input id="mapSizeOutput" data-stored="mapSize" type="range" min="1" max="100" />
<input id="mapSizeInput" data-stored="mapSize" type="number" min="1" max="100" step="0.1" />%
<input id="mapSizeOutput" data-stored="mapSize" type="range" min="1" max="100" step="0.1" />
</label>
</div>
<div>
<i data-locked="0" id="lock_latitude" class="icon-lock-open"></i>
<label data-tip="Set a North-South map shift">
<label data-tip="Set a North-South map shift, set to 50 to make map center lie on Equator">
<i>Latitudes:</i>
<input id="latitudeInput" data-stored="latitude" type="number" min="0" max="100" step="1" />
<input id="latitudeInput" data-stored="latitude" type="number" min="0" max="100" step="0.1" />
<br /><i>N</i
><input
id="latitudeOutput"
@ -2550,12 +2550,38 @@
type="range"
min="0"
max="100"
step="1"
step="0.1"
style="width: 10.3em"
/><i>S</i>
</label>
</div>
<div>
<i data-locked="0" id="lock_longitude" class="icon-lock-open"></i>
<label data-tip="Set a West-East map shift, set to 50 to make map center lie on Prime meridian">
<i>Longitudes:</i>
<input
id="longitudeInput"
data-stored="longitude"
type="number"
min="0"
max="100"
value="50"
step="0.1"
/>
<br /><i>W</i
><input
id="longitudeOutput"
data-stored="longitude"
type="range"
min="0"
max="100"
step="0.1"
style="width: 10.3em"
/><i>E</i>
</label>
</div>
<div>
<label
data-tip="Set precipitation - water amount clouds can bring. Defines rivers and biomes generation. Keep around 100% for default generation"
@ -2634,8 +2660,10 @@
<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" />
<circle id="globeGradient" cx="100" cy="100" r="100" fill="url(#temperatureGradient)" stroke="none" />
<line id="globePrimeMeridian" x1="100" x2="100" y1="0" y2="200" />
<line id="globeEquator" x1="1" x2="200" y1="100" y2="100" />
<circle id="globeOutline" cx="100" cy="100" r="100" fill="none" />
<path id="globeGraticule" />
<path id="globeArea" />
</svg>
@ -8081,15 +8109,15 @@
<script src="modules/ui/measurers.js?v=1.96.00"></script>
<script src="modules/ui/stylePresets.js?v=1.96.00"></script>
<script src="modules/ui/general.js?v=1.96.00"></script>
<script src="modules/ui/general.js?v=1.98.01"></script>
<script src="modules/ui/options.js?v=1.97.14"></script>
<script src="main.js?v=1.98.00"></script>
<script src="main.js?v=1.98.01"></script>
<script defer src="modules/relief-icons.js"></script>
<script defer src="modules/ui/style.js?v=1.96.00"></script>
<script defer src="modules/ui/editors.js?v=1.97.12"></script>
<script defer src="modules/ui/tools.js?v=1.97.12"></script>
<script defer src="modules/ui/world-configurator.js?v=1.97.16"></script>
<script defer src="modules/ui/world-configurator.js?v=1.98.01"></script>
<script defer src="modules/ui/heightmap-editor.js?v=1.96.00"></script>
<script defer src="modules/ui/provinces-editor.js?v=1.96.00"></script>
<script defer src="modules/ui/biomes-editor.js?v=1.91.05"></script>
@ -8124,10 +8152,10 @@
<script defer src="modules/coa-renderer.js?v=1.94.00"></script>
<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.96.00"></script>
<script defer src="modules/io/load.js?v=1.98.00"></script>
<script defer src="modules/io/save.js?v=1.98.01"></script>
<script defer src="modules/io/load.js?v=1.98.01"></script>
<script defer src="modules/io/cloud.js?v=1.96.00"></script>
<script defer src="modules/io/export.js?v=1.98.00"></script>
<script defer src="modules/io/export.js?v=1.98.01"></script>
<!-- Web Components -->
<script defer src="components/fill-box.js"></script>

120
main.js
View file

@ -198,10 +198,10 @@ let options = {
};
let mapCoordinates = {}; // map coordinates on globe
let populationRate = +document.getElementById("populationRateInput").value;
let distanceScale = +document.getElementById("distanceScaleInput").value;
let urbanization = +document.getElementById("urbanizationInput").value;
let urbanDensity = +document.getElementById("urbanDensityInput").value;
let populationRate = +byId("populationRateInput").value;
let distanceScale = +byId("distanceScaleInput").value;
let urbanization = +byId("urbanizationInput").value;
let urbanDensity = +byId("urbanDensityInput").value;
applyStoredOptions();
@ -442,10 +442,10 @@ function handleZoom(isScaleChanged, isPositionChanged) {
// zoom image converter overlay
if (customization === 1) {
const canvas = document.getElementById("canvas");
const canvas = byId("canvas");
if (!canvas || canvas.style.opacity === "0") return;
const img = document.getElementById("imageToConvert");
const img = byId("imageToConvert");
if (!img) return;
const ctx = canvas.getContext("2d");
@ -527,7 +527,7 @@ function invokeActiveZooming() {
+markers.attr("rescale") &&
pack.markers?.forEach(marker => {
const {i, x, y, size = 30, hidden} = marker;
const el = !hidden && document.getElementById(`marker${i}`);
const el = !hidden && byId(`marker${i}`);
if (!el) return;
const zoomedSize = Math.max(rn(size / 5 + 24 / scale, 2), 1);
@ -564,18 +564,18 @@ void (function addDragToUpload() {
document.addEventListener("dragover", function (e) {
e.stopPropagation();
e.preventDefault();
document.getElementById("mapOverlay").style.display = null;
byId("mapOverlay").style.display = null;
});
document.addEventListener("dragleave", function (e) {
document.getElementById("mapOverlay").style.display = "none";
byId("mapOverlay").style.display = "none";
});
document.addEventListener("drop", function (e) {
e.stopPropagation();
e.preventDefault();
const overlay = document.getElementById("mapOverlay");
const overlay = byId("mapOverlay");
overlay.style.display = "none";
if (e.dataTransfer.items == null || e.dataTransfer.items.length !== 1) return; // no files or more than one
const file = e.dataTransfer.items[0].getAsFile();
@ -782,7 +782,7 @@ function addLakesInDeepDepressions() {
TIME && console.time("addLakesInDeepDepressions");
const {cells, features} = grid;
const {c, h, b} = cells;
const ELEVATION_LIMIT = +document.getElementById("lakeElevationLimitOutput").value;
const ELEVATION_LIMIT = +byId("lakeElevationLimitOutput").value;
if (ELEVATION_LIMIT === 80) return;
for (const i of cells.i) {
@ -882,73 +882,77 @@ function openNearSeaLakes() {
// define map size and position based on template and random factor
function defineMapSize() {
const [size, latitude] = getSizeAndLatitude();
const [size, latitude, longitude] = getSizeAndLatitude();
const randomize = new URL(window.location.href).searchParams.get("options") === "default"; // ignore stored options
if (randomize || !locked("mapSize")) mapSizeOutput.value = mapSizeInput.value = rn(size);
if (randomize || !locked("latitude")) latitudeOutput.value = latitudeInput.value = rn(latitude);
if (randomize || !locked("mapSize")) mapSizeOutput.value = mapSizeInput.value = size;
if (randomize || !locked("latitude")) latitudeOutput.value = latitudeInput.value = latitude;
if (randomize || !locked("longitude")) longitudeOutput.value = longitudeInput.value = longitude;
function getSizeAndLatitude() {
const template = byId("templateInput").value; // heightmap template
if (template === "africa-centric") return [45, 53];
if (template === "arabia") return [20, 35];
if (template === "atlantics") return [42, 23];
if (template === "britain") return [7, 20];
if (template === "caribbean") return [15, 40];
if (template === "east-asia") return [11, 28];
if (template === "eurasia") return [38, 19];
if (template === "europe") return [20, 16];
if (template === "europe-accented") return [14, 22];
if (template === "europe-and-central-asia") return [25, 10];
if (template === "europe-central") return [11, 22];
if (template === "europe-north") return [7, 18];
if (template === "greenland") return [22, 7];
if (template === "hellenica") return [8, 27];
if (template === "iceland") return [2, 15];
if (template === "indian-ocean") return [45, 55];
if (template === "mediterranean-sea") return [10, 29];
if (template === "middle-east") return [8, 31];
if (template === "north-america") return [37, 17];
if (template === "us-centric") return [66, 27];
if (template === "us-mainland") return [16, 30];
if (template === "world") return [78, 27];
if (template === "world-from-pacific") return [75, 32];
if (template === "africa-centric") return [45, 53, 38];
if (template === "arabia") return [20, 35, 35];
if (template === "atlantics") return [42, 23, 65];
if (template === "britain") return [7, 20, 51.3];
if (template === "caribbean") return [15, 40, 74.8];
if (template === "east-asia") return [11, 28, 9.4];
if (template === "eurasia") return [38, 19, 27];
if (template === "europe") return [20, 16, 44.8];
if (template === "europe-accented") return [14, 22, 44.8];
if (template === "europe-and-central-asia") return [25, 10, 39.5];
if (template === "europe-central") return [11, 22, 46.4];
if (template === "europe-north") return [7, 18, 48.9];
if (template === "greenland") return [22, 7, 55.8];
if (template === "hellenica") return [8, 27, 43.5];
if (template === "iceland") return [2, 15, 55.3];
if (template === "indian-ocean") return [45, 55, 14];
if (template === "mediterranean-sea") return [10, 29, 45.8];
if (template === "middle-east") return [8, 31, 34.4];
if (template === "north-america") return [37, 17, 87];
if (template === "us-centric") return [66, 27, 100];
if (template === "us-mainland") return [16, 30, 77.5];
if (template === "world") return [78, 27, 40];
if (template === "world-from-pacific") return [75, 32, 30]; // longitude doesn't fit
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, 20, 25, 75); // latitude shift
if (!part) {
if (template === "Pangea") return [100, 50];
if (template === "Shattered" && P(0.7)) return [100, 50];
if (template === "Continents" && P(0.5)) return [100, 50];
if (template === "Archipelago" && P(0.35)) return [100, 50];
if (template === "High Island" && P(0.25)) return [100, 50];
if (template === "Low Island" && P(0.1)) return [100, 50];
if (template === "pangea") return [100, 50, 50];
if (template === "shattered" && P(0.7)) return [100, 50, 50];
if (template === "continents" && P(0.5)) return [100, 50, 50];
if (template === "archipelago" && P(0.35)) return [100, 50, 50];
if (template === "highIsland" && P(0.25)) return [100, 50, 50];
if (template === "lowIsland" && P(0.1)) return [100, 50, 50];
}
if (template === "Pangea") return [gauss(70, 20, 30, max), lat()];
if (template === "Volcano") return [gauss(20, 20, 10, max), lat()];
if (template === "Mediterranean") return [gauss(25, 30, 15, 80), lat()];
if (template === "Peninsula") return [gauss(15, 15, 5, 80), lat()];
if (template === "Isthmus") return [gauss(15, 20, 3, 80), lat()];
if (template === "Atoll") return [gauss(5, 10, 2, max), lat()];
if (template === "pangea") return [gauss(70, 20, 30, max), lat(), 50];
if (template === "volcano") return [gauss(20, 20, 10, max), lat(), 50];
if (template === "mediterranean") return [gauss(25, 30, 15, 80), lat(), 50];
if (template === "peninsula") return [gauss(15, 15, 5, 80), lat(), 50];
if (template === "isthmus") return [gauss(15, 20, 3, 80), lat(), 50];
if (template === "atoll") return [gauss(3, 2, 1, 5, 1), lat(), 50];
return [gauss(30, 20, 15, max), lat()]; // Continents, Archipelago, High Island, Low Island
return [gauss(30, 20, 15, max), lat(), 50]; // Continents, Archipelago, High Island, Low Island
}
}
// calculate map position on globe
function calculateMapCoordinates() {
const size = +document.getElementById("mapSizeOutput").value;
const latShift = +document.getElementById("latitudeOutput").value;
const sizeFraction = +byId("mapSizeOutput").value / 100;
const latShift = +byId("latitudeOutput").value / 100;
const lonShift = +byId("longitudeOutput").value / 100;
const latT = rn((size / 100) * 180, 1);
const latN = rn(90 - ((180 - latT) * latShift) / 100, 1);
const latT = rn(sizeFraction * 180, 1);
const latN = rn(90 - (180 - latT) * latShift, 1);
const latS = rn(latN - latT, 1);
const lon = rn(Math.min(((graphWidth / graphHeight) * latT) / 2, 180));
mapCoordinates = {latT, latN, latS, lonT: lon * 2, lonW: -lon, lonE: lon};
const lonT = rn(Math.min((graphWidth / graphHeight) * latT, 360), 1);
const lonE = rn(180 - (360 - lonT) * lonShift, 1);
const lonW = rn(lonE - lonT, 1);
mapCoordinates = {latT, latN, latS, lonT, lonW, lonE};
}
// temperature model, trying to follow real-world data
@ -1750,7 +1754,7 @@ function addZones(number = 1) {
}
function addEruption() {
const volcano = document.getElementById("markers").querySelector("use[data-id='#marker_volcano']");
const volcano = byId("markers").querySelector("use[data-id='#marker_volcano']");
if (!volcano) return;
const x = +volcano.dataset.x,
@ -1969,7 +1973,7 @@ function undraw() {
.getElementById("deftemp")
.querySelectorAll("path, clipPath, svg")
.forEach(el => el.remove());
document.getElementById("coas").innerHTML = ""; // remove auto-generated emblems
byId("coas").innerHTML = ""; // remove auto-generated emblems
notes = [];
rulers = new Rulers();
unfog();

View file

@ -93,7 +93,8 @@ function getSettings() {
populationRate: populationRate,
urbanization: urbanization,
mapSize: mapSizeOutput.value,
latitudeO: latitudeOutput.value,
latitude: latitudeOutput.value,
longitude: longitudeOutput.value,
prec: precOutput.value,
options: options,
mapName: mapName.value,

View file

@ -242,6 +242,7 @@ async function parseLoadedData(data, mapVersion) {
if (settings[22]) stylePreset.value = settings[22];
if (settings[23]) rescaleLabels.checked = +settings[23];
if (settings[24]) urbanDensity = urbanDensityInput.value = urbanDensityOutput.value = +settings[24];
if (settings[25]) longitudeInput.value = longitudeOutput.value = minmax(settings[25] || 50, 0, 100);
})();
void (function applyOptionsToUI() {

View file

@ -67,7 +67,8 @@ function prepareMapData() {
+hideLabels.checked,
stylePreset.value,
+rescaleLabels.checked,
urbanDensity
urbanDensity,
longitudeOutput.value
].join("|");
const coords = JSON.stringify(mapCoordinates);
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");

View file

@ -285,7 +285,7 @@ function toDMS(coord, c) {
const minutes = Math.floor(minutesNotTruncated);
const seconds = Math.floor((minutesNotTruncated - minutes) * 60);
const cardinal = c === "lat" ? (coord >= 0 ? "N" : "S") : coord >= 0 ? "E" : "W";
return degrees + " + minutes + " " + seconds + "″ " + cardinal;
return degrees + " + minutes + "" + seconds + "″" + cardinal;
}
// get surface elevation

View file

@ -33,8 +33,9 @@ function editWorld() {
if (modules.editWorld) return;
modules.editWorld = true;
const graticule = d3.geoGraticule();
globe.select("#globeWindArrows").on("click", handleWindChange);
globe.select("#globeGraticule").attr("d", round(path(d3.geoGraticule()()))); // globe graticule
globe.select("#globeGraticule").attr("d", round(path(graticule()))); // globe graticule
updateWindDirections();
byId("worldControls").on("input", handleControlsChange);

View file

@ -1,7 +1,7 @@
"use strict";
// version and caching control
const version = "1.98.00"; // generator version, update each time
const version = "1.98.01"; // generator version, update each time
{
document.title += " v" + version;