mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-16 17:31:24 +01:00
fix: image conversion UI, restrict namebase chars
This commit is contained in:
parent
931c5d3af8
commit
2bbff50b60
7 changed files with 158 additions and 82 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
||||||
.vscode
|
.vscode
|
||||||
.idea
|
.idea
|
||||||
/node_modules
|
/node_modules
|
||||||
/dist
|
/dist
|
||||||
|
/coverage
|
||||||
|
|
|
||||||
13
index.css
13
index.css
|
|
@ -1143,12 +1143,17 @@ div#regimentSelectorBody > div > div {
|
||||||
filter: sepia(1) hue-rotate(200deg);
|
filter: sepia(1) hue-rotate(200deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.colorsContainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
grid-column-gap: 0.3em;
|
||||||
|
grid-row-gap: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
.color-div {
|
.color-div {
|
||||||
width: 3em;
|
width: 3em;
|
||||||
height: 1em;
|
height: 1.5em;
|
||||||
display: inline-block;
|
border: 1px #999 solid;
|
||||||
margin: 0 0.16em;
|
|
||||||
border: 1px #c5c5c5 groove;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
26
index.html
26
index.html
|
|
@ -2245,7 +2245,7 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 350">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 350">
|
||||||
<rect width="100%" height="100%" fill="#005bbb"></rect>
|
<rect width="100%" height="100%" fill="#005bbb"></rect>
|
||||||
<rect y="50%" width="100%" height="50%" fill="#ffd500"></rect>
|
<rect y="50%" width="100%" height="50%" fill="#ffd500"></rect>
|
||||||
<text x="50%" text-anchor="middle" font-size="9em" y="35%" fill="#f5f5f5">Support Ukraine</text>
|
<text x="50%" text-anchor="middle" font-size="8em" y="32%" fill="#f5f5f5">Support Ukraine</text>
|
||||||
<text x="50%" text-anchor="middle" font-size="4em" y="78%" fill="#005bdd">
|
<text x="50%" text-anchor="middle" font-size="4em" y="78%" fill="#005bdd">
|
||||||
war.ukraine.ua/support-ukraine
|
war.ukraine.ua/support-ukraine
|
||||||
</text>
|
</text>
|
||||||
|
|
@ -2643,8 +2643,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-tip="Lake average depth in selected units">
|
<div data-tip="Lake average depth in selected units">
|
||||||
<div class="label">Avarage depth:</div>
|
<div class="label">Average depth:</div>
|
||||||
<input id="lakeAvarageDepth" disabled />
|
<input id="lakeAverageDepth" disabled />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-tip="Lake maximum depth in selected units">
|
<div data-tip="Lake maximum depth in selected units">
|
||||||
|
|
@ -4046,11 +4046,6 @@
|
||||||
></button>
|
></button>
|
||||||
<button id="convertColorsButton" data-tip="Set maximum number of colors" class="icon-signal"></button>
|
<button id="convertColorsButton" data-tip="Set maximum number of colors" class="icon-signal"></button>
|
||||||
<input id="convertColors" value="100" style="display: none" />
|
<input id="convertColors" value="100" style="display: none" />
|
||||||
<button
|
|
||||||
id="convertComplete"
|
|
||||||
data-tip="Complete the conversion. All unassigned colors will be considered as ocean"
|
|
||||||
class="icon-check"
|
|
||||||
></button>
|
|
||||||
<button
|
<button
|
||||||
id="convertCancel"
|
id="convertCancel"
|
||||||
data-tip="Cancel the conversion. Previous heightmap will be restored"
|
data-tip="Cancel the conversion. Previous heightmap will be restored"
|
||||||
|
|
@ -4072,12 +4067,23 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-tip="Select a color to re-assign the height value" id="colorsAssigned" style="display: none">
|
<div data-tip="Select a color to re-assign the height value" id="colorsAssigned" style="display: none">
|
||||||
<i>Assigned colors (<span id="colorsAssignedNumber"></span>):</i><br />
|
<i>Assigned colors (<span id="colorsAssignedNumber"></span>):</i>
|
||||||
|
<div id="colorsAssignedContainer" class="colorsContainer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-tip="Select a color to assign a height value" id="colorsUnassigned" style="display: none">
|
<div data-tip="Select a color to assign a height value" id="colorsUnassigned" style="display: none">
|
||||||
<i>Unassigned colors (<span id="colorsUnassignedNumber"></span>):</i><br />
|
<i>Unassigned colors (<span id="colorsUnassignedNumber"></span>):</i>
|
||||||
|
<div id="colorsUnassignedContainer" class="colorsContainer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
id="convertComplete"
|
||||||
|
data-tip="Complete the conversion. All unassigned colors will be considered as ocean"
|
||||||
|
style="margin: 0.4em 0"
|
||||||
|
class="glow"
|
||||||
|
>
|
||||||
|
Complete the conversion
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="biomesEditor" class="dialog stable" style="display: none">
|
<div id="biomesEditor" class="dialog stable" style="display: none">
|
||||||
|
|
|
||||||
|
|
@ -817,7 +817,7 @@ window.BurgsAndStates = (function () {
|
||||||
|
|
||||||
valid.forEach(s => (s.diplomacy = new Array(states.length).fill("x"))); // clear all relationships
|
valid.forEach(s => (s.diplomacy = new Array(states.length).fill("x"))); // clear all relationships
|
||||||
if (valid.length < 2) return; // no states to renerate relations with
|
if (valid.length < 2) return; // no states to renerate relations with
|
||||||
const areaMean = d3.mean(valid.map(s => s.area)); // avarage state area
|
const areaMean = d3.mean(valid.map(s => s.area)); // average state area
|
||||||
|
|
||||||
// generic relations
|
// generic relations
|
||||||
for (let f = 1; f < states.length; f++) {
|
for (let f = 1; f < states.length; f++) {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,10 @@ function editHeightmap(options) {
|
||||||
<p>You can <i>keep</i> the data, but you won't be able to change the coastline.</p>
|
<p>You can <i>keep</i> the data, but you won't be able to change the coastline.</p>
|
||||||
<p>Try <i>risk</i> mode to change the coastline and keep the data. The data will be restored as much as possible, but it can cause unpredictable errors.</p>
|
<p>Try <i>risk</i> mode to change the coastline and keep the data. The data will be restored as much as possible, but it can cause unpredictable errors.</p>
|
||||||
<p>Please <span class="pseudoLink" onclick="dowloadMap();">save the map</span> before editing the heightmap!</p>
|
<p>Please <span class="pseudoLink" onclick="dowloadMap();">save the map</span> before editing the heightmap!</p>
|
||||||
<p style="margin-bottom: 0">Check out ${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization", "wiki")} for guidance.</p>`;
|
<p style="margin-bottom: 0">Check out ${link(
|
||||||
|
"https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Heightmap-customization",
|
||||||
|
"wiki"
|
||||||
|
)} for guidance.</p>`;
|
||||||
|
|
||||||
$("#alert").dialog({
|
$("#alert").dialog({
|
||||||
resizable: false,
|
resizable: false,
|
||||||
|
|
@ -148,7 +151,11 @@ function editHeightmap(options) {
|
||||||
// Exit customization mode
|
// Exit customization mode
|
||||||
function finalizeHeightmap() {
|
function finalizeHeightmap() {
|
||||||
if (viewbox.select("#heights").selectAll("*").size() < 200)
|
if (viewbox.select("#heights").selectAll("*").size() < 200)
|
||||||
return tip("Insufficient land area! There should be at least 200 land cells to finalize the heightmap", null, "error");
|
return tip(
|
||||||
|
"Insufficient land area! There should be at least 200 land cells to finalize the heightmap",
|
||||||
|
null,
|
||||||
|
"error"
|
||||||
|
);
|
||||||
if (byId("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
|
if (byId("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
|
||||||
|
|
||||||
delete window.edits; // remove global variable
|
delete window.edits; // remove global variable
|
||||||
|
|
@ -210,7 +217,8 @@ function editHeightmap(options) {
|
||||||
if (!erosionAllowed) {
|
if (!erosionAllowed) {
|
||||||
for (const i of pack.cells.i) {
|
for (const i of pack.cells.i) {
|
||||||
const g = pack.cells.g[i];
|
const g = pack.cells.g[i];
|
||||||
if (pack.cells.h[i] !== grid.cells.h[g] && pack.cells.h[i] >= 20 === grid.cells.h[g] >= 20) pack.cells.h[i] = grid.cells.h[g];
|
if (pack.cells.h[i] !== grid.cells.h[g] && pack.cells.h[i] >= 20 === grid.cells.h[g] >= 20)
|
||||||
|
pack.cells.h[i] = grid.cells.h[g];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -349,7 +357,8 @@ function editHeightmap(options) {
|
||||||
const isLand = pack.cells.h[i] >= 20;
|
const isLand = pack.cells.h[i] >= 20;
|
||||||
|
|
||||||
// check biome
|
// check biome
|
||||||
pack.cells.biome[i] = isLand && biome[g] ? biome[g] : getBiomeId(grid.cells.prec[g], grid.cells.temp[g], pack.cells.h[i]);
|
pack.cells.biome[i] =
|
||||||
|
isLand && biome[g] ? biome[g] : getBiomeId(grid.cells.prec[g], grid.cells.temp[g], pack.cells.h[i]);
|
||||||
|
|
||||||
// rivers data
|
// rivers data
|
||||||
if (!erosionAllowed) {
|
if (!erosionAllowed) {
|
||||||
|
|
@ -373,7 +382,9 @@ function editHeightmap(options) {
|
||||||
const findBurgCell = function (x, y) {
|
const findBurgCell = function (x, y) {
|
||||||
let i = findCell(x, y);
|
let i = findCell(x, y);
|
||||||
if (pack.cells.h[i] >= 20) return i;
|
if (pack.cells.h[i] >= 20) return i;
|
||||||
const dist = pack.cells.c[i].map(c => (pack.cells.h[c] < 20 ? Infinity : (pack.cells.p[c][0] - x) ** 2 + (pack.cells.p[c][1] - y) ** 2));
|
const dist = pack.cells.c[i].map(c =>
|
||||||
|
pack.cells.h[c] < 20 ? Infinity : (pack.cells.p[c][0] - x) ** 2 + (pack.cells.p[c][1] - y) ** 2
|
||||||
|
);
|
||||||
return pack.cells.c[i][d3.scan(dist)];
|
return pack.cells.c[i][d3.scan(dist)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -630,15 +641,25 @@ function editHeightmap(options) {
|
||||||
|
|
||||||
const brush = document.querySelector("#brushesButtons > button.pressed").id;
|
const brush = document.querySelector("#brushesButtons > button.pressed").id;
|
||||||
if (brush === "brushRaise") s.forEach(i => (h[i] = h[i] < 20 ? 20 : lim(h[i] + power)));
|
if (brush === "brushRaise") s.forEach(i => (h[i] = h[i] < 20 ? 20 : lim(h[i] + power)));
|
||||||
else if (brush === "brushElevate") s.forEach((i, d) => (h[i] = lim(h[i] + interpolate(d / Math.max(s.length - 1, 1)))));
|
else if (brush === "brushElevate")
|
||||||
|
s.forEach((i, d) => (h[i] = lim(h[i] + interpolate(d / Math.max(s.length - 1, 1)))));
|
||||||
else if (brush === "brushLower") s.forEach(i => (h[i] = lim(h[i] - power)));
|
else if (brush === "brushLower") s.forEach(i => (h[i] = lim(h[i] - power)));
|
||||||
else if (brush === "brushDepress") s.forEach((i, d) => (h[i] = lim(h[i] - interpolate(d / Math.max(s.length - 1, 1)))));
|
else if (brush === "brushDepress")
|
||||||
|
s.forEach((i, d) => (h[i] = lim(h[i] - interpolate(d / Math.max(s.length - 1, 1)))));
|
||||||
else if (brush === "brushAlign") s.forEach(i => (h[i] = lim(h[start])));
|
else if (brush === "brushAlign") s.forEach(i => (h[i] = lim(h[start])));
|
||||||
else if (brush === "brushSmooth")
|
else if (brush === "brushSmooth")
|
||||||
s.forEach(
|
s.forEach(
|
||||||
i => (h[i] = rn((d3.mean(grid.cells.c[i].filter(i => (land ? h[i] >= 20 : 1)).map(c => h[c])) + h[i] * (10 - power) + 0.6) / (11 - power), 1))
|
i =>
|
||||||
|
(h[i] = rn(
|
||||||
|
(d3.mean(grid.cells.c[i].filter(i => (land ? h[i] >= 20 : 1)).map(c => h[c])) +
|
||||||
|
h[i] * (10 - power) +
|
||||||
|
0.6) /
|
||||||
|
(11 - power),
|
||||||
|
1
|
||||||
|
))
|
||||||
);
|
);
|
||||||
else if (brush === "brushDisrupt") s.forEach(i => (h[i] = h[i] < 15 ? h[i] : lim(h[i] + power / 1.6 - Math.random() * power)));
|
else if (brush === "brushDisrupt")
|
||||||
|
s.forEach(i => (h[i] = h[i] < 15 ? h[i] : lim(h[i] + power / 1.6 - Math.random() * power)));
|
||||||
|
|
||||||
mockHeightmapSelection(s);
|
mockHeightmapSelection(s);
|
||||||
// updateHistory(); uncomment to update history every step
|
// updateHistory(); uncomment to update history every step
|
||||||
|
|
@ -662,7 +683,8 @@ function editHeightmap(options) {
|
||||||
const operator = conditionSign.value;
|
const operator = conditionSign.value;
|
||||||
const operand = rescaleModifier.valueAsNumber;
|
const operand = rescaleModifier.valueAsNumber;
|
||||||
if (Number.isNaN(operand)) return tip("Operand should be a number", false, "error");
|
if (Number.isNaN(operand)) return tip("Operand should be a number", false, "error");
|
||||||
if ((operator === "add" || operator === "subtract") && !Number.isInteger(operand)) return tip("Operand should be an integer", false, "error");
|
if ((operator === "add" || operator === "subtract") && !Number.isInteger(operand))
|
||||||
|
return tip("Operand should be an integer", false, "error");
|
||||||
|
|
||||||
HeightmapGenerator.setGraph(grid);
|
HeightmapGenerator.setGraph(grid);
|
||||||
|
|
||||||
|
|
@ -691,7 +713,8 @@ function editHeightmap(options) {
|
||||||
function startFromScratch() {
|
function startFromScratch() {
|
||||||
if (changeOnlyLand.checked) return tip("Not allowed when 'Change only land cells' mode is set", false, "error");
|
if (changeOnlyLand.checked) return tip("Not allowed when 'Change only land cells' mode is set", false, "error");
|
||||||
const someHeights = grid.cells.h.some(h => h);
|
const someHeights = grid.cells.h.some(h => h);
|
||||||
if (!someHeights) return tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
|
if (!someHeights)
|
||||||
|
return tip("Heightmap is already cleared, please do not click twice if not required", false, "error");
|
||||||
|
|
||||||
grid.cells.h = new Uint8Array(grid.cells.i.length);
|
grid.cells.h = new Uint8Array(grid.cells.i.length);
|
||||||
viewbox.select("#heights").selectAll("*").remove();
|
viewbox.select("#heights").selectAll("*").remove();
|
||||||
|
|
@ -714,7 +737,12 @@ function editHeightmap(options) {
|
||||||
if (modules.openTemplateEditor) return;
|
if (modules.openTemplateEditor) return;
|
||||||
modules.openTemplateEditor = true;
|
modules.openTemplateEditor = true;
|
||||||
|
|
||||||
$("#templateBody").sortable({items: "> div", handle: ".icon-resize-vertical", containment: "#templateBody", axis: "y"});
|
$("#templateBody").sortable({
|
||||||
|
items: "> div",
|
||||||
|
handle: ".icon-resize-vertical",
|
||||||
|
containment: "#templateBody",
|
||||||
|
axis: "y"
|
||||||
|
});
|
||||||
|
|
||||||
// add listeners
|
// add listeners
|
||||||
$body.on("click", function (ev) {
|
$body.on("click", function (ev) {
|
||||||
|
|
@ -788,22 +816,31 @@ function editHeightmap(options) {
|
||||||
const common = /* html */ `<div data-type="${type}">${Hide}<div style="width:4em">${type}</div>${Trash}${Reorder}`;
|
const common = /* html */ `<div data-type="${type}">${Hide}<div style="width:4em">${type}</div>${Trash}${Reorder}`;
|
||||||
|
|
||||||
const TempY = /* html */ `<span>y:
|
const TempY = /* html */ `<span>y:
|
||||||
<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${arg5 || "20-80"} />
|
<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value=${
|
||||||
|
arg5 || "20-80"
|
||||||
|
} />
|
||||||
</span>`;
|
</span>`;
|
||||||
|
|
||||||
const TempX = /* html */ `<span>x:
|
const TempX = /* html */ `<span>x:
|
||||||
<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${arg4 || "15-85"} />
|
<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value=${
|
||||||
|
arg4 || "15-85"
|
||||||
|
} />
|
||||||
</span>`;
|
</span>`;
|
||||||
|
|
||||||
const Height = /* html */ `<span>h:
|
const Height = /* html */ `<span>h:
|
||||||
<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${arg3 || "40-50"} />
|
<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value=${
|
||||||
|
arg3 || "40-50"
|
||||||
|
} />
|
||||||
</span>`;
|
</span>`;
|
||||||
|
|
||||||
const Count = /* html */ `<span>n:
|
const Count = /* html */ `<span>n:
|
||||||
<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${count || "1-2"} />
|
<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value=${
|
||||||
|
count || "1-2"
|
||||||
|
} />
|
||||||
</span>`;
|
</span>`;
|
||||||
|
|
||||||
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough") return /* html */ `${common}${TempY}${TempX}${Height}${Count}</div>`;
|
if (type === "Hill" || type === "Pit" || type === "Range" || type === "Trough")
|
||||||
|
return /* html */ `${common}${TempY}${TempX}${Height}${Count}</div>`;
|
||||||
|
|
||||||
if (type === "Strait")
|
if (type === "Strait")
|
||||||
return /* html */ `${common}
|
return /* html */ `${common}
|
||||||
|
|
@ -814,7 +851,9 @@ function editHeightmap(options) {
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<span>w:
|
<span>w:
|
||||||
<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${count || "2-7"} />
|
<input class="templateCount" data-tip="Strait width, use hyphen to get a random number in range" value=${
|
||||||
|
count || "2-7"
|
||||||
|
} />
|
||||||
</span>
|
</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
|
@ -1135,7 +1174,7 @@ function editHeightmap(options) {
|
||||||
.on("click", mapClicked);
|
.on("click", mapClicked);
|
||||||
|
|
||||||
const colors = pallete.map(p => `rgb(${p[0]}, ${p[1]}, ${p[2]})`);
|
const colors = pallete.map(p => `rgb(${p[0]}, ${p[1]}, ${p[2]})`);
|
||||||
d3.select("#colorsUnassigned")
|
d3.select("#colorsUnassignedContainer")
|
||||||
.selectAll("div")
|
.selectAll("div")
|
||||||
.data(colors)
|
.data(colors)
|
||||||
.enter()
|
.enter()
|
||||||
|
|
@ -1198,25 +1237,23 @@ function editHeightmap(options) {
|
||||||
this.setAttribute("data-height", height);
|
this.setAttribute("data-height", height);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (selectedColor.parentNode.id === "colorsUnassigned") {
|
if (selectedColor.parentNode.id === "colorsUnassignedContainer") {
|
||||||
colorsAssigned.appendChild(selectedColor);
|
colorsAssignedContainer.appendChild(selectedColor);
|
||||||
colorsAssigned.style.display = "block";
|
colorsAssigned.style.display = "block";
|
||||||
|
|
||||||
byId("colorsUnassignedNumber").innerHTML = colorsUnassigned.childElementCount - 2;
|
byId("colorsUnassignedNumber").innerHTML = colorsUnassignedContainer.childElementCount - 2;
|
||||||
byId("colorsAssignedNumber").innerHTML = colorsAssigned.childElementCount - 2;
|
byId("colorsAssignedNumber").innerHTML = colorsAssignedContainer.childElementCount - 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto assign color based on luminosity or hue
|
// auto assign color based on luminosity or hue
|
||||||
function autoAssing(type) {
|
function autoAssing(type) {
|
||||||
let unassigned = colorsUnassigned.querySelectorAll("div");
|
let unassigned = colorsUnassignedContainer.querySelectorAll("div");
|
||||||
if (!unassigned.length) {
|
if (!unassigned.length) {
|
||||||
heightsFromImage(+convertColors.value);
|
heightsFromImage(+convertColors.value);
|
||||||
unassigned = colorsUnassigned.querySelectorAll("div");
|
unassigned = colorsUnassignedContainer.querySelectorAll("div");
|
||||||
if (!unassigned.length) {
|
if (!unassigned.length)
|
||||||
tip("No unassigned colors. Please load an image and click the button again", false, "error");
|
return tip("No unassigned colors. Please load an image and click the button again", false, "error");
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getHeightByHue = function (color) {
|
const getHeightByHue = function (color) {
|
||||||
|
|
@ -1245,7 +1282,8 @@ function editHeightmap(options) {
|
||||||
const assinged = []; // store assigned heights
|
const assinged = []; // store assigned heights
|
||||||
unassigned.forEach(el => {
|
unassigned.forEach(el => {
|
||||||
const clr = el.dataset.color;
|
const clr = el.dataset.color;
|
||||||
const height = type === "hue" ? getHeightByHue(clr) : type === "lum" ? getHeightByLum(clr) : getHeightByScheme(clr);
|
const height =
|
||||||
|
type === "hue" ? getHeightByHue(clr) : type === "lum" ? getHeightByLum(clr) : getHeightByScheme(clr);
|
||||||
const colorTo = color(1 - (height < 20 ? (height - 5) / 100 : height / 100));
|
const colorTo = color(1 - (height < 20 ? (height - 5) / 100 : height / 100));
|
||||||
viewbox
|
viewbox
|
||||||
.select("#heights")
|
.select("#heights")
|
||||||
|
|
@ -1259,18 +1297,18 @@ function editHeightmap(options) {
|
||||||
} // if color is already added, remove it
|
} // if color is already added, remove it
|
||||||
el.style.backgroundColor = el.dataset.color = colorTo;
|
el.style.backgroundColor = el.dataset.color = colorTo;
|
||||||
el.dataset.height = height;
|
el.dataset.height = height;
|
||||||
colorsAssigned.appendChild(el);
|
colorsAssignedContainer.appendChild(el);
|
||||||
assinged[height] = true;
|
assinged[height] = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// sort assigned colors by height
|
// sort assigned colors by height
|
||||||
Array.from(colorsAssigned.children)
|
Array.from(colorsAssignedContainer.children)
|
||||||
.sort((a, b) => +a.dataset.height - +b.dataset.height)
|
.sort((a, b) => +a.dataset.height - +b.dataset.height)
|
||||||
.forEach(line => colorsAssigned.appendChild(line));
|
.forEach(line => colorsAssignedContainer.appendChild(line));
|
||||||
|
|
||||||
colorsAssigned.style.display = "block";
|
colorsAssigned.style.display = "block";
|
||||||
colorsUnassigned.style.display = "none";
|
colorsUnassigned.style.display = "none";
|
||||||
byId("colorsAssignedNumber").innerHTML = colorsAssigned.childElementCount - 2;
|
byId("colorsAssignedNumber").innerHTML = colorsAssignedContainer.childElementCount - 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setConvertColorsNumber() {
|
function setConvertColorsNumber() {
|
||||||
|
|
@ -1290,7 +1328,8 @@ function editHeightmap(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyConversion() {
|
function applyConversion() {
|
||||||
if (colorsAssigned.childElementCount < 3) return tip("Please do the assignment first", false, "error");
|
if (colorsAssignedContainer.childElementCount < 3)
|
||||||
|
return tip("Please assign colors to heights first", false, "error");
|
||||||
|
|
||||||
viewbox
|
viewbox
|
||||||
.select("#heights")
|
.select("#heights")
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,14 @@ function editLake() {
|
||||||
document.getElementById("lakeArea").value = si(getArea(l.area)) + " " + getAreaUnit();
|
document.getElementById("lakeArea").value = si(getArea(l.area)) + " " + getAreaUnit();
|
||||||
|
|
||||||
const length = d3.polygonLength(l.vertices.map(v => pack.vertices.p[v]));
|
const length = d3.polygonLength(l.vertices.map(v => pack.vertices.p[v]));
|
||||||
document.getElementById("lakeShoreLength").value = si(length * distanceScaleInput.value) + " " + distanceUnitInput.value;
|
document.getElementById("lakeShoreLength").value =
|
||||||
|
si(length * distanceScaleInput.value) + " " + distanceUnitInput.value;
|
||||||
|
|
||||||
const lakeCells = Array.from(cells.i.filter(i => cells.f[i] === l.i));
|
const lakeCells = Array.from(cells.i.filter(i => cells.f[i] === l.i));
|
||||||
const heights = lakeCells.map(i => cells.h[i]);
|
const heights = lakeCells.map(i => cells.h[i]);
|
||||||
|
|
||||||
document.getElementById("lakeElevation").value = getHeight(l.height);
|
document.getElementById("lakeElevation").value = getHeight(l.height);
|
||||||
document.getElementById("lakeAvarageDepth").value = getHeight(d3.mean(heights), "abs");
|
document.getElementById("lakeAverageDepth").value = getHeight(d3.mean(heights), "abs");
|
||||||
document.getElementById("lakeMaxDepth").value = getHeight(d3.min(heights), "abs");
|
document.getElementById("lakeMaxDepth").value = getHeight(d3.min(heights), "abs");
|
||||||
|
|
||||||
document.getElementById("lakeFlux").value = l.flux;
|
document.getElementById("lakeFlux").value = l.flux;
|
||||||
|
|
@ -91,7 +92,9 @@ function editLake() {
|
||||||
.attr("r", 0.4)
|
.attr("r", 0.4)
|
||||||
.attr("data-v", d => d)
|
.attr("data-v", d => d)
|
||||||
.call(d3.drag().on("drag", dragVertex))
|
.call(d3.drag().on("drag", dragVertex))
|
||||||
.on("mousemove", () => tip("Drag to move the vertex, please use for fine-tuning only. Edit heightmap to change actual cell heights"));
|
.on("mousemove", () =>
|
||||||
|
tip("Drag to move the vertex, please use for fine-tuning only. Edit heightmap to change actual cell heights")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dragVertex() {
|
function dragVertex() {
|
||||||
|
|
|
||||||
|
|
@ -23,15 +23,23 @@ function editNamesbase() {
|
||||||
|
|
||||||
const uploader = document.getElementById("namesbaseToLoad");
|
const uploader = document.getElementById("namesbaseToLoad");
|
||||||
document.getElementById("namesbaseUpload").addEventListener("click", () => {
|
document.getElementById("namesbaseUpload").addEventListener("click", () => {
|
||||||
uploader.addEventListener("change", function (event) {
|
uploader.addEventListener(
|
||||||
uploadFile(event.target, d => namesbaseUpload(d, true));
|
"change",
|
||||||
}, { once: true });
|
function (event) {
|
||||||
|
uploadFile(event.target, d => namesbaseUpload(d, true));
|
||||||
|
},
|
||||||
|
{once: true}
|
||||||
|
);
|
||||||
uploader.click();
|
uploader.click();
|
||||||
});
|
});
|
||||||
document.getElementById("namesbaseUploadExtend").addEventListener("click", () => {
|
document.getElementById("namesbaseUploadExtend").addEventListener("click", () => {
|
||||||
uploader.addEventListener("change", function (event) {
|
uploader.addEventListener(
|
||||||
uploadFile(event.target, d => namesbaseUpload(d, false));
|
"change",
|
||||||
}, { once: true });
|
function (event) {
|
||||||
|
uploadFile(event.target, d => namesbaseUpload(d, false));
|
||||||
|
},
|
||||||
|
{once: true}
|
||||||
|
);
|
||||||
uploader.click();
|
uploader.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -57,10 +65,8 @@ function editNamesbase() {
|
||||||
|
|
||||||
function updateInputs() {
|
function updateInputs() {
|
||||||
const base = +document.getElementById("namesbaseSelect").value;
|
const base = +document.getElementById("namesbaseSelect").value;
|
||||||
if (!nameBases[base]) {
|
if (!nameBases[base]) return tip(`Namesbase ${base} is not defined`, false, "error");
|
||||||
tip(`Namesbase ${base} is not defined`, false, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
document.getElementById("namesbaseTextarea").value = nameBases[base].b;
|
document.getElementById("namesbaseTextarea").value = nameBases[base].b;
|
||||||
document.getElementById("namesbaseName").value = nameBases[base].name;
|
document.getElementById("namesbaseName").value = nameBases[base].name;
|
||||||
document.getElementById("namesbaseMin").value = nameBases[base].min;
|
document.getElementById("namesbaseMin").value = nameBases[base].min;
|
||||||
|
|
@ -86,20 +92,23 @@ function editNamesbase() {
|
||||||
|
|
||||||
function updateNamesData() {
|
function updateNamesData() {
|
||||||
const base = +document.getElementById("namesbaseSelect").value;
|
const base = +document.getElementById("namesbaseSelect").value;
|
||||||
const b = document.getElementById("namesbaseTextarea").value;
|
const rawInput = document.getElementById("namesbaseTextarea").value;
|
||||||
if (b.split(",").length < 3) {
|
if (rawInput.split(",").length < 3) return tip("The names data provided is too short of incorrect", false, "error");
|
||||||
tip("The names data provided is too short of incorrect", false, "error");
|
|
||||||
return;
|
const namesData = rawInput.replace(/[/|]/g, "");
|
||||||
}
|
nameBases[base].b = namesData;
|
||||||
nameBases[base].b = b;
|
|
||||||
Names.updateChain(base);
|
Names.updateChain(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBaseName() {
|
function updateBaseName() {
|
||||||
const base = +document.getElementById("namesbaseSelect").value;
|
const base = +document.getElementById("namesbaseSelect").value;
|
||||||
const select = document.getElementById("namesbaseSelect");
|
const select = document.getElementById("namesbaseSelect");
|
||||||
select.options[namesbaseSelect.selectedIndex].innerHTML = this.value;
|
|
||||||
nameBases[base].name = this.value;
|
const rawName = this.value;
|
||||||
|
const name = rawName.replace(/[/|]/g, "");
|
||||||
|
|
||||||
|
select.options[namesbaseSelect.selectedIndex].innerHTML = name;
|
||||||
|
nameBases[base].name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBaseMin() {
|
function updateBaseMin() {
|
||||||
|
|
@ -147,21 +156,28 @@ function editNamesbase() {
|
||||||
: "none";
|
: "none";
|
||||||
|
|
||||||
const geminate = namesArray.map(name => name.match(/[^\w\s]|(.)(?=\1)/g) || []).flat();
|
const geminate = namesArray.map(name => name.match(/[^\w\s]|(.)(?=\1)/g) || []).flat();
|
||||||
const doubled = unique(geminate).filter(char => geminate.filter(doudledChar => doudledChar === char).length > 3) || ["none"];
|
const doubled = unique(geminate).filter(
|
||||||
|
char => geminate.filter(doudledChar => doudledChar === char).length > 3
|
||||||
|
) || ["none"];
|
||||||
|
|
||||||
const duplicates = unique(namesArray.filter((e, i, a) => a.indexOf(e) !== i)).join(", ") || "none";
|
const duplicates = unique(namesArray.filter((e, i, a) => a.indexOf(e) !== i)).join(", ") || "none";
|
||||||
const multiwordRate = d3.mean(namesArray.map(n => +n.includes(" ")));
|
const multiwordRate = d3.mean(namesArray.map(n => +n.includes(" ")));
|
||||||
|
|
||||||
const getLengthQuality = () => {
|
const getLengthQuality = () => {
|
||||||
if (length < 30) return "<span data-tip='Namesbase contains < 30 names - not enough to generate reasonable data' style='color:red'>[not enough]</span>";
|
if (length < 30)
|
||||||
if (length < 100) return "<span data-tip='Namesbase contains < 100 names - not enough to generate good names' style='color:darkred'>[low]</span>";
|
return "<span data-tip='Namesbase contains < 30 names - not enough to generate reasonable data' style='color:red'>[not enough]</span>";
|
||||||
if (length <= 400) return "<span data-tip='Namesbase contains a reasonable number of samples' style='color:green'>[good]</span>";
|
if (length < 100)
|
||||||
|
return "<span data-tip='Namesbase contains < 100 names - not enough to generate good names' style='color:darkred'>[low]</span>";
|
||||||
|
if (length <= 400)
|
||||||
|
return "<span data-tip='Namesbase contains a reasonable number of samples' style='color:green'>[good]</span>";
|
||||||
return "<span data-tip='Namesbase contains > 400 names. That is too much, try to reduce it to ~300 names' style='color:darkred'>[overmuch]</span>";
|
return "<span data-tip='Namesbase contains > 400 names. That is too much, try to reduce it to ~300 names' style='color:darkred'>[overmuch]</span>";
|
||||||
};
|
};
|
||||||
|
|
||||||
const getVarietyLevel = () => {
|
const getVarietyLevel = () => {
|
||||||
if (variety < 15) return "<span data-tip='Namesbase average variety < 15 - generated names will be too repetitive' style='color:red'>[low]</span>";
|
if (variety < 15)
|
||||||
if (variety < 30) return "<span data-tip='Namesbase average variety < 30 - names can be too repetitive' style='color:orange'>[mean]</span>";
|
return "<span data-tip='Namesbase average variety < 15 - generated names will be too repetitive' style='color:red'>[low]</span>";
|
||||||
|
if (variety < 30)
|
||||||
|
return "<span data-tip='Namesbase average variety < 30 - names can be too repetitive' style='color:orange'>[mean]</span>";
|
||||||
return "<span data-tip='Namesbase variety is good' style='color:green'>[good]</span>";
|
return "<span data-tip='Namesbase variety is good' style='color:green'>[good]</span>";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -175,9 +191,14 @@ function editNamesbase() {
|
||||||
<div data-tip="Common name length">Median name length: ${d3.median(wordsLength)}</div>
|
<div data-tip="Common name length">Median name length: ${d3.median(wordsLength)}</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div data-tip="Characters outside of Basic Latin have bad font support">Non-basic chars: ${nonBasicLatinChars}</div>
|
<div data-tip="Characters outside of Basic Latin have bad font support">Non-basic chars: ${nonBasicLatinChars}</div>
|
||||||
<div data-tip="Characters that are frequently (more than 3 times) doubled">Doubled chars: ${doubled.join("")}</div>
|
<div data-tip="Characters that are frequently (more than 3 times) doubled">Doubled chars: ${doubled.join(
|
||||||
|
""
|
||||||
|
)}</div>
|
||||||
<div data-tip="Names used more than one time">Duplicates: ${duplicates}</div>
|
<div data-tip="Names used more than one time">Duplicates: ${duplicates}</div>
|
||||||
<div data-tip="Percentage of names containing space character">Multi-word names: ${rn(multiwordRate * 100, 2)}%</div>
|
<div data-tip="Percentage of names containing space character">Multi-word names: ${rn(
|
||||||
|
multiwordRate * 100,
|
||||||
|
2
|
||||||
|
)}%</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
$("#alert").dialog({
|
$("#alert").dialog({
|
||||||
|
|
@ -194,7 +215,8 @@ function editNamesbase() {
|
||||||
|
|
||||||
function namesbaseAdd() {
|
function namesbaseAdd() {
|
||||||
const base = nameBases.length;
|
const base = nameBases.length;
|
||||||
const b = "This,is,an,example,of,name,base,showing,correct,format,It,should,have,at,least,one,hundred,names,separated,with,comma";
|
const b =
|
||||||
|
"This,is,an,example,of,name,base,showing,correct,format,It,should,have,at,least,one,hundred,names,separated,with,comma";
|
||||||
nameBases.push({name: "Base" + base, min: 5, max: 12, d: "", m: 0, b});
|
nameBases.push({name: "Base" + base, min: 5, max: 12, d: "", m: 0, b});
|
||||||
document.getElementById("namesbaseSelect").add(new Option("Base" + base, base));
|
document.getElementById("namesbaseSelect").add(new Option("Base" + base, base));
|
||||||
document.getElementById("namesbaseSelect").value = base;
|
document.getElementById("namesbaseSelect").value = base;
|
||||||
|
|
@ -232,7 +254,7 @@ function editNamesbase() {
|
||||||
downloadFile(data, name);
|
downloadFile(data, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function namesbaseUpload(dataLoaded, override=true) {
|
function namesbaseUpload(dataLoaded, override = true) {
|
||||||
const data = dataLoaded.split("\r\n");
|
const data = dataLoaded.split("\r\n");
|
||||||
if (!data || !data[0]) {
|
if (!data || !data[0]) {
|
||||||
tip("Cannot load a namesbase. Please check the data format", false, "error");
|
tip("Cannot load a namesbase. Please check the data format", false, "error");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue