not bad city system
This commit is contained in:
parent
f5e7a1df1d
commit
15c1031d72
6 changed files with 329 additions and 195 deletions
102
renderer.js
102
renderer.js
|
|
@ -407,16 +407,16 @@ function discreteColor(map, x, y, mode) {
|
|||
color = [160, 205, 239];
|
||||
} else if (mode === "landuse") {
|
||||
const colors = {
|
||||
0: [242, 248, 238], // rural / natural land
|
||||
1: [238, 246, 222], // farmland
|
||||
2: [240, 238, 232], // old urban
|
||||
3: [245, 230, 220], // CBD / DID core
|
||||
4: [250, 248, 245], // suburb
|
||||
5: [235, 235, 240], // industrial
|
||||
6: [240, 245, 240], // logistics
|
||||
7: [245, 248, 252], // new town
|
||||
8: [250, 248, 240], // roadside
|
||||
9: [225, 238, 220], // forest / mountain land
|
||||
0: [244, 247, 240], // rural / natural land
|
||||
1: [222, 236, 188], // farmland
|
||||
2: [232, 222, 214], // old urban
|
||||
3: [221, 188, 184], // CBD / DID core
|
||||
4: [235, 225, 236], // suburb
|
||||
5: [223, 224, 232], // industrial
|
||||
6: [232, 237, 232], // logistics
|
||||
7: [231, 236, 246], // new town
|
||||
8: [243, 233, 210], // roadside
|
||||
9: [221, 236, 216], // forest / mountain land
|
||||
};
|
||||
color = colors[map.landuse[i]] || colors[0];
|
||||
} else if (mode === "admin") {
|
||||
|
|
@ -573,24 +573,25 @@ function drawSegments(ctx, segments, color, width, dashed = false) {
|
|||
}
|
||||
|
||||
function drawUrbanAreas(ctx, map, mode) {
|
||||
const visibleModes = ["all", "modern", "development", "landuse", "roads", "admin"];
|
||||
const visibleModes = ["all", "modern", "development", "landuse", "admin"];
|
||||
if (!visibleModes.includes(mode)) return;
|
||||
|
||||
const colors = {
|
||||
2: "rgba(225, 222, 215, 0.6)",
|
||||
3: "rgba(240, 220, 205, 0.85)",
|
||||
4: "rgba(242, 240, 235, 0.5)",
|
||||
5: "rgba(220, 220, 225, 0.6)",
|
||||
6: "rgba(225, 230, 225, 0.5)",
|
||||
7: "rgba(235, 240, 245, 0.6)",
|
||||
8: "rgba(245, 242, 235, 0.5)",
|
||||
2: "rgba(223, 214, 206, 0.72)",
|
||||
3: "rgba(215, 175, 172, 0.88)",
|
||||
4: "rgba(231, 219, 231, 0.68)",
|
||||
5: "rgba(218, 218, 226, 0.64)",
|
||||
6: "rgba(225, 230, 225, 0.56)",
|
||||
7: "rgba(229, 234, 242, 0.64)",
|
||||
8: "rgba(244, 230, 205, 0.62)",
|
||||
};
|
||||
|
||||
ctx.save();
|
||||
for (let y = 0; y < MAP_H; y++) {
|
||||
for (let x = 0; x < MAP_W; x++) {
|
||||
const i = indexOf(x, y);
|
||||
if (!map.prefectureMask[i]) continue;
|
||||
const areaMask = map.humanRegionMask || map.prefectureMask;
|
||||
if (areaMask && !areaMask[i]) continue;
|
||||
const lu = map.landuse[i];
|
||||
if (!colors[lu]) continue;
|
||||
|
||||
|
|
@ -678,6 +679,42 @@ function drawLabels(ctx, points, limit = Infinity) {
|
|||
for (const p of prioritized.slice(0, limit)) labelWithCollision(ctx, p, occupied);
|
||||
}
|
||||
|
||||
function drawScaleBar(ctx) {
|
||||
const kmPerCell = 2;
|
||||
const targetKm = 20;
|
||||
const lengthCells = Math.max(8, Math.round(targetKm / kmPerCell));
|
||||
const lengthPx = lengthCells * CELL_SIZE;
|
||||
const margin = 14;
|
||||
const x = margin;
|
||||
const y = margin + 18;
|
||||
|
||||
ctx.save();
|
||||
ctx.lineCap = "butt";
|
||||
ctx.strokeStyle = "rgba(0,0,0,0.78)";
|
||||
ctx.lineWidth = 2.2;
|
||||
ctx.fillStyle = "rgba(255,255,255,0.92)";
|
||||
ctx.fillRect(x - 8, y - 18, lengthPx + 16, 30);
|
||||
ctx.strokeStyle = "rgba(80,80,80,0.22)";
|
||||
ctx.strokeRect(x - 8, y - 18, lengthPx + 16, 30);
|
||||
ctx.strokeStyle = "rgba(30,30,30,0.82)";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + lengthPx, y);
|
||||
ctx.stroke();
|
||||
for (let t = 0; t <= 2; t++) {
|
||||
const tx = x + (lengthPx * t) / 2;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(tx, y - 5);
|
||||
ctx.lineTo(tx, y + 5);
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.fillStyle = "rgba(20,20,20,0.88)";
|
||||
ctx.font = "600 11px ui-sans-serif, system-ui, -apple-system, sans-serif";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(`${targetKm} km`, x + lengthPx / 2, y - 7);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
export function drawMap(canvas, map, options) {
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
|
@ -749,9 +786,9 @@ export function drawMap(canvas, map, options) {
|
|||
}
|
||||
|
||||
const showHistory = ["history", "all", "terrain"].includes(mode);
|
||||
const showModern = ["modern", "all", "development", "landuse", "roads", "admin-debug", "borders-debug"].includes(mode);
|
||||
const showRoads = ["roads", "all", "development"].includes(mode);
|
||||
const showMinorRoads = ["roads", "all", "modern", "development"].includes(mode);
|
||||
const showModern = ["modern", "all", "development", "landuse", "admin-debug", "borders-debug"].includes(mode);
|
||||
const showRoads = ["all", "development"].includes(mode);
|
||||
const showMinorRoads = ["all", "modern", "development"].includes(mode);
|
||||
const showAdmin = ["admin", "all", "admin-debug", "borders-debug"].includes(mode);
|
||||
|
||||
// 3. Borders
|
||||
|
|
@ -829,11 +866,15 @@ export function drawMap(canvas, map, options) {
|
|||
|
||||
if (showModern) {
|
||||
for (const p of map.stations) dot(ctx, p, 2.5, "#fff", "#444");
|
||||
const allLayerTowns = mode === "all"
|
||||
? (map.markets || []).filter((p) => (p.population || 0) >= 25000 && !(map.modernCities || []).some((c) => c.x === p.x && c.y === p.y))
|
||||
: [];
|
||||
for (const p of allLayerTowns) dot(ctx, p, 3.1, "rgba(244, 164, 118, 0.92)", "rgba(255,255,255,0.88)");
|
||||
for (const p of map.modernCities) {
|
||||
const popRadius = p.population ? Math.min(8.5, 3.5 + Math.sqrt(p.population) / 400) : 4.5;
|
||||
const popRadius = p.population ? Math.min(9.4, 3.8 + Math.sqrt(p.population) / 360) : 4.8;
|
||||
dot(ctx, p, popRadius, "rgba(240, 110, 110, 0.95)", "rgba(255,255,255,0.9)");
|
||||
if (p.isPrefecturalCapital) dot(ctx, p, popRadius + 3.0, "transparent", "rgba(200,80,80,0.9)");
|
||||
else if (p.isRegionalCapital) dot(ctx, p, popRadius + 2.2, "transparent", "rgba(190,95,95,0.62)");
|
||||
if (p.isPrefecturalCapital) dot(ctx, p, popRadius + 3.4, "transparent", "rgba(200,80,80,0.9)");
|
||||
else if (p.isRegionalCapital) dot(ctx, p, popRadius + 2.4, "transparent", "rgba(190,95,95,0.62)");
|
||||
}
|
||||
for (const p of map.interchanges || []) dot(ctx, p, 2.7, "rgba(250, 250, 245, 0.95)", "rgba(95, 125, 95, 0.95)");
|
||||
if (mode === "admin-debug" || mode === "borders-debug") {
|
||||
|
|
@ -845,17 +886,24 @@ export function drawMap(canvas, map, options) {
|
|||
if (showLabels) {
|
||||
if (mode === "admin") {
|
||||
drawLabels(ctx, map.adminCenters || [], Infinity);
|
||||
drawScaleBar(ctx);
|
||||
return;
|
||||
}
|
||||
if (mode === "admin-debug" || mode === "borders-debug") {
|
||||
drawLabels(ctx, map.adminCenters || [], Infinity);
|
||||
drawScaleBar(ctx);
|
||||
return;
|
||||
}
|
||||
const allLayerTowns = mode === "all"
|
||||
? (map.markets || []).filter((p) => (p.population || 0) >= 25000 && !(map.modernCities || []).some((c) => c.x === p.x && c.y === p.y)).map((p) => ({ ...p, labelPriorityBase: 120 }))
|
||||
: [];
|
||||
const important = [
|
||||
...map.modernCities,
|
||||
...map.ports,
|
||||
...(map.satelliteCities || []),
|
||||
].filter((p) => p.insidePrefecture || p.isRegionalCapital || p.kind === "External Gateway");
|
||||
drawLabels(ctx, important, 60);
|
||||
...allLayerTowns,
|
||||
].filter((p) => p.insidePrefecture || p.isRegionalCapital || p.kind === "External Gateway" || (p.population || 0) >= 25000);
|
||||
drawLabels(ctx, important, mode === "all" ? 85 : 60);
|
||||
}
|
||||
drawScaleBar(ctx);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue