diff --git a/index.css b/index.css
index ca18c7d4..9976406c 100644
--- a/index.css
+++ b/index.css
@@ -957,14 +957,6 @@ body button.noicon {
margin: 6px 1px 4px 1px;
}
-#colorsSelectValue {
- font-size: larger;
- position: relative;
- font-family: monospace;
- font-weight: bold;
- top: -3px;
-}
-
#debug path.selected {
stroke-width: .8;
stroke: #da3126;
diff --git a/index.html b/index.html
index 97bcfbdc..75df1f56 100644
--- a/index.html
+++ b/index.html
@@ -2522,9 +2522,10 @@
diff --git a/main.js b/main.js
index 8693ad9a..35dfa0e8 100644
--- a/main.js
+++ b/main.js
@@ -1690,12 +1690,11 @@ const regenerateMap = debounce(function() {
resetZoom(1000);
generate();
restoreLayers();
- const canvas3d = document.getElementById("canvas3d");
- if (canvas3d) ThreeD.redraw();
+ if (ThreeD.options.isOn) ThreeD.redraw();
if ($("#worldConfigurator").is(":visible")) editWorld();
}, 500);
-// Clear the map
+// clear the map
function undraw() {
viewbox.selectAll("path, circle, polygon, line, text, use, #zones > g, #ruler > g").remove();
defs.selectAll("path, clipPath").remove();
diff --git a/modules/ui/3d.js b/modules/ui/3d.js
index 584b5ed3..05f61654 100644
--- a/modules/ui/3d.js
+++ b/modules/ui/3d.js
@@ -14,6 +14,7 @@ let Renderer, scene, camera, controls, animationFrame, material, texture,
// initiate 3d scene
const create = async function(canvas, type = "viewMesh") {
+ options.isOn = true;
options.isGlobe = type === "viewGlobe";
return options.isGlobe ? newGlobe(canvas) : newMesh(canvas);
}
@@ -57,6 +58,8 @@ const stop = function() {
texture = undefined;
geometry = undefined;
mesh = undefined;
+
+ ThreeD.options.isOn = false;
}
const setScale = function(scale) {
@@ -81,10 +84,11 @@ const setSun = function(x, y, z) {
}
const setRotation = function(speed) {
+ cancelAnimationFrame(animationFrame);
if (options.isGlobe) options.rotateGlobe = speed; else options.rotateMesh = speed;
controls.autoRotateSpeed = speed;
controls.autoRotate = Boolean(controls.autoRotateSpeed);
- controls.autoRotate ? animate() : cancelAnimationFrame(animationFrame);
+ if (controls.autoRotate) animate();
}
const toggleSky = function() {
diff --git a/modules/ui/general.js b/modules/ui/general.js
index 07726d91..59bba74d 100644
--- a/modules/ui/general.js
+++ b/modules/ui/general.js
@@ -305,7 +305,7 @@ document.addEventListener("keydown", event => {
document.addEventListener("keyup", event => {
if (!window.closeDialogs) return; // not all modules are loaded
const canvas3d = document.getElementById("canvas3d"); // check if 3d mode is active
- const active = canvas3d ? null : document.activeElement.tagName;
+ const active = document.activeElement.tagName;
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
if (active === "DIV" && document.activeElement.contentEditable === "true") return; // don't trigger if user inputs a text
event.stopPropagation();
diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js
index 6a66f895..a06f5258 100644
--- a/modules/ui/heightmap-editor.js
+++ b/modules/ui/heightmap-editor.js
@@ -33,7 +33,7 @@ function editHeightmap() {
document.getElementById("applyTemplate").addEventListener("click", openTemplateEditor);
document.getElementById("convertImage").addEventListener("click", openImageConverter);
document.getElementById("heightmapPreview").addEventListener("click", toggleHeightmapPreview);
- document.getElementById("heightmap3DView").addEventListener("click", toggleHeightmap3dView);
+ document.getElementById("heightmap3DView").addEventListener("click", changeViewMode);
document.getElementById("finalizeHeightmap").addEventListener("click", finalizeHeightmap);
document.getElementById("renderOcean").addEventListener("click", mockHeightmap);
document.getElementById("templateUndo").addEventListener("click", () => restoreHistory(edits.n-1));
@@ -43,9 +43,6 @@ function editHeightmap() {
editHeightmap.layers = Array.from(mapLayers.querySelectorAll("li:not(.buttonoff)")).map(node => node.id); // store layers preset
editHeightmap.layers.forEach(l => document.getElementById(l).click()); // turn off all layers
- enterStandardView();
- disable3dViews();
-
customization = 1;
closeDialogs();
tip('Heightmap edit mode is active. Click on "Exit Customization" to finalize the heightmap', true);
@@ -112,8 +109,6 @@ function editHeightmap() {
return;
}
- enable3dViews();
-
customization = 0;
customizationMenu.style.display = "none";
toolsContent.style.display = "block";
@@ -125,8 +120,7 @@ function editHeightmap() {
restartHistory();
if (document.getElementById("preview")) document.getElementById("preview").remove();
- if (document.getElementById("canvas3d")) toggleHeightmap3dView();
-
+ if (document.getElementById("canvas3d")) enterStandardView();
const mode = heightmapEditMode.innerHTML;
if (mode === "erase") regenerateErasedData();
@@ -981,7 +975,9 @@ function editHeightmap() {
document.getElementById("convertOverlayNumber").addEventListener("input", function() {setOverlayOpacity(this.value)});
function showPalleteHeight() {
- colorsSelectValue.innerHTML = this.getAttribute("data-color");
+ const height = +this.getAttribute("data-color");
+ colorsSelectValue.innerHTML = height;
+ colorsSelectFriendly.innerHTML = getHeight(height);
const former = colorScheme.querySelector(".hoveredColor")
if (former) former.className = "";
this.className = "hoveredColor";
@@ -1056,15 +1052,16 @@ function editHeightmap() {
if (selectedColor) selectedColor.classList.remove("selectedColor");
const hoveredColor = colorScheme.querySelector("div.hoveredColor");
if (hoveredColor) hoveredColor.classList.remove("hoveredColor");
- colorsSelectValue.innerHTML = "";
+ colorsSelectValue.innerHTML = colorsSelectFriendly.innerHTML = 0;
if (unselect) return;
this.classList.add("selectedColor");
- if (this.getAttribute("data-height")) {
- const height = this.getAttribute("data-height");
+ if (this.dataset.height) {
+ const height = +this.dataset.height;
colorScheme.querySelector(`div[data-color="${height}"]`).classList.add("hoveredColor");
colorsSelectValue.innerHTML = height;
+ colorsSelectFriendly.innerHTML = getHeight(height);
}
const color = this.getAttribute("data-color");
@@ -1073,7 +1070,7 @@ function editHeightmap() {
}
function assignHeight() {
- const height = +this.getAttribute("data-color");
+ const height = +this.dataset.color;
const rgb = color(1 - (height < 20 ? height-5 : height) / 100);
const selectedColor = imageConverter.querySelector("div.selectedColor");
selectedColor.style.backgroundColor = rgb;
@@ -1081,7 +1078,7 @@ function editHeightmap() {
selectedColor.setAttribute("data-height", height);
viewbox.select("#heights").selectAll(".selectedCell").each(function() {
- this.setAttribute("fill", rgb);
+ this.setAttribute("fill", rgb);
this.setAttribute("data-height", height);
});
@@ -1097,20 +1094,32 @@ function editHeightmap() {
const unassigned = colorsUnassigned.querySelectorAll("div");
if (!unassigned.length) {tip("No unassigned colors. Please load an image and click the button again", false, "error"); return;}
- unassigned.forEach(function(el) {
- const colorFrom = el.getAttribute("data-color");
+ const assinged = []; // assigned heights
+ unassigned.forEach(el => {
+ const colorFrom = el.dataset.color;
const lab = d3.lab(colorFrom);
const normalized = type === "hue" ? rn(normalize(lab.b + lab.a / 2, -50, 200), 2) : rn(normalize(lab.l, -15, 100), 2);
- const colorTo = color(1 - (normalized < .2 ? normalized-.05 : normalized));
- const heightTo = normalized * 100;
+ let heightTo = rn(normalized * 100);
+ if (assinged[heightTo] && heightTo < 100) heightTo += 1; // if height is already added, try increated one
+ if (assinged[heightTo] && heightTo < 100) heightTo += 1; // if height is already added, try increated one
+ if (assinged[heightTo] && heightTo > 3) heightTo -= 3; // if increased one is also added, try decreased one
+ if (assinged[heightTo] && heightTo > 1) heightTo -= 1; // if increased one is also added, try decreased one
+ const colorTo = color(1 - (heightTo < 20 ? (heightTo-5)/100 : heightTo/100));
viewbox.select("#heights").selectAll("polygon[fill='" + colorFrom + "']").attr("fill", colorTo).attr("data-height", heightTo);
- el.style.backgroundColor = colorTo;
- el.setAttribute("data-color", colorTo);
- el.setAttribute("data-height", heightTo);
+
+ if (assinged[heightTo]) {el.remove(); return;} // if color is already added, remove it
+ el.style.backgroundColor = el.dataset.color = colorTo;
+ el.dataset.height = heightTo;
colorsAssigned.appendChild(el);
+ assinged[heightTo] = true;
});
-
+
+ // sort assigned colors by height
+ Array.from(colorsAssigned.children).sort((a, b) => {
+ return +a.dataset.height - +b.dataset.height;
+ }).forEach(line => colorsAssigned.appendChild(line));
+
colorsAssigned.style.display = "block";
colorsUnassigned.style.display = "none";
}
@@ -1137,12 +1146,12 @@ function editHeightmap() {
d3.select("#imageConverter").selectAll("div.color-div").remove();
colorsAssigned.style.display = "none";
colorsUnassigned.style.display = "none";
- colorsSelectValue.innerHTML = "";
+ colorsSelectValue.innerHTML = colorsSelectFriendly.innerHTML = 0;
viewbox.style("cursor", "default").on(".drag", null);
tip('Heightmap edit mode is active. Click on "Exit Customization" to finalize the heightmap', true);
viewbox.select("#heights").selectAll("polygon").each(function() {
- const height = +this.getAttribute("data-height") || 0;
+ const height = +this.dataset.height || 0;
const i = +this.id.slice(4);
grid.cells.h[i] = height;
});
@@ -1207,42 +1216,4 @@ function editHeightmap() {
}
}
- // 3D previewer
- async function toggleHeightmap3dView() {
- if (document.getElementById("canvas3d")) {
- $("#preview3d").dialog("close");
- return;
- }
-
- const canvas = document.createElement("canvas");
- canvas.id = "canvas3d";
- canvas.style.display = "block";
- canvas.width = parseFloat(preview3d.style.width) || graphWidth / 3;
- canvas.height = canvas.width / (graphWidth / graphHeight);
- const started = ThreeD.create(canvas);
- if (!started) return;
-
- document.getElementById("preview3d").appendChild(canvas);
- canvas.onmouseenter = () => {
- +canvas.dataset.hovered > 2 ? tip("") : tip("Left mouse to change angle, middle mouse or mousewheel to zoom, right mouse to pan. R to toggle rotation");
- canvas.dataset.hovered = (+canvas.dataset.hovered|0) + 1;
- };
-
- $("#preview3d").dialog({
- title: "3D Preview", resizable: true,
- position: {my: "left bottom", at: "left+10 bottom-20", of: "svg"},
- resizeStop: resize3d, close: close3dPreview
- });
-
- function resize3d() {
- canvas.width = parseFloat(preview3d.style.width);
- canvas.height = parseFloat(preview3d.style.height) - 2;
- ThreeD.redraw();
- }
-
- function close3dPreview() {
- ThreeD.stop();
- canvas.remove();
- }
- }
}
diff --git a/modules/ui/options.js b/modules/ui/options.js
index 83bd4273..557d8003 100644
--- a/modules/ui/options.js
+++ b/modules/ui/options.js
@@ -427,68 +427,81 @@ document.getElementById("mapToLoad").addEventListener("change", function() {
// View mode
viewMode.addEventListener("click", changeViewMode);
-function changeViewMode(event) {
- if (event.target.tagName !== "BUTTON") return;
+function changeViewMode() {
const button = event.target;
-
+ if (button.tagName !== "BUTTON") return;
+ const pressed = button.classList.contains("pressed");
enterStandardView();
- if (button.classList.contains("pressed")) {
- button.classList.remove("pressed");
- viewStandard.classList.add("pressed");
- } else {
- viewMode.querySelectorAll(".pressed").forEach(button => button.classList.remove("pressed"));
+ if (!pressed && button.id !== "viewStandard") {
+ viewStandard.classList.remove("pressed");
button.classList.add("pressed");
- if (button.id !== "viewStandard") enter3dView(button.id);
+ enter3dView(button.id);
}
}
-function disable3dViews() {
- viewMesh.disabled = true;
- viewGlobe.disabled = true;
-}
-
-function enable3dViews() {
- viewMesh.disabled = false;
- viewGlobe.disabled = false;
-}
-
function enterStandardView() {
viewMode.querySelectorAll(".pressed").forEach(button => button.classList.remove("pressed"));
+ heightmap3DView.classList.remove("pressed");
viewStandard.classList.add("pressed");
if (!document.getElementById("canvas3d")) return;
ThreeD.stop();
document.getElementById("canvas3d").remove();
if (options3dUpdate.offsetParent) $("#options3d").dialog("close");
+ if (preview3d.offsetParent) $("#preview3d").dialog("close");
}
async function enter3dView(type) {
const canvas = document.createElement("canvas");
canvas.id = "canvas3d";
- canvas.style.display = "block";
- canvas.width = svgWidth;
- canvas.height = svgHeight;
- canvas.style.position = "absolute";
- canvas.style.display = "none";
canvas.dataset.type = type;
+
+ if (type === "heightmap3DView") {
+ canvas.width = parseFloat(preview3d.style.width) || graphWidth / 3;
+ canvas.height = canvas.width / (graphWidth / graphHeight);
+ canvas.style.display = "block";
+ } else {
+ canvas.width = svgWidth;
+ canvas.height = svgHeight;
+ canvas.style.position = "absolute";
+ canvas.style.display = "none";
+ }
+
const started = await ThreeD.create(canvas, type);
if (!started) return;
+
canvas.style.display = "block";
- document.body.insertBefore(canvas, optionsContainer);
canvas.onmouseenter = () => {
const help = "Left mouse to change angle, middle mouse / mousewheel to zoom, right mouse to pan. O to toggle options";
+canvas.dataset.hovered > 2 ? tip("") : tip(help);
canvas.dataset.hovered = (+canvas.dataset.hovered|0) + 1;
};
+
+ if (type === "heightmap3DView") {
+ document.getElementById("preview3d").appendChild(canvas);
+ $("#preview3d").dialog({
+ title: "3D Preview", resizable: true,
+ position: {my: "left bottom", at: "left+10 bottom-20", of: "svg"},
+ resizeStop: resize3d, close: enterStandardView
+ });
+ } else document.body.insertBefore(canvas, optionsContainer);
+
toggle3dOptions();
}
+function resize3d() {
+ const canvas = document.getElementById("canvas3d");
+ canvas.width = parseFloat(preview3d.style.width);
+ canvas.height = parseFloat(preview3d.style.height) - 2;
+ ThreeD.redraw();
+}
+
function toggle3dOptions() {
if (options3dUpdate.offsetParent) {$("#options3d").dialog("close"); return;}
$("#options3d").dialog({
title: "3D mode settings", resizable: false, width: fitContent(),
- position: {my: "right top", at: "right-40 top+10", of: "svg", collision: "fit"}
+ position: {my: "right top", at: "right-30 top+10", of: "svg", collision: "fit"}
});
updateValues();