Merge remote-tracking branch 'origin/sub_laptop_7' into main_laptop_1

This commit is contained in:
2026-10-30 18:01:34 +09:00
5 changed files with 114 additions and 8 deletions
@@ -130,7 +130,7 @@ export function paintNetwork(
network.lines.forEach((line, index) => {
if (line.vertices.length < 2) return;
const color = index === active ? colors.active : routeColor(index);
const width = line.branch ? 2.5 : 3;
const width = 3;
const path = (vertices: ReadonlyArray<Vertex>): void => {
context.beginPath();
vertices.forEach((v, i) => {
+11 -2
View File
@@ -73,6 +73,7 @@ import {
import { layerCounts, legendRows, type Prepared } from "./D03_PlanAnalysis_UI_LayerLegend";
import { createCanvasLayers } from "./D03_PlanAnalysis_UI_LayerPaint";
import { createGlBase, GL_FONT, type GlImage } from "./D03_PlanAnalysis_UI_MapGl";
import { createSatLightRow, readSatLight } from "./D03_PlanAnalysis_UI_SatLight";
import {
openSlopeBands,
paintSlope,
@@ -208,11 +209,19 @@ export function createPlanLayers(opts: {
for (const def of LAYERS) gl.setVisible(def.key, on[def.key]);
gl.setData("hillshade", hillshade && (on.satellite ? hillshade.shade : hillshade.plain));
const rows = meta ? legendRows(on, data) : [];
legend.replaceChildren(...rows.map((row) => createLegend(row)));
const light = meta && glOn && on.satellite; // 옛 캔버스 = 위성 없음
legend.replaceChildren(...rows.map((row) => createLegend(row)), ...(light ? [lightRow] : []));
if (meta && on.slope && data.slope) legend.firstElementChild?.append(gear);
legend.hidden = !rows.length;
legend.hidden = !rows.length && !light;
}
/** 위성 밝기(요구 475) — 위성 켠 동안 범례 맨 아래 한 줄 · 바로 반영. */
gl.setSatelliteLight(readSatLight());
const lightRow = createSatLightRow(readSatLight(), (level) => {
gl.setSatelliteLight(level);
map.redrawBase();
});
/** 급경사 범위(603) — 바꾸면 범례 바로 · 그림은 다시 칠함(늦은 칠하기는 버림). */
let slopeBands = readSlopeBands();
let slopeTurn = 0;
+23 -5
View File
@@ -24,6 +24,7 @@ import {
import { themeColor } from "@ui/ui_template_palette";
import type { GeoJsonCollection } from "../B04_PreProcess/B04_PreProcess_UI_MapRender";
import type { PlanLayerKey } from "./D03_PlanAnalysis_UI_LayerDefs";
import { SAT_LIGHT_DEFAULT } from "./D03_PlanAnalysis_UI_SatLight";
export { GL_FONT, type GlImage };
@@ -38,6 +39,8 @@ export interface GlBase {
setVisible: (key: PlanLayerKey, on: boolean) => void;
/** 등고선 주곡선 간격(m) — 캔버스와 같은 「화면 안 가닥 수」 규칙. */
setContourStep: (step: number) => void;
/** 위성 밝기 상한(0~1) — 바로 반영 · 지도를 다시 세워도 유지. */
setSatelliteLight: (level: number) => void;
/** 켬 = 지도를 `parent` 맨 앞에 만듦(참 = 섬 · 거짓 = WebGL 못 씀) · null = 버림. */
enable: (parent: HTMLElement | null) => boolean;
map: () => MapLibreMap | null;
@@ -122,22 +125,27 @@ function fillEdge(
}
/** 겹 차례(아래 → 위)와 꼴 — 캔버스 `D03_PlanAnalysis_UI_Layers` 의 색 · 굵기 · 투명도 · 차례 그대로. */
function layerSpecs(step: number): GlSpec[] {
function layerSpecs(step: number, light: number): GlSpec[] {
const contour = themeColor("--draw-map-contour", "#ffd68c");
const place = themeColor("--draw-map-place", "#f8fafc");
const landslideZone = themeColor("--draw-map-landslide-zone", "#e11d48");
const raster = (key: GlSource | "satellite", opacity: number): GlSpec =>
const raster = (
key: GlSource | "satellite",
opacity: number,
extra: Record<string, number> = {},
): GlSpec =>
({
key,
id: key,
type: "raster",
source: key,
paint: { "raster-opacity": opacity, "raster-fade-duration": 0 },
paint: { "raster-opacity": opacity, "raster-fade-duration": 0, ...extra },
}) as GlSpec;
const lineKind = (key: "faults" | "lineaments" | "zeroOrder", width: number, pattern: number[]) =>
haloLine(key, key, themeColor(LINE_COLOR[key], "#f43f5e"), width, pattern);
return [
raster("satellite", 1),
// 위성 = 조금 어둡고 연하게(요구 475 · 노선 선 대비) — 밝기 상한은 사용자 조절
raster("satellite", 1, { "raster-brightness-max": light, "raster-saturation": SAT_SATURATION }),
raster("hillshade", 1), // 위성 위 = 「곱하기」와 같은 검은 그늘 그림(받는 쪽이 바꿈)
raster("slope", 0.55),
raster("landslide", 0.6),
@@ -313,10 +321,14 @@ const THEME_NAMES = [
"--draw-map-parcel",
] as const;
/** 위성 채도(−1~1) — 조금 연하게. */
const SAT_SATURATION = -0.3;
export function createGlBase(projectId: string, onFail: (why: string) => void): GlBase {
let step = 5;
let light = SAT_LIGHT_DEFAULT;
const base = createGlMap<PlanLayerKey>({
specs: () => layerSpecs(step),
specs: () => layerSpecs(step, light),
fixed: { satellite: satelliteTileSource(projectId) },
themeNames: THEME_NAMES,
className: "d03-plan__gl",
@@ -330,5 +342,11 @@ export function createGlBase(projectId: string, onFail: (why: string) => void):
const map = base.map();
if (map?.getLayer("contour-minor")) map.setFilter("contour-minor", minorFilter(step));
},
setSatelliteLight(next) {
light = next;
const map = base.map();
if (map?.getLayer("satellite"))
map.setPaintProperty("satellite", "raster-brightness-max", next);
},
};
}
@@ -0,0 +1,39 @@
/* =============================================================================
* D03_PlanAnalysis_UI_SatLight.ts
* D03 위성 바탕 밝기(요구 475) — 노선 선 대비를 위해 위성을 조금 어둡게 · 사용자가 범례에서 조절.
* 값 = 밝기 상한(0.4~1) · 계정 화면 취향으로 기억. 칠하기 = `D03_PlanAnalysis_UI_MapGl` `setSatelliteLight`.
* ========================================================================== */
import { createSlider } from "@ui/ui_template_input";
import { readByKey, writeByKey } from "../A00_Common/b_page_state";
const PREF_KEY = "aislo:pref:d03.satellite-light";
export const SAT_LIGHT_MIN = 0.4;
export const SAT_LIGHT_MAX = 1;
export const SAT_LIGHT_DEFAULT = 0.8;
/** 기억한 밝기 — 없거나 깨지면 처음 값. */
export function readSatLight(): number {
const value = Number(readByKey(PREF_KEY));
return readByKey(PREF_KEY) !== null && value >= SAT_LIGHT_MIN && value <= SAT_LIGHT_MAX
? value
: SAT_LIGHT_DEFAULT;
}
/** 범례 「위성 밝기」 칸 — 움직이면 바로 `onChange` · 기억. */
export function createSatLightRow(value: number, onChange: (value: number) => void): HTMLElement {
const { root, input } = createSlider({
label: "위성 밝기",
min: SAT_LIGHT_MIN,
max: SAT_LIGHT_MAX,
step: 0.05,
value,
format: (v) => `${Math.round(v * 100)} %`,
onInput: (v) => {
writeByKey(PREF_KEY, String(v));
onChange(v);
},
});
input.dataset.role = "satellite-light";
return root;
}
+40
View File
@@ -0,0 +1,40 @@
"""606-1 위성 바탕 밝기 지킴 — D03 위성 칠에 밝기 상한 · 채도 · 사용자 조절 칸 · 갈래 굵기 3 (B04 · B05 위성은 그대로).
./venv/Scripts/python.exe -m pytest resources/tester/test_606_1_sat_light.py -q
"""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
read = lambda rel: (ROOT / rel).read_text(encoding="utf-8") # noqa: E731
MAPGL = read("D03_PlanAnalysis/D03_PlanAnalysis_UI_MapGl.ts")
LIGHT = read("D03_PlanAnalysis/D03_PlanAnalysis_UI_SatLight.ts")
LAYERS = read("D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts")
def test_위성_칠에_밝기_채도():
assert re.search(r'raster\("satellite", 1, \{[^}]*"raster-brightness-max": light', MAPGL)
assert '"raster-saturation": SAT_SATURATION' in MAPGL
def test_밝기_처음값은_어둡게_범위_안():
m = {k: float(v) for k, v in re.findall(r"SAT_LIGHT_(MIN|MAX|DEFAULT) = ([\d.]+)", LIGHT)}
assert m["MIN"] < m["DEFAULT"] < m["MAX"] == 1
def test_조절_칸은_GL_위성_켠_때만_기억():
assert "createSatLightRow(" in LAYERS
assert "glOn && on.satellite" in LAYERS
assert "aislo:pref:d03.satellite-light" in LIGHT
def test_갈래_굵기_3():
paint = read("D03_PlanAnalysis/D03_PlanAnalysis_UI_DrawPaint.ts")
assert "const width = 3;" in paint
assert "branch ? 2.5" not in paint
def test_공용_GL_바탕은_안_바뀜():
assert "brightness" not in read("ui_template/ui_template_gl_map.ts")