From 8abf443f700cd785d61bc6043f22ebe2b3557337 Mon Sep 17 00:00:00 2001 From: Azgaar Date: Mon, 29 Aug 2022 22:40:06 +0300 Subject: [PATCH] refactor: render covering layers --- package.json | 1 + src/assets/styles/ancient.json | 4 +- src/assets/styles/atlas.json | 4 +- src/assets/styles/clean.json | 4 +- src/assets/styles/cyberpunk.json | 4 +- src/assets/styles/default.json | 4 +- src/assets/styles/gloom.json | 4 +- src/assets/styles/light.json | 4 +- src/assets/styles/monochrome.json | 4 +- src/assets/styles/watercolor.json | 4 +- src/index.css | 2 +- src/layers/renderers/drawBiomes.js | 61 ------- src/layers/renderers/drawBiomes.ts | 29 ++++ src/layers/renderers/drawCultures.ts | 46 ++---- src/layers/renderers/drawFeatures.ts | 2 +- src/layers/renderers/drawReligions.js | 91 ----------- src/layers/renderers/drawReligions.ts | 28 ++++ src/layers/renderers/drawRoutes.ts | 5 +- src/layers/renderers/drawStates.js | 149 ------------------ src/layers/renderers/drawStates.ts | 48 ++++++ .../{utilts.ts => utils/getVertexPaths.ts} | 19 ++- src/scripts/generation/generation.ts | 12 +- .../pack/religions/generateReligions.ts | 2 - src/types/pack/states.d.ts | 1 + yarn.lock | 5 + 25 files changed, 171 insertions(+), 366 deletions(-) delete mode 100644 src/layers/renderers/drawBiomes.js create mode 100644 src/layers/renderers/drawBiomes.ts delete mode 100644 src/layers/renderers/drawReligions.js create mode 100644 src/layers/renderers/drawReligions.ts delete mode 100644 src/layers/renderers/drawStates.js create mode 100644 src/layers/renderers/drawStates.ts rename src/layers/renderers/{utilts.ts => utils/getVertexPaths.ts} (84%) diff --git a/package.json b/package.json index 4ee3b0c0..5754d5fc 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/delaunator": "^5.0.0", "@types/jquery": "^3.5.14", "@types/jqueryui": "^1.12.16", + "@types/polylabel": "^1.0.5", "c8": "^7.12.0", "happy-dom": "^6.0.4", "rollup": "^2.75.7", diff --git a/src/assets/styles/ancient.json b/src/assets/styles/ancient.json index ffc3e775..3f5b3281 100644 --- a/src/assets/styles/ancient.json +++ b/src/assets/styles/ancient.json @@ -78,13 +78,13 @@ "#relig": { "opacity": 0.7, "stroke": "#404040", - "stroke-width": 0.7, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.6, "stroke": "#777777", - "stroke-width": 0.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/atlas.json b/src/assets/styles/atlas.json index c26848a0..6a6917c3 100644 --- a/src/assets/styles/atlas.json +++ b/src/assets/styles/atlas.json @@ -78,13 +78,13 @@ "#relig": { "opacity": 0.7, "stroke": "#777777", - "stroke-width": 0, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.6, "stroke": "#777777", - "stroke-width": 0.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/clean.json b/src/assets/styles/clean.json index fd00c5ad..4fed8dea 100644 --- a/src/assets/styles/clean.json +++ b/src/assets/styles/clean.json @@ -79,13 +79,13 @@ "#relig": { "opacity": 0.7, "stroke": "#404040", - "stroke-width": 0.7, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.6, "stroke": "#777777", - "stroke-width": 0.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/cyberpunk.json b/src/assets/styles/cyberpunk.json index 579d093b..31c493f2 100644 --- a/src/assets/styles/cyberpunk.json +++ b/src/assets/styles/cyberpunk.json @@ -78,13 +78,13 @@ "#relig": { "opacity": 0.5, "stroke": "#404040", - "stroke-width": 2, + "stroke-width": 3, "filter": "url(#splotch)" }, "#cults": { "opacity": 0.35, "stroke": "#777777", - "stroke-width": 2, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": "url(#splotch)" diff --git a/src/assets/styles/default.json b/src/assets/styles/default.json index 37a52b33..775bdbd2 100644 --- a/src/assets/styles/default.json +++ b/src/assets/styles/default.json @@ -78,13 +78,13 @@ "#relig": { "opacity": 0.7, "stroke": "#777777", - "stroke-width": 0, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.6, "stroke": "#777777", - "stroke-width": 0.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/gloom.json b/src/assets/styles/gloom.json index 95dee382..b5096a95 100644 --- a/src/assets/styles/gloom.json +++ b/src/assets/styles/gloom.json @@ -79,13 +79,13 @@ "#relig": { "opacity": 0.7, "stroke": "#404040", - "stroke-width": 1, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.7, "stroke": "#777777", - "stroke-width": 1.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/light.json b/src/assets/styles/light.json index 6a225e86..b6dd72ed 100644 --- a/src/assets/styles/light.json +++ b/src/assets/styles/light.json @@ -78,13 +78,13 @@ "#relig": { "opacity": 0.5, "stroke": null, - "stroke-width": 0, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.5, "stroke": "#777777", - "stroke-width": 0, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/monochrome.json b/src/assets/styles/monochrome.json index e94f5a7b..0c843f0c 100644 --- a/src/assets/styles/monochrome.json +++ b/src/assets/styles/monochrome.json @@ -79,13 +79,13 @@ "#relig": { "opacity": 0.7, "stroke": "#404040", - "stroke-width": 0.7, + "stroke-width": 3, "filter": null }, "#cults": { "opacity": 0.6, "stroke": "#777777", - "stroke-width": 0.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": null diff --git a/src/assets/styles/watercolor.json b/src/assets/styles/watercolor.json index 99908126..24d7787b 100644 --- a/src/assets/styles/watercolor.json +++ b/src/assets/styles/watercolor.json @@ -78,13 +78,13 @@ "#relig": { "opacity": 0.7, "stroke": "#777777", - "stroke-width": 0, + "stroke-width": 3, "filter": "url(#bluredSplotch)" }, "#cults": { "opacity": 0.6, "stroke": "#777777", - "stroke-width": 0.5, + "stroke-width": 3, "stroke-dasharray": null, "stroke-linecap": null, "filter": "url(#splotch)" diff --git a/src/index.css b/src/index.css index b5180a25..a626de1c 100644 --- a/src/index.css +++ b/src/index.css @@ -102,7 +102,7 @@ a { } #biomes { - stroke-width: 0.7; + stroke-width: 3; } #landmass { diff --git a/src/layers/renderers/drawBiomes.js b/src/layers/renderers/drawBiomes.js deleted file mode 100644 index 5e406cb5..00000000 --- a/src/layers/renderers/drawBiomes.js +++ /dev/null @@ -1,61 +0,0 @@ -import {clipPoly} from "utils/lineUtils"; -import {TIME} from "config/logging"; - -export function drawBiomes() { - TIME && console.time("drawBiomes"); - biomes.selectAll("path").remove(); - - const {cells, vertices} = pack; - const n = cells.i.length; - - const used = new Uint8Array(cells.i.length); - const paths = new Array(biomesData.i.length).fill(""); - - for (const i of cells.i) { - if (!cells.biome[i]) continue; // no need to mark marine biome (liquid water) - if (used[i]) continue; // already marked - const b = cells.biome[i]; - const onborder = cells.c[i].some(n => cells.biome[n] !== b); - if (!onborder) continue; - const edgeVerticle = cells.v[i].find(v => vertices.c[v].some(i => cells.biome[i] !== b)); - const chain = connectVertices(edgeVerticle, b); - if (chain.length < 3) continue; - const points = clipPoly(chain.map(v => vertices.p[v])); - paths[b] += "M" + points.join("L") + "Z"; - } - - paths.forEach(function (d, i) { - if (d.length < 10) return; - biomes - .append("path") - .attr("d", d) - .attr("fill", biomesData.color[i]) - .attr("stroke", biomesData.color[i]) - .attr("id", "biome" + i); - }); - - // connect vertices to chain - function connectVertices(start, b) { - const chain = []; // vertices chain to form a path - for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) { - const prev = chain[chain.length - 1]; // previous vertex in chain - chain.push(current); // add current vertex to sequence - const c = vertices.c[current]; // cells adjacent to vertex - c.filter(c => cells.biome[c] === b).forEach(c => (used[c] = 1)); - const c0 = c[0] >= n || cells.biome[c[0]] !== b; - const c1 = c[1] >= n || cells.biome[c[1]] !== b; - const c2 = c[2] >= n || cells.biome[c[2]] !== b; - const v = vertices.v[current]; // neighboring vertices - if (v[0] !== prev && c0 !== c1) current = v[0]; - else if (v[1] !== prev && c1 !== c2) current = v[1]; - else if (v[2] !== prev && c0 !== c2) current = v[2]; - if (current === chain[chain.length - 1]) { - ERROR && console.error("Next vertex is not found"); - break; - } - } - return chain; - } - - TIME && console.timeEnd("drawBiomes"); -} diff --git a/src/layers/renderers/drawBiomes.ts b/src/layers/renderers/drawBiomes.ts new file mode 100644 index 00000000..382f858f --- /dev/null +++ b/src/layers/renderers/drawBiomes.ts @@ -0,0 +1,29 @@ +import {pick} from "utils/functionUtils"; +import {byId} from "utils/shorthands"; +import {getPaths} from "./utils/getVertexPaths"; + +export function drawBiomes() { + /* global */ const {cells, vertices, features} = pack; + /* global */ const colors = biomesData.color; + + const paths = getPaths({ + getType: (cellId: number) => cells.biome[cellId], + cells: pick(cells, "c", "v", "b", "h", "f"), + vertices, + features, + options: {fill: true, waterGap: true, halo: false} + }); + + console.log(paths); + + const htmlPaths = paths.map(([index, {fill, waterGap}]) => { + const color = colors[Number(index)]; + + return /* html */ ` + + + `; + }); + + byId("biomes")!.innerHTML = htmlPaths.join(""); +} diff --git a/src/layers/renderers/drawCultures.ts b/src/layers/renderers/drawCultures.ts index aa9189ef..9d3cdeae 100644 --- a/src/layers/renderers/drawCultures.ts +++ b/src/layers/renderers/drawCultures.ts @@ -1,44 +1,28 @@ -import * as d3 from "d3"; - -import {getPaths} from "./utilts"; import {pick} from "utils/functionUtils"; +import {byId} from "utils/shorthands"; +import {getPaths} from "./utils/getVertexPaths"; export function drawCultures() { - d3.select("#cults").selectAll("g").remove(); - - /* uses */ const {cells, vertices, features, cultures} = pack; + /* global */ const {cells, vertices, features, cultures} = pack; const paths = getPaths({ getType: (cellId: number) => cells.culture[cellId], cells: pick(cells, "c", "v", "b", "h", "f"), vertices, - features + features, + options: {fill: true, waterGap: true, halo: false} }); - const getColor = (i: number) => (cultures[i] as ICulture).color; + const getColor = (i: string) => (cultures[Number(i)] as ICulture).color; - d3.select("#cults") - .append("g") - .attr("fill", "none") - .attr("stroke-width", 3) - .selectAll("path") - .remove() - .data(paths) - .enter() - .append("path") - .attr("d", ([, path]) => path.waterGap) - .attr("stroke", ([i]) => getColor(Number(i))) - .attr("id", ([i]) => "culture-gap" + i); + const htmlPaths = paths.map(([index, {fill, waterGap}]) => { + const color = getColor(index); - d3.select("#cults") - .append("g") - .attr("stroke", "none") - .selectAll("path") - .remove() - .data(paths) - .enter() - .append("path") - .attr("d", ([, path]) => path.fill) - .attr("fill", ([i]) => getColor(Number(i))) - .attr("id", ([i]) => "culture" + i); + return /* html */ ` + + + `; + }); + + byId("cults")!.innerHTML = htmlPaths.join(""); } diff --git a/src/layers/renderers/drawFeatures.ts b/src/layers/renderers/drawFeatures.ts index 7832e84a..41ccba46 100644 --- a/src/layers/renderers/drawFeatures.ts +++ b/src/layers/renderers/drawFeatures.ts @@ -5,7 +5,7 @@ import {filterOutOfCanvasPoints} from "utils/lineUtils"; import {round} from "utils/stringUtils"; export function drawFeatures() { - /* uses */ const {vertices, features} = pack; + /* global */ const {vertices, features} = pack; const landMask = defs.select("#land"); const waterMask = defs.select("#water"); diff --git a/src/layers/renderers/drawReligions.js b/src/layers/renderers/drawReligions.js deleted file mode 100644 index e81810b4..00000000 --- a/src/layers/renderers/drawReligions.js +++ /dev/null @@ -1,91 +0,0 @@ -export function drawReligions() { - relig.selectAll("path").remove(); - const {cells, vertices, religions} = pack; - const n = cells.i.length; - - const used = new Uint8Array(cells.i.length); - const body = new Array(religions.length).fill(""); // store path around each religion - const gap = new Array(religions.length).fill(""); // store path along water for each religion to fill the gaps - - for (const i of cells.i) { - if (!cells.religion[i]) continue; - if (used[i]) continue; - used[i] = 1; - const r = cells.religion[i]; - const onborder = cells.c[i].filter(n => cells.religion[n] !== r); - if (!onborder.length) continue; - const borderWith = cells.c[i].map(c => cells.religion[c]).find(n => n !== r); - const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.religion[i] === borderWith)); - const chain = connectVertices(vertex, r, borderWith); - if (chain.length < 3) continue; - const points = chain.map(v => vertices.p[v[0]]); - - body[r] += "M" + points.join("L") + "Z"; - gap[r] += - "M" + - vertices.p[chain[0][0]] + - chain.reduce( - (r2, v, i, d) => - !i ? r2 : !v[2] ? r2 + "L" + vertices.p[v[0]] : d[i + 1] && !d[i + 1][2] ? r2 + "M" + vertices.p[v[0]] : r2, - "" - ); - } - - const bodyData = body.map((p, i) => [p.length > 10 ? p : null, i, religions[i].color]).filter(d => d[0]); - relig - .selectAll("path") - .data(bodyData) - .enter() - .append("path") - .attr("d", d => d[0]) - .attr("fill", d => d[2]) - .attr("id", d => "religion" + d[1]); - - const gapData = gap.map((p, i) => [p.length > 10 ? p : null, i, religions[i].color]).filter(d => d[0]); - relig - .selectAll(".path") - .data(gapData) - .enter() - .append("path") - .attr("d", d => d[0]) - .attr("fill", "none") - .attr("stroke", d => d[2]) - .attr("id", d => "religion-gap" + d[1]) - .attr("stroke-width", "10px"); - - // connect vertices to chain - function connectVertices(start, t, religion) { - const chain = []; // vertices chain to form a path - let land = vertices.c[start].some(c => cells.h[c] >= 20 && cells.religion[c] !== t); - function check(i) { - religion = cells.religion[i]; - land = cells.h[i] >= 20; - } - - for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) { - const prev = chain[chain.length - 1] ? chain[chain.length - 1][0] : -1; // previous vertex in chain - chain.push([current, religion, land]); // add current vertex to sequence - const c = vertices.c[current]; // cells adjacent to vertex - c.filter(c => cells.religion[c] === t).forEach(c => (used[c] = 1)); - const c0 = c[0] >= n || cells.religion[c[0]] !== t; - const c1 = c[1] >= n || cells.religion[c[1]] !== t; - const c2 = c[2] >= n || cells.religion[c[2]] !== t; - const v = vertices.v[current]; // neighboring vertices - if (v[0] !== prev && c0 !== c1) { - current = v[0]; - check(c0 ? c[0] : c[1]); - } else if (v[1] !== prev && c1 !== c2) { - current = v[1]; - check(c1 ? c[1] : c[2]); - } else if (v[2] !== prev && c0 !== c2) { - current = v[2]; - check(c2 ? c[2] : c[0]); - } - if (current === chain[chain.length - 1][0]) { - ERROR && console.error("Next vertex is not found"); - break; - } - } - return chain; - } -} diff --git a/src/layers/renderers/drawReligions.ts b/src/layers/renderers/drawReligions.ts new file mode 100644 index 00000000..19c63354 --- /dev/null +++ b/src/layers/renderers/drawReligions.ts @@ -0,0 +1,28 @@ +import {pick} from "utils/functionUtils"; +import {byId} from "utils/shorthands"; +import {getPaths} from "./utils/getVertexPaths"; + +export function drawReligions() { + /* global */ const {cells, vertices, features, religions} = pack; + + const paths = getPaths({ + getType: (cellId: number) => cells.religion[cellId], + cells: pick(cells, "c", "v", "b", "h", "f"), + vertices, + features, + options: {fill: true, waterGap: true, halo: false} + }); + + const getColor = (i: string) => (religions[Number(i)] as IReligion).color; + + const htmlPaths = paths.map(([index, {fill, waterGap}]) => { + const color = getColor(index); + + return /* html */ ` + + + `; + }); + + byId("relig")!.innerHTML = htmlPaths.join(""); +} diff --git a/src/layers/renderers/drawRoutes.ts b/src/layers/renderers/drawRoutes.ts index f6362490..dc269981 100644 --- a/src/layers/renderers/drawRoutes.ts +++ b/src/layers/renderers/drawRoutes.ts @@ -10,9 +10,7 @@ const lineGenTypeMap: {[key in IRoute["type"]]: d3.CurveFactory | d3.CurveFactor }; export function drawRoutes() { - routes.selectAll("path").remove(); - - /* uses */ const {cells, burgs} = pack; + /* global */ const {cells, burgs} = pack; const lineGen = d3.line(); const SHARP_ANGLE = 135; @@ -32,6 +30,7 @@ export function drawRoutes() { routePaths[type].push(``); } + routes.selectAll("path").remove(); for (const type in routePaths) { routes.select(`[data-type=${type}]`).html(routePaths[type].join("")); } diff --git a/src/layers/renderers/drawStates.js b/src/layers/renderers/drawStates.js deleted file mode 100644 index 2c7e1cd7..00000000 --- a/src/layers/renderers/drawStates.js +++ /dev/null @@ -1,149 +0,0 @@ -import * as d3 from "d3"; - -import polylabel from "polylabel"; - -export function drawStates() { - regions.selectAll("path").remove(); - - const {cells, vertices, features} = pack; - const states = pack.states; - const n = cells.i.length; - - const used = new Uint8Array(cells.i.length); - const vArray = new Array(states.length); // store vertices array - const body = new Array(states.length).fill(""); // path around each state - const gap = new Array(states.length).fill(""); // path along water for each state to fill the gaps - const halo = new Array(states.length).fill(""); // path around states, but not lakes - - const getStringPoint = v => vertices.p[v[0]].join(","); - - // define inner-state lakes to omit on border render - const innerLakes = features.map(feature => { - if (feature.type !== "lake") return false; - - const shoreline = feature.shoreline || []; - const states = shoreline.map(i => cells.state[i]); - return new Set(states).size > 1 ? false : true; - }); - - for (const i of cells.i) { - if (!cells.state[i] || used[i]) continue; - const state = cells.state[i]; - - const onborder = cells.c[i].some(n => cells.state[n] !== state); - if (!onborder) continue; - - const borderWith = cells.c[i].map(c => cells.state[c]).find(n => n !== state); - const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.state[i] === borderWith)); - const chain = connectVertices(vertex, state); - - const noInnerLakes = chain.filter(v => v[1] !== "innerLake"); - if (noInnerLakes.length < 3) continue; - - // get path around the state - if (!vArray[state]) vArray[state] = []; - const points = noInnerLakes.map(v => vertices.p[v[0]]); - vArray[state].push(points); - body[state] += "M" + points.join("L"); - - // connect path for halo - let discontinued = true; - halo[state] += noInnerLakes - .map(v => { - if (v[1] === "border") { - discontinued = true; - return ""; - } - - const operation = discontinued ? "M" : "L"; - discontinued = false; - return `${operation}${getStringPoint(v)}`; - }) - .join(""); - - // connect gaps between state and water into a single path - discontinued = true; - gap[state] += chain - .map(v => { - if (v[1] === "land") { - discontinued = true; - return ""; - } - - const operation = discontinued ? "M" : "L"; - discontinued = false; - return `${operation}${getStringPoint(v)}`; - }) - .join(""); - } - - // find state visual center - vArray.forEach((ar, i) => { - const sorted = ar.sort((a, b) => b.length - a.length); // sort by points number - states[i].pole = polylabel(sorted, 1.0); // pole of inaccessibility - }); - - const bodyData = body.map((p, s) => [p.length > 10 ? p : null, s, states[s].color]).filter(d => d[0]); - const gapData = gap.map((p, s) => [p.length > 10 ? p : null, s, states[s].color]).filter(d => d[0]); - const haloData = halo.map((p, s) => [p.length > 10 ? p : null, s, states[s].color]).filter(d => d[0]); - - const bodyString = bodyData.map(d => ``).join(""); - const gapString = gapData.map(d => ``).join(""); - const clipString = bodyData - .map(d => ``) - .join(""); - const haloString = haloData - .map( - d => - `` - ) - .join(""); - - statesBody.html(bodyString + gapString); - defs.select("#statePaths").html(clipString); - statesHalo.html(haloString); - - // connect vertices to chain - function connectVertices(start, state) { - const chain = []; // vertices chain to form a path - const getType = c => { - const borderCell = c.find(i => cells.b[i]); - if (borderCell) return "border"; - - const waterCell = c.find(i => cells.h[i] < 20); - if (!waterCell) return "land"; - if (innerLakes[cells.f[waterCell]]) return "innerLake"; - return features[cells.f[waterCell]].type; - }; - - for (let i = 0, current = start; i === 0 || (current !== start && i < 20000); i++) { - const prev = chain.length ? chain[chain.length - 1][0] : -1; // previous vertex in chain - - const c = vertices.c[current]; // cells adjacent to vertex - chain.push([current, getType(c)]); // add current vertex to sequence - - c.filter(c => cells.state[c] === state).forEach(c => (used[c] = 1)); - const c0 = c[0] >= n || cells.state[c[0]] !== state; - const c1 = c[1] >= n || cells.state[c[1]] !== state; - const c2 = c[2] >= n || cells.state[c[2]] !== state; - - const v = vertices.v[current]; // neighboring vertices - - if (v[0] !== prev && c0 !== c1) current = v[0]; - else if (v[1] !== prev && c1 !== c2) current = v[1]; - else if (v[2] !== prev && c0 !== c2) current = v[2]; - - if (current === prev) { - ERROR && console.error("Next vertex is not found"); - break; - } - } - - if (chain.length) chain.push(chain[0]); - return chain; - } - - Zoom.invoke(); -} diff --git a/src/layers/renderers/drawStates.ts b/src/layers/renderers/drawStates.ts new file mode 100644 index 00000000..1c5f65b2 --- /dev/null +++ b/src/layers/renderers/drawStates.ts @@ -0,0 +1,48 @@ +import * as d3 from "d3"; + +import {pick} from "utils/functionUtils"; +import {byId} from "utils/shorthands"; +import {getPaths} from "./utils/getVertexPaths"; + +export function drawStates() { + /* global */ const {cells, vertices, features, states} = pack; + + const paths = getPaths({ + getType: (cellId: number) => cells.state[cellId], + cells: pick(cells, "c", "v", "b", "h", "f"), + vertices, + features, + options: {fill: true, waterGap: true, halo: true} + }); + + const getColor = (i: number) => (states[i] as IState).color; + + const maxLength = states.length - 1; + const bodyPaths = new Array(maxLength); + const clipPaths = new Array(maxLength); + const haloPaths = new Array(maxLength); + + for (const [index, {fill, waterGap, halo}] of paths) { + const color = getColor(Number(index)); + const haloColor = d3.color(color)?.darker().formatHex() || "#666666"; + + bodyPaths.push(/* html */ ` + + + `); + + clipPaths.push(/* html */ ` + + `); + + haloPaths.push(/* html */ ` + + `); + } + + byId("statesBody")!.innerHTML = bodyPaths.join(""); + byId("statePaths")!.innerHTML = clipPaths.join(""); + byId("statesHalo")!.innerHTML = haloPaths.join(""); + + /* global */ window.Zoom.invoke(); +} diff --git a/src/layers/renderers/utilts.ts b/src/layers/renderers/utils/getVertexPaths.ts similarity index 84% rename from src/layers/renderers/utilts.ts rename to src/layers/renderers/utils/getVertexPaths.ts index 7931004a..6231c359 100644 --- a/src/layers/renderers/utilts.ts +++ b/src/layers/renderers/utils/getVertexPaths.ts @@ -8,12 +8,14 @@ export function getPaths({ vertices, getType, features, - cells + cells, + options }: { vertices: IGraphVertices; getType: (cellId: number) => number; features: TPackFeatures; cells: Pick; + options: {[key in keyof TPath]: boolean}; }) { const paths: Dict = {}; @@ -55,11 +57,12 @@ export function getPaths({ function getFillPath(vertexChain: number[]) { const points: TPoints = vertexChain.map(getVertexPoint); const firstPoint = points.shift(); - return `M${firstPoint} L${points.join(" ")} Z`; + return `M${firstPoint} L${points.join(" ")}`; } function getBorderPath(vertexChain: number[], discontinue: (vertex: number) => boolean) { let discontinued = true; + let lastOperation = ""; const path = vertexChain.map(vertex => { if (discontinue(vertex)) { discontinued = true; @@ -67,8 +70,12 @@ export function getPaths({ } const operation = discontinued ? "M" : "L"; + const command = operation === lastOperation ? "" : operation; + discontinued = false; - return ` ${operation}${getVertexPoint(vertex)}`; + lastOperation = operation; + + return ` ${command}${getVertexPoint(vertex)}`; }); return path.join("").trim(); @@ -87,9 +94,9 @@ export function getPaths({ function addPath(index: number, vertexChain: number[]) { if (!paths[index]) paths[index] = {fill: "", waterGap: "", halo: ""}; - paths[index].fill += getFillPath(vertexChain); - paths[index].halo += getBorderPath(vertexChain, isBorderVertex); - paths[index].waterGap += getBorderPath(vertexChain, isLandVertex); + if (options.fill) paths[index].fill += getFillPath(vertexChain); + if (options.halo) paths[index].halo += getBorderPath(vertexChain, isBorderVertex); + if (options.waterGap) paths[index].waterGap += getBorderPath(vertexChain, isLandVertex); } } diff --git a/src/scripts/generation/generation.ts b/src/scripts/generation/generation.ts index 6d776f82..0b83ef0f 100644 --- a/src/scripts/generation/generation.ts +++ b/src/scripts/generation/generation.ts @@ -26,7 +26,8 @@ import {createGrid} from "./grid/grid"; import {createPack} from "./pack/pack"; import {getInputValue, setInputValue} from "utils/nodeUtils"; import {calculateMapCoordinates} from "modules/coordinates"; -import {drawPolygons} from "utils/debugUtils"; +import {drawPoint, drawPolygons} from "utils/debugUtils"; +import {isReligion} from "utils/typeUtils"; const {Zoom, ThreeD} = window; @@ -70,10 +71,15 @@ async function generate(options?: IGenerationOptions) { // renderLayer("biomes"); renderLayer("burgs"); renderLayer("routes"); - renderLayer("cultures"); - //renderLayer("religions"); + // renderLayer("states"); + renderLayer("religions"); // drawPolygons(pack.cells.religion, pack.cells.v, pack.vertices.p, {fillOpacity: 0.8, excludeZeroes: true}); + pack.religions.filter(isReligion).forEach(({center}) => + drawPoint(pack.cells.p[center], { + radius: 5 + }) + ); WARN && console.warn(`TOTAL: ${rn((performance.now() - timeStart) / 1000, 2)}s`); // showStatistics(); diff --git a/src/scripts/generation/pack/religions/generateReligions.ts b/src/scripts/generation/pack/religions/generateReligions.ts index 8a92c224..c0dfe85a 100644 --- a/src/scripts/generation/pack/religions/generateReligions.ts +++ b/src/scripts/generation/pack/religions/generateReligions.ts @@ -32,8 +32,6 @@ export function generateReligions({ pick(cells, "i", "c", "biome", "culture", "burg", "state", "route") ); - console.log(religions); - TIME && console.timeEnd("generateReligions"); return {religionIds, religions}; } diff --git a/src/types/pack/states.d.ts b/src/types/pack/states.d.ts index 01c216e8..1a104e4b 100644 --- a/src/types/pack/states.d.ts +++ b/src/types/pack/states.d.ts @@ -9,6 +9,7 @@ interface IState { fullName: string; capital: Logical; coa: ICoa | string; + // pole: TPoint ? removed?: boolean; } diff --git a/yarn.lock b/yarn.lock index b0f6d4ff..e5e80b0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -422,6 +422,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== +"@types/polylabel@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/polylabel/-/polylabel-1.0.5.tgz#9262f269de36f1e9248aeb9dee0ee9d10065e043" + integrity sha512-gnaNmo1OJiYNBFAZMZdqLZ3hKx2ee4ksAzqhKWBxuQ61PmhINHMcvIqsGmyCD1WFKCkwRt9NFhMSmKE6AgYY+w== + "@types/qs@^6.2.31": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"