diff --git a/public/index.css b/public/index.css index c46fded9a..8d5ed9053 100644 --- a/public/index.css +++ b/public/index.css @@ -133,6 +133,10 @@ a { fill-rule: evenodd; } +#lakes { + mask: url(#water); +} + #lakes, #coastline, #armies, diff --git a/public/main.js b/public/main.js index 033181cbf..6786852a6 100644 --- a/public/main.js +++ b/public/main.js @@ -40,10 +40,10 @@ let legend = svg.append("g").attr("id", "legend"); let ocean = viewbox.append("g").attr("id", "ocean"); let oceanLayers = ocean.append("g").attr("id", "oceanLayers"); let oceanPattern = ocean.append("g").attr("id", "oceanPattern"); -let lakes = viewbox.append("g").attr("id", "lakes"); let landmass = viewbox.append("g").attr("id", "landmass"); let texture = viewbox.append("g").attr("id", "texture"); let terrs = viewbox.append("g").attr("id", "terrs"); +let lakes = viewbox.append("g").attr("id", "lakes"); let biomes = viewbox.append("g").attr("id", "biomes"); let cells = viewbox.append("g").attr("id", "cells"); let gridOverlay = viewbox.append("g").attr("id", "gridOverlay"); diff --git a/public/modules/io/load.js b/public/modules/io/load.js index f1ee17e4c..3d41752f3 100644 --- a/public/modules/io/load.js +++ b/public/modules/io/load.js @@ -434,6 +434,7 @@ async function parseLoadedData(data, mapVersion) { // turn on active layers if (hasChild(texture, "image")) turnOn("toggleTexture"); if (hasChildren(terrs.select("#landHeights"))) turnOn("toggleHeight"); + if (isVisible(lakes)) turnOn("toggleLakes"); if (hasChildren(biomes)) turnOn("toggleBiomes"); if (hasChildren(cells)) turnOn("toggleCells"); if (hasChildren(gridOverlay)) turnOn("toggleGrid"); diff --git a/public/modules/ui/hotkeys.js b/public/modules/ui/hotkeys.js index 4b1e626d5..8dd54f022 100644 --- a/public/modules/ui/hotkeys.js +++ b/public/modules/ui/hotkeys.js @@ -61,6 +61,7 @@ function handleKeyup(event) { else if (key === "%") toggleAddMarker(); else if (code === "KeyX") toggleTexture(); else if (code === "KeyH") toggleHeight(); + else if (code === "KeyQ") toggleLakes(); else if (code === "KeyB") toggleBiomes(); else if (code === "KeyE") toggleCells(); else if (code === "KeyG") toggleGrid(); diff --git a/public/modules/ui/layers.js b/public/modules/ui/layers.js index f2f04a4be..10123b386 100644 --- a/public/modules/ui/layers.js +++ b/public/modules/ui/layers.js @@ -11,6 +11,7 @@ function getDefaultPresets() { "toggleBurgIcons", "toggleIce", "toggleLabels", + "toggleLakes", "toggleRivers", "toggleRoutes", "toggleScaleBar", @@ -22,6 +23,7 @@ function getDefaultPresets() { "toggleBurgIcons", "toggleCultures", "toggleLabels", + "toggleLakes", "toggleRivers", "toggleRoutes", "toggleScaleBar", @@ -31,6 +33,7 @@ function getDefaultPresets() { "toggleBorders", "toggleBurgIcons", "toggleLabels", + "toggleLakes", "toggleReligions", "toggleRivers", "toggleRoutes", @@ -40,19 +43,21 @@ function getDefaultPresets() { provinces: [ "toggleBorders", "toggleBurgIcons", + "toggleLakes", "toggleProvinces", "toggleRivers", "toggleScaleBar", "toggleVignette" ], - biomes: ["toggleBiomes", "toggleIce", "toggleRivers", "toggleScaleBar", "toggleVignette"], - heightmap: ["toggleHeight", "toggleRivers", "toggleVignette"], - physical: ["toggleCoordinates", "toggleHeight", "toggleIce", "toggleRivers", "toggleScaleBar", "toggleVignette"], + biomes: ["toggleBiomes", "toggleIce", "toggleLakes", "toggleRivers", "toggleScaleBar", "toggleVignette"], + heightmap: ["toggleHeight", "toggleLakes", "toggleRivers", "toggleVignette"], + physical: ["toggleCoordinates", "toggleHeight", "toggleIce", "toggleLakes", "toggleRivers", "toggleScaleBar", "toggleVignette"], poi: [ "toggleBorders", "toggleBurgIcons", "toggleHeight", "toggleIce", + "toggleLakes", "toggleMarkers", "toggleRivers", "toggleRoutes", @@ -63,6 +68,7 @@ function getDefaultPresets() { "toggleBorders", "toggleBurgIcons", "toggleLabels", + "toggleLakes", "toggleMilitary", "toggleRivers", "toggleRoutes", @@ -75,6 +81,7 @@ function getDefaultPresets() { "toggleBurgIcons", "toggleIce", "toggleEmblems", + "toggleLakes", "toggleRivers", "toggleRoutes", "toggleScaleBar", @@ -709,6 +716,18 @@ function toggleRelief(event) { } } +function toggleLakes(event) { + if (!layerIsOn("toggleLakes")) { + turnButtonOn("toggleLakes"); + $("#lakes").fadeIn(); + if (event && isCtrlClick(event)) editStyle("lakes"); + } else { + if (event && isCtrlClick(event)) return editStyle("lakes"); + $("#lakes").fadeOut(); + turnButtonOff("toggleLakes"); + } +} + function toggleTexture(event) { if (!layerIsOn("toggleTexture")) { turnButtonOn("toggleTexture"); @@ -979,6 +998,7 @@ function moveLayer(event, ui) { // define connection between option layer buttons and actual svg groups to move the element function getLayer(id) { + if (id === "toggleLakes") return $("#lakes"); if (id === "toggleHeight") return $("#terrs"); if (id === "toggleBiomes") return $("#biomes"); if (id === "toggleCells") return $("#cells"); diff --git a/src/index.html b/src/index.html index e4958414e..f32c80ed0 100644 --- a/src/index.html +++ b/src/index.html @@ -513,6 +513,14 @@ > Heightmap +
  • + Lakes +
  • { html.landMask.push( ``, ); + html.waterMask.push( + ``, + ); const lakeGroup = feature.group || "freshwater"; if (!html.lakes[lakeGroup]) html.lakes[lakeGroup] = []; diff --git a/tests/e2e/lakes-layer.spec.ts b/tests/e2e/lakes-layer.spec.ts new file mode 100644 index 000000000..0d9a19102 --- /dev/null +++ b/tests/e2e/lakes-layer.spec.ts @@ -0,0 +1,103 @@ +import { test, expect } from "@playwright/test"; + +test.describe("Lakes layer", () => { + test.beforeEach(async ({ context, page }) => { + await context.clearCookies(); + + await page.goto("/"); + await page.evaluate(() => { + localStorage.clear(); + sessionStorage.clear(); + }); + + await page.goto("/?seed=test-seed&width=1280&height=720"); + + // Wait for map generation to complete + await page.waitForFunction(() => (window as any).mapId !== undefined, { + timeout: 60000, + }); + + // Wait for any post-generation rendering to settle + await page.waitForTimeout(500); + }); + + test("lakes toggle button hides and shows the #lakes SVG group", async ({ + page, + }) => { + const lakes = page.locator("#lakes"); + + // Open the options panel (layers tab) so the toggle button is reachable + await page.evaluate(() => (window as any).showOptions()); + + // Lakes should be visible by default + await expect(lakes).toBeVisible(); + + // Click the toggle button to hide; wait for jQuery fadeOut to complete + await page.locator("#toggleLakes").click(); + await expect(lakes).toBeHidden(); + + // Click again to show; wait for jQuery fadeIn to complete + await page.locator("#toggleLakes").click(); + await expect(lakes).toBeVisible(); + }); + + test("KeyQ toggles the lakes layer", async ({ page }) => { + const lakes = page.locator("#lakes"); + + // Lakes should be visible by default + await expect(lakes).toBeVisible(); + + // Press Q to hide lakes; wait for jQuery fadeOut to complete + await page.keyboard.press("q"); + await expect(lakes).toBeHidden(); + + // Press Q again to show lakes; wait for jQuery fadeIn to complete + await page.keyboard.press("q"); + await expect(lakes).toBeVisible(); + }); + + test("Lakes panel entry is positioned just after Heightmap", async ({ + page, + }) => { + const [lakesIndex, heightmapIndex] = await page.evaluate(() => { + const items = Array.from( + document.querySelectorAll("#mapLayers > li") + ) as HTMLElement[]; + return [ + items.findIndex((li) => li.id === "toggleLakes"), + items.findIndex((li) => li.id === "toggleHeight"), + ]; + }); + + expect(lakesIndex).toBe(heightmapIndex + 1); + }); + + test("dragging Lakes above Heightmap in panel moves #lakes before #terrs in SVG", async ({ + page, + }) => { + // Confirm initial SVG order: #lakes is after #terrs (rendered above heightmap by default) + const initialOrder = await page.evaluate(() => { + const viewbox = document.getElementById("viewbox")!; + const ids = Array.from(viewbox.children).map((el) => el.id); + return { lakes: ids.indexOf("lakes"), terrs: ids.indexOf("terrs") }; + }); + expect(initialOrder.lakes).toBeGreaterThanOrEqual(0); + expect(initialOrder.terrs).toBeGreaterThanOrEqual(0); + expect(initialOrder.lakes).toBeGreaterThan(initialOrder.terrs); + + // Simulate what moveLayer does when the user drags Lakes above Heightmap: + // panel item "toggleLakes" is now before "toggleHeight" → el.insertBefore(#terrs) + await page.evaluate(() => { + const $ = (window as any).$; + $("#lakes").insertBefore($("#terrs")); + }); + + // After move: #lakes should be before #terrs in SVG → renders behind heightmap + const newOrder = await page.evaluate(() => { + const viewbox = document.getElementById("viewbox")!; + const ids = Array.from(viewbox.children).map((el) => el.id); + return { lakes: ids.indexOf("lakes"), terrs: ids.indexOf("terrs") }; + }); + expect(newOrder.lakes).toBeLessThan(newOrder.terrs); + }); +});