mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 01:41:22 +01:00
Custom heightmap color scheme (#1013)
* feat: custom heightmap color scheme * feat: custom heightmap color scheme - add shceme on load --------- Co-authored-by: Azgaar <azgaar.fmg@yandex.com>
This commit is contained in:
parent
778bea15ee
commit
958a2c6ef8
10 changed files with 216 additions and 64 deletions
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
// add available filters to lists
|
||||
{
|
||||
const filters = Array.from(document.getElementById("filters").querySelectorAll("filter"));
|
||||
const filters = Array.from(byId("filters").querySelectorAll("filter"));
|
||||
const emptyOption = '<option value="" selected>None</option>';
|
||||
const options = filters.map(filter => {
|
||||
const id = filter.getAttribute("id");
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
});
|
||||
const allOptions = emptyOption + options.join("");
|
||||
|
||||
document.getElementById("styleFilterInput").innerHTML = allOptions;
|
||||
document.getElementById("styleStatesBodyFilter").innerHTML = allOptions;
|
||||
byId("styleFilterInput").innerHTML = allOptions;
|
||||
byId("styleStatesBodyFilter").innerHTML = allOptions;
|
||||
}
|
||||
|
||||
// store some style inputs as options
|
||||
|
|
@ -37,20 +37,37 @@ function editStyle(element, group) {
|
|||
}, 1500);
|
||||
}
|
||||
|
||||
// Color schemes
|
||||
const heightmapColorSchemes = {
|
||||
bright: d3.scaleSequential(d3.interpolateSpectral),
|
||||
light: d3.scaleSequential(d3.interpolateRdYlGn),
|
||||
natural: d3.scaleSequential(d3.interpolateRgbBasis(["white", "#EEEECC", "tan", "green", "teal"])),
|
||||
green: d3.scaleSequential(d3.interpolateGreens),
|
||||
olive: d3.scaleSequential(d3.interpolateRgbBasis(["#ffffff", "#cea48d", "#d5b085", "#0c2c19", "#151320"])),
|
||||
livid: d3.scaleSequential(d3.interpolateRgbBasis(["#BBBBDD", "#2A3440", "#17343B", "#0A1E24"])),
|
||||
monochrome: d3.scaleSequential(d3.interpolateGreys)
|
||||
};
|
||||
|
||||
// add color schemes to the lists
|
||||
document.getElementById("styleHeightmapScheme").innerHTML = Object.keys(heightmapColorSchemes)
|
||||
// add default color schemes to the list of options
|
||||
byId("styleHeightmapScheme").innerHTML = Object.keys(heightmapColorSchemes)
|
||||
.map(scheme => `<option value="${scheme}">${scheme}</option>`)
|
||||
.join("");
|
||||
|
||||
function addCustomColorScheme(scheme) {
|
||||
const stops = scheme.split(",");
|
||||
heightmapColorSchemes[scheme] = d3.scaleSequential(d3.interpolateRgbBasis(stops));
|
||||
byId("styleHeightmapScheme").options.add(new Option(scheme, scheme, false, true));
|
||||
}
|
||||
|
||||
function getColorScheme(scheme = "bright") {
|
||||
if (!(scheme in heightmapColorSchemes)) {
|
||||
const colors = scheme.split(",");
|
||||
heightmapColorSchemes[scheme] = d3.scaleSequential(d3.interpolateRgbBasis(colors));
|
||||
}
|
||||
|
||||
return heightmapColorSchemes[scheme];
|
||||
}
|
||||
|
||||
// Toggle style sections on element select
|
||||
styleElementSelect.addEventListener("change", selectStyleElement);
|
||||
function selectStyleElement() {
|
||||
|
|
@ -278,9 +295,9 @@ function selectStyleElement() {
|
|||
if (sel === "ocean") {
|
||||
styleOcean.style.display = "block";
|
||||
styleOceanFill.value = styleOceanFillOutput.value = oceanLayers.select("#oceanBase").attr("fill");
|
||||
styleOceanPattern.value = document.getElementById("oceanicPattern")?.getAttribute("href");
|
||||
styleOceanPattern.value = byId("oceanicPattern")?.getAttribute("href");
|
||||
styleOceanPatternOpacity.value = styleOceanPatternOpacityOutput.value =
|
||||
document.getElementById("oceanicPattern").getAttribute("opacity") || 1;
|
||||
byId("oceanicPattern").getAttribute("opacity") || 1;
|
||||
outlineLayers.value = oceanLayers.attr("layers");
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +330,7 @@ function selectStyleElement() {
|
|||
// update group options
|
||||
styleGroupSelect.options.length = 0; // remove all options
|
||||
if (["routes", "labels", "coastline", "lakes", "anchors", "burgIcons", "borders"].includes(sel)) {
|
||||
const groups = document.getElementById(sel).querySelectorAll("g");
|
||||
const groups = byId(sel).querySelectorAll("g");
|
||||
groups.forEach(el => {
|
||||
if (el.id === "burgLabels") return;
|
||||
const option = new Option(`${el.id} (${el.childElementCount})`, el.id, false, false);
|
||||
|
|
@ -458,11 +475,11 @@ styleOceanFill.addEventListener("input", function () {
|
|||
});
|
||||
|
||||
styleOceanPattern.addEventListener("change", function () {
|
||||
document.getElementById("oceanicPattern")?.setAttribute("href", this.value);
|
||||
byId("oceanicPattern")?.setAttribute("href", this.value);
|
||||
});
|
||||
|
||||
styleOceanPatternOpacity.addEventListener("input", function () {
|
||||
document.getElementById("oceanicPattern").setAttribute("opacity", this.value);
|
||||
byId("oceanicPattern").setAttribute("opacity", this.value);
|
||||
styleOceanPatternOpacityOutput.value = this.value;
|
||||
});
|
||||
|
||||
|
|
@ -477,6 +494,127 @@ styleHeightmapScheme.addEventListener("change", function () {
|
|||
drawHeightmap();
|
||||
});
|
||||
|
||||
openCreateHeightmapSchemeButton.addEventListener("click", function () {
|
||||
// start with current scheme
|
||||
this.dataset.stops = terrs.attr("scheme").startsWith("#")
|
||||
? terrs.attr("scheme")
|
||||
: (function () {
|
||||
const scheme = heightmapColorSchemes[terrs.attr("scheme")];
|
||||
return [0, 0.25, 0.5, 0.75, 1].map(scheme).map(toHEX).join(",");
|
||||
})();
|
||||
|
||||
// render dialog base structure
|
||||
alertMessage.innerHTML = /* html */ `<div>
|
||||
<i>Define heightmap gradient colors from high to low altitude</i>
|
||||
<img id="heightmapSchemePreview" alt="heightmap preview" style="margin-top: 0.5em; width: 100%;" />
|
||||
<div id="heightmapSchemeStops" style="margin-block: 0.5em; display: flex; flex-wrap: wrap;"></div>
|
||||
<div id="heightmapSchemeGradient" style="height: 1.9em; border: 1px solid #767676;"></div>
|
||||
</div>`;
|
||||
|
||||
renderPreview();
|
||||
renderStops();
|
||||
renderGradient();
|
||||
|
||||
function renderPreview() {
|
||||
const stops = openCreateHeightmapSchemeButton.dataset.stops.split(",");
|
||||
const scheme = d3.scaleSequential(d3.interpolateRgbBasis(stops));
|
||||
|
||||
const preview = drawHeights({
|
||||
heights: grid.cells.h,
|
||||
width: grid.cellsX,
|
||||
height: grid.cellsY,
|
||||
scheme,
|
||||
renderOcean: false
|
||||
});
|
||||
|
||||
byId("heightmapSchemePreview").src = preview;
|
||||
}
|
||||
|
||||
function renderStops() {
|
||||
const stops = openCreateHeightmapSchemeButton.dataset.stops.split(",");
|
||||
|
||||
const colorInput = color =>
|
||||
`<input type="color" class="stop" value="${color}" data-tip="Click to set the color" style="width: 2.5em; border: none;" />`;
|
||||
const removeStopButton = index =>
|
||||
`<button class="remove" data-index="${index}" data-tip="Remove color stop" style="margin-top: 0.3em; height: max-content;">x</button>`;
|
||||
const addStopButton = () =>
|
||||
`<button class="add" data-tip="Add color stop in between" style="margin-top: 0.3em; height: max-content;">+</button>`;
|
||||
|
||||
const container = byId("heightmapSchemeStops");
|
||||
container.innerHTML = stops
|
||||
.map(
|
||||
(stop, index) => `${colorInput(stop)}
|
||||
${index && index < stops.length - 1 ? removeStopButton(index) : ""}`
|
||||
)
|
||||
.join(addStopButton());
|
||||
|
||||
Array.from(container.querySelectorAll("input.stop")).forEach(
|
||||
(input, index) =>
|
||||
(input.oninput = function () {
|
||||
stops[index] = this.value;
|
||||
openCreateHeightmapSchemeButton.dataset.stops = stops.join(",");
|
||||
renderPreview();
|
||||
renderGradient();
|
||||
})
|
||||
);
|
||||
|
||||
Array.from(container.querySelectorAll("button.remove")).forEach(
|
||||
button =>
|
||||
(button.onclick = function () {
|
||||
const index = +this.dataset.index;
|
||||
stops.splice(index, 1);
|
||||
openCreateHeightmapSchemeButton.dataset.stops = stops.join(",");
|
||||
renderPreview();
|
||||
renderStops();
|
||||
renderGradient();
|
||||
})
|
||||
);
|
||||
|
||||
Array.from(container.querySelectorAll("button.add")).forEach(
|
||||
(button, index) =>
|
||||
(button.onclick = function () {
|
||||
const middleColor = d3.interpolateRgb(stops[index], stops[index + 1])(0.5);
|
||||
stops.splice(index + 1, 0, toHEX(middleColor));
|
||||
openCreateHeightmapSchemeButton.dataset.stops = stops.join(",");
|
||||
renderPreview();
|
||||
renderStops();
|
||||
renderGradient();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function renderGradient() {
|
||||
const stops = openCreateHeightmapSchemeButton.dataset.stops;
|
||||
byId("heightmapSchemeGradient").style.background = `linear-gradient(to right, ${stops})`;
|
||||
}
|
||||
|
||||
function handleCreate() {
|
||||
const stops = openCreateHeightmapSchemeButton.dataset.stops;
|
||||
if (stops in heightmapColorSchemes) return tip("This scheme already exists", false, "error");
|
||||
|
||||
addCustomColorScheme(stops);
|
||||
terrs.attr("scheme", stops);
|
||||
drawHeightmap();
|
||||
|
||||
handleClose();
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
$("#alert").dialog("close");
|
||||
}
|
||||
|
||||
$("#alert").dialog({
|
||||
resizable: false,
|
||||
title: "Create heightmap color scheme",
|
||||
width: "28em",
|
||||
buttons: {
|
||||
Create: handleCreate,
|
||||
Cancel: handleClose
|
||||
},
|
||||
position: {my: "center top+150", at: "center top", of: "svg"}
|
||||
});
|
||||
});
|
||||
|
||||
styleHeightmapTerracingInput.addEventListener("input", function () {
|
||||
terrs.attr("terracing", this.value);
|
||||
drawHeightmap();
|
||||
|
|
@ -801,7 +939,7 @@ function fetchTextureURL(url) {
|
|||
INFO && console.log("Provided URL is", url);
|
||||
const img = new Image();
|
||||
img.onload = function () {
|
||||
const canvas = document.getElementById("texturePreview");
|
||||
const canvas = byId("texturePreview");
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue