refactor dialogs to be mobile-friendly

This commit is contained in:
Azgaar 2022-05-28 01:47:25 +03:00
parent 8b1778cb93
commit 8a9a29a9d3
16 changed files with 402 additions and 373 deletions

View file

@ -16,7 +16,6 @@ export function open() {
$("#culturesEditor").dialog({
title: "Cultures Editor",
resizable: false,
width: fitContent(),
close: closeCulturesEditor,
position: {my: "right top", at: "right-10 top+10", of: "svg"}
});
@ -25,15 +24,15 @@ export function open() {
function insertEditorHtml() {
const editorHtml = /* html */ `<div id="culturesEditor" class="dialog stable">
<div id="culturesHeader" class="header">
<div style="left: 1.8em" data-tip="Click to sort by culture name" class="sortable alphabetically" data-sortby="name">Culture&nbsp;</div>
<div style="left: 9.9em" data-tip="Click to sort by type" class="sortable alphabetically" data-sortby="type">Type&nbsp;</div>
<div style="left: 16.2em" data-tip="Click to sort by culture namesbase" class="sortable" data-sortby="base">Namesbase&nbsp;</div>
<div style="left: 24.5em" data-tip="Click to sort by culture cells count" class="sortable hide" data-sortby="cells">Cells&nbsp;</div>
<div style="left: 29.8em" data-tip="Click to sort by expansionism" class="sortable hide" data-sortby="expansionism">Expansion&nbsp;</div>
<div style="left: 37.2em" data-tip="Click to sort by culture area" class="sortable hide" data-sortby="area">Area&nbsp;</div>
<div style="left: 42.8em" data-tip="Click to sort by culture population" class="sortable hide icon-sort-number-down" data-sortby="population">Population&nbsp;</div>
<div style="left: 50.8em" data-tip="Click to sort by culture emblems shape" class="sortable alphabetically hide" data-sortby="emblems">Emblems&nbsp;</div>
<div id="culturesHeader" class="header" style="grid-template-columns: 10em 7em 8em 4em 8em 5em 8em 8em">
<div data-tip="Click to sort by culture name" class="sortable alphabetically" data-sortby="name">Culture&nbsp;</div>
<div data-tip="Click to sort by type" class="sortable alphabetically" data-sortby="type">Type&nbsp;</div>
<div data-tip="Click to sort by culture namesbase" class="sortable" data-sortby="base">Namesbase&nbsp;</div>
<div data-tip="Click to sort by culture cells count" class="sortable hide" data-sortby="cells">Cells&nbsp;</div>
<div data-tip="Click to sort by expansionism" class="sortable hide" data-sortby="expansionism">Expansion&nbsp;</div>
<div data-tip="Click to sort by culture area" class="sortable hide" data-sortby="area">Area&nbsp;</div>
<div data-tip="Click to sort by culture population" class="sortable hide icon-sort-number-down" data-sortby="population">Population&nbsp;</div>
<div data-tip="Click to sort by culture emblems shape" class="sortable alphabetically hide" data-sortby="emblems">Emblems&nbsp;</div>
</div>
<div id="culturesBody" class="table" data-type="absolute"></div>

View file

@ -14,7 +14,6 @@ export function open() {
$("#statesEditor").dialog({
title: "States Editor",
resizable: false,
width: fitContent(),
close: closeStatesEditor,
position: {my: "right top", at: "right-10 top+10", of: "svg", collision: "fit"}
});
@ -22,17 +21,17 @@ export function open() {
function insertEditorHtml() {
const editorHtml = /* html */ `<div id="statesEditor" class="dialog stable">
<div id="statesHeader" class="header">
<div style="left: 1.8em" data-tip="Click to sort by state name" class="sortable alphabetically" data-sortby="name">State&nbsp;</div>
<div style="left: 10.8em" data-tip="Click to sort by state form name" class="sortable alphabetically" data-sortby="form">Form&nbsp;</div>
<div style="left: 19.1em" data-tip="Click to sort by capital name" class="sortable alphabetically hide" data-sortby="capital">Capital&nbsp;</div>
<div style="left: 26.1em" data-tip="Click to sort by state dominant culture" class="sortable alphabetically hide" data-sortby="culture">Culture&nbsp;</div>
<div style="left: 33.4em" data-tip="Click to sort by state burgs count" class="sortable hide" data-sortby="burgs">Burgs&nbsp;</div>
<div style="left: 39.6em" data-tip="Click to sort by state area" class="sortable hide icon-sort-number-down" data-sortby="area">Area&nbsp;</div>
<div style="left: 45.9em" data-tip="Click to sort by state population" class="sortable hide" data-sortby="population">Population&nbsp;</div>
<div style="left: 52.2em" data-tip="Click to sort by state type" class="sortable alphabetically hidden show hide" data-sortby="type">Type&nbsp;</div>
<div style="left: 59em" data-tip="Click to sort by state expansion value" class="sortable hidden show hide" data-sortby="expansionism">Expansion&nbsp;</div>
<div style="left: 65.5em" data-tip="Click to sort by state cells count" class="sortable hidden show hide" data-sortby="cells">Cells&nbsp;</div>
<div id="statesHeader" class="header" style="grid-template-columns: 11em 8em 7em 7em 6em 6em 8em 6em 7em 6em">
<div data-tip="Click to sort by state name" class="sortable alphabetically" data-sortby="name">State&nbsp;</div>
<div data-tip="Click to sort by state form name" class="sortable alphabetically" data-sortby="form">Form&nbsp;</div>
<div data-tip="Click to sort by capital name" class="sortable alphabetically hide" data-sortby="capital">Capital&nbsp;</div>
<div data-tip="Click to sort by state dominant culture" class="sortable alphabetically hide" data-sortby="culture">Culture&nbsp;</div>
<div data-tip="Click to sort by state burgs count" class="sortable hide" data-sortby="burgs">Burgs&nbsp;</div>
<div data-tip="Click to sort by state area" class="sortable hide icon-sort-number-down" data-sortby="area">Area&nbsp;</div>
<div data-tip="Click to sort by state population" class="sortable hide" data-sortby="population">Population&nbsp;</div>
<div data-tip="Click to sort by state type" class="sortable alphabetically hidden show hide" data-sortby="type">Type&nbsp;</div>
<div data-tip="Click to sort by state expansion value" class="sortable hidden show hide" data-sortby="expansionism">Expansion&nbsp;</div>
<div data-tip="Click to sort by state cells count" class="sortable hidden show hide" data-sortby="cells">Cells&nbsp;</div>
</div>
<div id="statesBodySection" class="table" data-type="absolute"></div>

View file

@ -41,6 +41,7 @@ const heightmaps = [
{id: "world-from-pacific", name: "World from Pacific"}
];
const initialSeed = generateSeed();
appendStyleSheet();
insertEditorHtml();
addListeners();
@ -107,6 +108,14 @@ function appendStyleSheet() {
}
}
.heightmap-selection_options {
display: grid;
grid-template-columns: repeat(2, minmax(50%, 200px));
grid-row-gap: 6px;
justify-items: start;
align-items: center;
}
.heightmap-selection article {
padding: 4px;
border-radius: 8px;
@ -154,15 +163,49 @@ function appendStyleSheet() {
}
function insertEditorHtml() {
const seed = generateSeed();
const heightmapSelectionHtml = /* html */ `<div id="heightmapSelection" class="dialog stable">
<div class="heightmap-selection">
<section>
<header><h1>Heightmap templates</h1></header>
<div class="heightmap-selection_container"></div>
</section>
<section>
<header><h1>Pre-created heightmaps</h1></header>
<div class="heightmap-selection_container"></div>
</section>
<section>
<header><h1>Options</h1></header>
<div class="heightmap-selection_options">
<div>
<input id="heightmapSelectionRenderOcean" class="checkbox" type="checkbox" />
<label for="heightmapSelectionRenderOcean" class="checkbox-label">Render ocean heights</label>
</div>
<div>
Color scheme
<select id="heightmapSelectionColorScheme">
<option value="bright" selected>Bright</option>
<option value="light">Light</option>
<option value="green">Green</option>
<option value="monochrome">Monochrome</option>
</select>
</div>
<button data-tip="Open Template Editor" id="heightmapSelectionEditTemplates">Edit Templates</button>
<button data-tip="Open Image Converter" id="heightmapSelectionImportHeightmap">Import Heightmap</button>
</div>
</section>
</div>
</div>`;
const templatesHtml = templates
byId("dialogs").insertAdjacentHTML("beforeend", heightmapSelectionHtml);
const sections = document.getElementsByClassName("heightmap-selection_container");
sections[0].innerHTML = templates
.map(({id, name}) => {
Math.random = aleaPRNG(seed);
Math.random = aleaPRNG(initialSeed);
const heights = generateHeightmap(id);
const dataUrl = drawHeights(heights);
return /* html */ `<article data-id="${id}" data-seed="${seed}">
return /* html */ `<article data-id="${id}" data-seed="${initialSeed}">
<img src="${dataUrl}" alt="${name}" />
<div>
${name}
@ -172,35 +215,16 @@ function insertEditorHtml() {
})
.join("");
const heightmapsHtml = heightmaps
sections[1].innerHTML = heightmaps
.map(({id, name}) => {
drawPrecreatedHeightmap(id);
return /* html */ `<article data-id="${id}" data-seed="${seed}">
return /* html */ `<article data-id="${id}" data-seed="${initialSeed}">
<img alt="${name}" />
<div>${name}</div>
</article>`;
})
.join("");
const heightmapSelectionHtml = /* html */ `<div id="heightmapSelection" class="dialog stable">
<div class="heightmap-selection">
<section>
<header><h1>Heightmap templates</h1></header>
<div class="heightmap-selection_container">
${templatesHtml}
</div>
</section>
<section>
<header><h1>Pre-created heightmaps</h1></header>
<div class="heightmap-selection_container">
${heightmapsHtml}
</div>
</section>
</div>
</div>`;
byId("dialogs").insertAdjacentHTML("beforeend", heightmapSelectionHtml);
}
function addListeners() {
@ -209,9 +233,16 @@ function addListeners() {
if (!article) return;
const id = article.dataset.id;
if (event.target.matches("span.icon-cw")) regeneratePreview(article, id);
else setSelected(id);
if (event.target.matches("span.icon-cw")) {
const seed = generateSeed();
article.dataset.seed = seed;
Math.random = aleaPRNG(seed);
drawTemplatePreview(id);
} else setSelected(id);
});
byId("heightmapSelectionRenderOcean").on("change", redrawAll);
byId("heightmapSelectionColorScheme").on("change", redrawAll);
}
function getSelected() {
@ -234,11 +265,14 @@ function drawHeights(heights) {
canvas.height = grid.cellsY;
const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(grid.cellsX, grid.cellsY);
const scheme = getColorScheme();
const waterColor = scheme(1);
const schemeId = byId("heightmapSelectionColorScheme").value;
const scheme = getColorScheme(schemeId);
const renderOcean = byId("heightmapSelectionRenderOcean").checked;
const getHeight = height => (height < 20 ? (renderOcean ? height : 0) : height);
for (let i = 0; i < heights.length; i++) {
const color = heights[i] < 20 ? waterColor : scheme(1 - heights[i] / 100);
const color = scheme(1 - getHeight(heights[i]) / 100);
const {r, g, b} = d3.color(color);
const n = i * 4;
@ -259,6 +293,13 @@ function generateHeightmap(id) {
return heights;
}
function drawTemplatePreview(id) {
const heights = generateHeightmap(id);
const dataUrl = drawHeights(heights);
const article = byId("heightmapSelection").querySelector(`[data-id="${id}"]`);
article.querySelector("img").src = dataUrl;
}
async function drawPrecreatedHeightmap(id) {
const heights = await HeightmapGenerator.fromPrecreated(id);
const dataUrl = drawHeights(heights);
@ -266,12 +307,14 @@ async function drawPrecreatedHeightmap(id) {
article.querySelector("img").src = dataUrl;
}
function regeneratePreview(article, id) {
const seed = generateSeed();
article.dataset.seed = seed;
Math.random = aleaPRNG(seed);
function redrawAll() {
const articles = byId("heightmapSelection").querySelectorAll(`article`);
for (const article of articles) {
const {id, seed} = article.dataset;
Math.random = aleaPRNG(seed);
const heights = generateHeightmap(id);
const dataUrl = drawHeights(heights);
article.querySelector("img").src = dataUrl;
const isTemplate = id in HeightmapTemplates;
if (isTemplate) drawTemplatePreview(id);
else drawPrecreatedHeightmap(id);
}
}

View file

@ -339,7 +339,7 @@ function removeUnusedElements(clone) {
function updateMeshCells(clone) {
const data = renderOcean.checked ? grid.cells.i : grid.cells.i.filter(i => grid.cells.h[i] >= 20);
const scheme = getColorScheme();
const scheme = getColorScheme(terrs.attr("scheme"));
clone.select("#heights").attr("filter", "url(#blur1)");
clone
.select("#heights")

View file

@ -109,7 +109,8 @@ function showElevationProfile(data, routeLen, isRiver) {
draw();
function downloadCSV() {
let data = "Point,X,Y,Cell,Height,Height value,Population,Burg,Burg population,Biome,Biome color,Culture,Culture color,Religion,Religion color,Province,Province color,State,State color\n"; // headers
let data =
"Point,X,Y,Cell,Height,Height value,Population,Burg,Burg population,Biome,Biome color,Culture,Culture color,Religion,Religion color,Province,Province color,State,State color\n"; // headers
for (let k = 0; k < chartData.points.length; k++) {
let cell = chartData.cell[k];
@ -179,9 +180,20 @@ function showElevationProfile(data, routeLen, isRiver) {
.attr("id", "elevationSVG")
.attr("class", "epbackground");
// arrow-head definition
chart.append("defs").append("marker").attr("id", "arrowhead").attr("orient", "auto").attr("markerWidth", "2").attr("markerHeight", "4").attr("refX", "0.1").attr("refY", "2").append("path").attr("d", "M0,0 V4 L2,2 Z").attr("fill", "darkgray");
chart
.append("defs")
.append("marker")
.attr("id", "arrowhead")
.attr("orient", "auto")
.attr("markerWidth", "2")
.attr("markerHeight", "4")
.attr("refX", "0.1")
.attr("refY", "2")
.append("path")
.attr("d", "M0,0 V4 L2,2 Z")
.attr("fill", "darkgray");
let colors = getColorScheme();
let colors = getColorScheme(terrs.attr("scheme"));
const landdef = chart.select("defs").append("linearGradient").attr("id", "landdef").attr("x1", "0%").attr("y1", "0%").attr("x2", "0%").attr("y2", "100%");
if (chartData.mah == chartData.mih) {
@ -258,7 +270,24 @@ function showElevationProfile(data, routeLen, isRiver) {
const populationDesc = rn(pop * populationRate);
const provinceDesc = province ? ", " + pack.provinces[province].name : "";
const dataTip = biomesData.name[chartData.biome[k]] + provinceDesc + ", " + pack.states[state].name + ", " + pack.religions[religion].name + ", " + pack.cultures[culture].name + " (height: " + chartData.height[k] + " " + hu + ", population " + populationDesc + ", cell " + chartData.cell[k] + ")";
const dataTip =
biomesData.name[chartData.biome[k]] +
provinceDesc +
", " +
pack.states[state].name +
", " +
pack.religions[religion].name +
", " +
pack.cultures[culture].name +
" (height: " +
chartData.height[k] +
" " +
hu +
", population " +
populationDesc +
", cell " +
chartData.cell[k] +
")";
g.append("rect").attr("stroke", c).attr("fill", c).attr("x", x).attr("y", y).attr("width", xscale(1)).attr("height", 15).attr("data-tip", dataTip);
}

View file

@ -157,7 +157,7 @@ function drawHeightmap() {
const used = new Uint8Array(cells.i.length);
const paths = new Array(101).fill("");
const scheme = getColorScheme();
const scheme = getColorScheme(terrs.attr("scheme"));
const terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect
const skip = +terrs.attr("skip") + 1;
const simplification = +terrs.attr("relax");
@ -234,8 +234,7 @@ function drawHeightmap() {
TIME && console.timeEnd("drawHeightmap");
}
function getColorScheme() {
const scheme = terrs.attr("scheme");
function getColorScheme(scheme) {
if (scheme === "bright") return d3.scaleSequential(d3.interpolateSpectral);
if (scheme === "light") return d3.scaleSequential(d3.interpolateRdYlGn);
if (scheme === "green") return d3.scaleSequential(d3.interpolateGreens);

View file

@ -47,6 +47,9 @@ function overviewMilitary() {
// update military types in header and tooltips
function updateHeaders() {
const header = document.getElementById("militaryHeader");
const units = options.military.length;
header.style.gridTemplateColumns = `8em repeat(${units}, 5.2em) 4em 7em 5em 6em`;
header.querySelectorAll(".removable").forEach(el => el.remove());
const insert = html => document.getElementById("militaryTotal").insertAdjacentHTML("beforebegin", html);
for (const u of options.military) {

View file

@ -42,7 +42,7 @@ function editNotes(id, name) {
$("#notesEditor").dialog({
title: "Notes Editor",
width: "70vw",
width: "minmax(80vw, 540px)",
height: window.innerHeight * 0.75,
position: {my: "center", at: "center", of: "svg"},
close: removeEditor

View file

@ -30,6 +30,9 @@ function overviewRegiments(state) {
// update military types in header and tooltips
function updateHeaders() {
const header = document.getElementById("regimentsHeader");
const units = options.military.length;
header.style.gridTemplateColumns = `9em 13em repeat(${units}, 5.2em) 7em`;
header.querySelectorAll(".removable").forEach(el => el.remove());
const insert = html => document.getElementById("regimentsTotal").insertAdjacentHTML("beforebegin", html);
for (const u of options.military) {

View file

@ -2,7 +2,6 @@
// UI elements for submap generation
window.UISubmap = (function () {
const byId = document.getElementById.bind(document);
byId("submapPointsInput").addEventListener("input", function () {
const output = byId("submapPointsOutputFormatted");
const cells = cellsDensityMap[+this.value] || 1000;
@ -13,7 +12,7 @@ window.UISubmap = (function () {
byId("submapScaleInput").addEventListener("input", function (event) {
const exp = Math.pow(1.1, +event.target.value);
byId("submapScaleOutput").value = rn(exp,2);
byId("submapScaleOutput").value = rn(exp, 2);
});
byId("submapAngleInput").addEventListener("input", function (event) {
@ -28,7 +27,6 @@ window.UISubmap = (function () {
function openSubmapMenu() {
$("#submapOptionsDialog").dialog({
title: "Create a submap",
width: "30em",
resizable: false,
position: {my: "center", at: "center", of: "svg"},
buttons: {
@ -49,8 +47,8 @@ window.UISubmap = (function () {
shiftY: +byId("submapShiftY").value,
ratio: +byId("submapScaleInput").value,
mirrorH: byId("submapMirrorH").checked,
mirrorV: byId("submapMirrorV").checked,
})
mirrorV: byId("submapMirrorV").checked
});
async function openResampleMenu() {
resetZoom(0);
@ -64,14 +62,14 @@ window.UISubmap = (function () {
$shiftX.value = 0;
$shiftY.value = 0;
const previewScale = 400 / graphWidth;
const [w, h] = [400, graphHeight * previewScale];
$previewBox.style.width = w + 'px';
$previewBox.style.height = h + 'px';
$previewBox.style.position = 'relative';
const w = Math.min(400, window.innerWidth * 0.5);
const previewScale = w / graphWidth;
const h = graphHeight * previewScale;
$previewBox.style.width = w + "px";
$previewBox.style.height = h + "px";
// handle mouse input
const dispatchInput = e => e.dispatchEvent(new Event('input', {bubbles:true}));
const dispatchInput = e => e.dispatchEvent(new Event("input", {bubbles: true}));
// mouse wheel
$previewBox.onwheel = e => {
@ -80,14 +78,16 @@ window.UISubmap = (function () {
};
// mouse drag
let mouseIsDown = false, mouseX = 0, mouseY = 0;
let mouseIsDown = false,
mouseX = 0,
mouseY = 0;
$previewBox.onmousedown = e => {
mouseIsDown = true;
mouseX = $shiftX.value - e.clientX / previewScale;
mouseY = $shiftY.value - e.clientY / previewScale;
}
$previewBox.onmouseup = _ => mouseIsDown = false;
$previewBox.onmouseleave = _ => mouseIsDown = false;
};
$previewBox.onmouseup = _ => (mouseIsDown = false);
$previewBox.onmouseleave = _ => (mouseIsDown = false);
$previewBox.onmousemove = e => {
if (!mouseIsDown) return;
e.preventDefault();
@ -99,7 +99,6 @@ window.UISubmap = (function () {
$("#resampleDialog").dialog({
title: "Transform map",
width: "430px",
resizable: false,
position: {my: "center", at: "center", of: "svg"},
buttons: {
@ -114,7 +113,7 @@ window.UISubmap = (function () {
});
// use double resolution for PNG to get sharper image
const $preview = await loadPreview($previewBox, w*2, h*2);
const $preview = await loadPreview($previewBox, w * 2, h * 2);
// could be done with SVG. Faster to load, slower to use.
// const $preview = await loadPreviewSVG($previewBox, w, h);
$preview.style.position = "absolute";
@ -122,22 +121,22 @@ window.UISubmap = (function () {
$preview.style.height = h + "px";
byId("resampleDialog").oninput = event => {
const { angle, shiftX, shiftY, ratio, mirrorH, mirrorV } = getTransformInput();
const scale = Math.pow(1.1,ratio);
const {angle, shiftX, shiftY, ratio, mirrorH, mirrorV} = getTransformInput();
const scale = Math.pow(1.1, ratio);
const transformStyle = `
translate(${shiftX*previewScale}px, ${shiftY*previewScale}px)
scale(${mirrorH?-scale:scale}, ${mirrorV?-scale:scale})
translate(${shiftX * previewScale}px, ${shiftY * previewScale}px)
scale(${mirrorH ? -scale : scale}, ${mirrorV ? -scale : scale})
rotate(${angle}rad)
`;
$preview.style.transform = transformStyle;
$preview.style['transform-origin'] = 'center';
$preview.style["transform-origin"] = "center";
event.stopPropagation();
}
};
}
async function loadPreview($container, w, h) {
const url = await getMapURL("png", { globe: false, noWater: true, fullMap: true, noLabels: true, noScaleBar: true, noIce: true });
const url = await getMapURL("png", {globe: false, noWater: true, fullMap: true, noLabels: true, noScaleBar: true, noIce: true});
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
@ -148,16 +147,16 @@ window.UISubmap = (function () {
img.onload = function () {
ctx.drawImage(img, 0, 0, w, h);
};
$container.textContent = '';
$container.textContent = "";
$container.appendChild(canvas);
return canvas;
}
// currently unused alternative to PNG version
async function loadPreviewSVG($container, w, h) {
$container.innerHTML = /*html*/`
$container.innerHTML = /*html*/ `
<svg id="submapPreviewSVG" viewBox="0 0 ${graphWidth} ${graphHeight}">
<rect width="100%" height="100%" fill="${byId('styleOceanFill').value}" />
<rect width="100%" height="100%" fill="${byId("styleOceanFill").value}" />
<rect fill="url(#oceanic)" width="100%" height="100%" />
<use href="#map"></use>
</svg>
@ -171,12 +170,12 @@ window.UISubmap = (function () {
const cellNumId = +byId("submapPointsInput").value;
if (!cellsDensityMap[cellNumId]) return console.error("Unknown cell number!");
const { angle, shiftX, shiftY, ratio, mirrorH, mirrorV } = getTransformInput()
const {angle, shiftX, shiftY, ratio, mirrorH, mirrorV} = getTransformInput();
const [cx, cy] = [graphWidth / 2, graphHeight / 2];
const rot = alfa => (x, y) => [(x - cx) * Math.cos(alfa) - (y - cy) * Math.sin(alfa) + cx, (y - cy) * Math.cos(alfa) + (x - cx) * Math.sin(alfa) + cy];
const shift = (dx, dy) => (x, y) => [x + dx, y + dy];
const scale = r => (x, y) => [(x-cx) * r + cx, (y-cy) * r + cy];
const scale = r => (x, y) => [(x - cx) * r + cx, (y - cy) * r + cy];
const flipH = (x, y) => [-x + 2 * cx, y];
const flipV = (x, y) => [x, -y + 2 * cy];
const app = (f, g) => (x, y) => f(...g(x, y));
@ -186,7 +185,7 @@ window.UISubmap = (function () {
let inverse = id;
if (angle) [projection, inverse] = [rot(angle), rot(-angle)];
if (ratio) [projection, inverse] = [app(scale(Math.pow(1.1,ratio)), projection), app(inverse, scale(Math.pow(1.1,-ratio)))];
if (ratio) [projection, inverse] = [app(scale(Math.pow(1.1, ratio)), projection), app(inverse, scale(Math.pow(1.1, -ratio)))];
if (mirrorH) [projection, inverse] = [app(flipH, projection), app(inverse, flipH)];
if (mirrorV) [projection, inverse] = [app(flipV, projection), app(inverse, flipV)];
if (shiftX || shiftY) {
@ -230,7 +229,7 @@ window.UISubmap = (function () {
smoothHeightMap: scale > 2,
inverse: (x, y) => [x / origScale + x0, y / origScale + y0],
projection: (x, y) => [(x - x0) * origScale, (y - y0) * origScale],
scale: origScale,
scale: origScale
};
// converting map position on the planet

View file

@ -3,7 +3,7 @@ function editWorld() {
$("#worldConfigurator").dialog({
title: "Configure World",
resizable: false,
width: "42em",
width: "minmax(40em, 85vw)",
buttons: {
"Whole World": () => applyWorldPreset(100, 50),
Northern: () => applyWorldPreset(33, 25),