feat(D03): 평면 도구줄을 공용 지도 도구줄로 — [?] 안내 · 측점 · 기울기 켬끔 더해 아홉 · 겹 단추 아이콘 (PLAN 568-3 · 569-2 · 요구 395)
- UI_Map — createMapTools · mapToolButton(되돌리기 · 다시하기 · 3D · 돌리기 둘 · 측점 · 기울기 · 거리 재기) · [?] 조작 안내 여덟 줄 · ScreenMap 에 측점 · 기울기 켬 실음 - UI_Draw — 측점 눈금 · 구간 길이 · 기울기 글을 켬끔 따라 그림 - UI_Layers — 겹 단추 글자 대신 공용 아이콘(satellite · droplet · borderAll · angle) - test_553_4 — 옛 createToolbar · createIconButton 지킴을 공용 도구줄 · 겹 단추 지킴으로 바꿈 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -360,18 +360,19 @@ export function createPlanDraw(params: PlanDrawParams): PlanDraw {
|
||||
else context.moveTo(sx, sy);
|
||||
});
|
||||
context.stroke();
|
||||
drawStationTicks(
|
||||
context,
|
||||
line.vertices.map(([x, y]) => ({ x, y })),
|
||||
{
|
||||
intervalM: PLAN_STATION_INTERVAL_M,
|
||||
pxPerMeter: map.pxPerMeter,
|
||||
toScreen: (x, y) => map.toScreen([x, y]),
|
||||
uprightRad: map.uprightRad,
|
||||
chainages: stationChainages(lineLength(line.vertices), PLAN_STATION_INTERVAL_M),
|
||||
},
|
||||
);
|
||||
segmentLabels(context, map, line.vertices);
|
||||
if (map.stations)
|
||||
drawStationTicks(
|
||||
context,
|
||||
line.vertices.map(([x, y]) => ({ x, y })),
|
||||
{
|
||||
intervalM: PLAN_STATION_INTERVAL_M,
|
||||
pxPerMeter: map.pxPerMeter,
|
||||
toScreen: (x, y) => map.toScreen([x, y]),
|
||||
uprightRad: map.uprightRad,
|
||||
chainages: stationChainages(lineLength(line.vertices), PLAN_STATION_INTERVAL_M),
|
||||
},
|
||||
);
|
||||
if (map.slopes) segmentLabels(context, map, line.vertices);
|
||||
});
|
||||
// 꺾임점
|
||||
context.fillStyle = "#ffffff";
|
||||
|
||||
@@ -44,20 +44,18 @@ export type PlanLayerKey = "satellite" | "contour" | "stream" | "cadastral" | "r
|
||||
|
||||
interface LayerDef {
|
||||
key: PlanLayerKey;
|
||||
/** 아이콘 — 없으면 글자 단추(`glyph`). */
|
||||
icon?: IconName;
|
||||
glyph?: string;
|
||||
icon: IconName;
|
||||
title: string;
|
||||
on: boolean;
|
||||
}
|
||||
|
||||
const LAYERS: readonly LayerDef[] = [
|
||||
{ key: "satellite", glyph: "위성", title: "위성사진", on: true },
|
||||
{ key: "satellite", icon: "satellite", title: "위성사진", on: true },
|
||||
{ key: "contour", icon: "mountain", title: "도엽 등고선(굵은 선 = 계곡선 25 m)", on: true },
|
||||
{ key: "stream", glyph: "세류", title: "세류선(가는 파랑) · 하천(굵은 파랑)", on: true },
|
||||
{ key: "cadastral", glyph: "지적", title: "지적도(참고용 · 법적 효력 없음)", on: false },
|
||||
{ key: "stream", icon: "droplet", title: "세류선(가는 파랑) · 하천(굵은 파랑)", on: true },
|
||||
{ key: "cadastral", icon: "borderAll", title: "지적도(참고용 · 법적 효력 없음)", on: false },
|
||||
{ key: "road", icon: "road", title: "기존 도로(도엽 도로중심선)", on: false },
|
||||
{ key: "slope", glyph: "경사", title: "급경사 색(15° · 35° · 40° 이상)", on: false },
|
||||
{ key: "slope", icon: "angle", title: "급경사 색(15° · 35° · 40° 이상)", on: false },
|
||||
];
|
||||
const PREF_KEY = "aislo:pref:d03.layers";
|
||||
/** 등고선을 받아 올 그은 선 둘레(m). */
|
||||
@@ -128,7 +126,6 @@ export function createPlanLayers(opts: {
|
||||
for (const def of LAYERS) {
|
||||
const button = createIconButton({
|
||||
icon: def.icon,
|
||||
glyph: def.glyph,
|
||||
title: def.title,
|
||||
pressed: on[def.key],
|
||||
onClick: () => toggle(def.key),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* =============================================================================
|
||||
* D03_PlanAnalysis_UI_Map.ts
|
||||
* D03 메인 평면(PLAN 530-3 · 562-3) — 위성 바탕 · 위에 겹(바탕 겹 569-2 · 그리기 · 거리재기) · 도구줄 여섯
|
||||
* (되돌리기 · 다시하기 · 3D · 좌회전 · 우회전 · 거리재기).
|
||||
* D03 메인 평면(PLAN 530-3 · 562-3) — 위성 바탕 · 위에 겹(바탕 겹 569-2 · 그리기 · 거리재기) · 도구줄 아홉
|
||||
* (공용 `createMapTools` 568-3 — [?] · 되돌리기 · 다시하기 · 3D · 좌회전 · 우회전 · 측점 · 기울기 · 거리재기).
|
||||
*
|
||||
* 셈 · 그리기는 B 부품 그대로(import 만) — 좌표 `createMetricProjector` · `screenToMetric` · 맞춤
|
||||
* `computeRouteView` · 휠 확대 · 가운데 단추 옮기기 `bindRouteEditNavigation` ·
|
||||
@@ -10,9 +10,8 @@
|
||||
* 겹은 돌리기 전 그림 좌표로 그리고 받음 — 누른 자리는 `unrotate` 로 되돌려 넘김.
|
||||
* ========================================================================== */
|
||||
|
||||
import { createIconButton } from "@ui/ui_template_button";
|
||||
import { createMapTools, mapToolButton } from "@ui/ui_template_map_tools";
|
||||
import { themeColor } from "@ui/ui_template_palette";
|
||||
import { createToolbar } from "@ui/ui_template_toolbar";
|
||||
import type { VWorldMeta } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
|
||||
import {
|
||||
computeMapRect,
|
||||
@@ -56,6 +55,9 @@ export interface ScreenMap {
|
||||
pxPerMeter: number;
|
||||
/** B04 그리기 틀(`drawPreparedLayer` 등이 받음). */
|
||||
view: ViewState;
|
||||
/** 측점 눈금 · 구간 길이 · 기울기 글 켬(도구줄 측점 · 기울기). */
|
||||
stations: boolean;
|
||||
slopes: boolean;
|
||||
/** 글자를 세울 각(라디안 · 안 돌렸으면 0). */
|
||||
uprightRad: number;
|
||||
/** (x, y) 둘레로 글자를 눈높이로 세워 그림(돌린 지도). */
|
||||
@@ -129,36 +131,44 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
const root = document.createElement("div");
|
||||
root.className = "d03-plan__map";
|
||||
const canvas = document.createElement("canvas");
|
||||
const tool = (
|
||||
act: string,
|
||||
icon: Parameters<typeof createIconButton>[0]["icon"],
|
||||
title: string,
|
||||
onClick?: () => void,
|
||||
): HTMLButtonElement => {
|
||||
const button = createIconButton({ icon, title, onClick });
|
||||
button.dataset.act = act;
|
||||
let marks = { stations: true, slopes: true };
|
||||
const markButton = (act: "stations" | "slopes", title: string): HTMLButtonElement => {
|
||||
const button = mapToolButton(act, {
|
||||
title,
|
||||
pressed: true,
|
||||
onClick: () => {
|
||||
marks = { ...marks, [act]: !marks[act] };
|
||||
button.setAttribute("aria-pressed", String(marks[act]));
|
||||
draw();
|
||||
},
|
||||
});
|
||||
return button;
|
||||
};
|
||||
const undoButton = tool("undo", "undo", "되돌리기(Ctrl+Z)", events.onUndo);
|
||||
const redoButton = tool("redo", "redo", "다시하기(Ctrl+Y)", events.onRedo);
|
||||
const viewButton = tool("view3d", "cube", "3D 보기", events.on3d);
|
||||
const measureButton = tool("measure", "ruler", "거리재기", events.onMeasure);
|
||||
measureButton.setAttribute("aria-pressed", "false");
|
||||
const toolbar = createToolbar({
|
||||
glass: true,
|
||||
size: 32,
|
||||
const undoButton = mapToolButton("undo", { onClick: events.onUndo });
|
||||
const redoButton = mapToolButton("redo", { onClick: events.onRedo });
|
||||
const viewButton = mapToolButton("view3d", { onClick: events.on3d });
|
||||
const measureButton = mapToolButton("measure", { onClick: events.onMeasure });
|
||||
const tools = createMapTools({
|
||||
label: "평면 도구",
|
||||
items: [
|
||||
undoButton,
|
||||
redoButton,
|
||||
"divider",
|
||||
viewButton,
|
||||
tool("rotate-ccw", "rotateCcw", "왼쪽으로 돌림(15°)"),
|
||||
tool("rotate-cw", "rotateCw", "오른쪽으로 돌림(15°)"),
|
||||
"divider",
|
||||
measureButton,
|
||||
hint: {
|
||||
lines: [
|
||||
"누름 = 점 찍기",
|
||||
"Enter = 긋기 끝",
|
||||
"Esc = 긋기 취소",
|
||||
"Backspace = 마지막 점 빼기",
|
||||
"오른쪽 누름 = 마크 지움",
|
||||
"가운데 끌기 = 옮기기",
|
||||
"휠 = 확대 · 축소",
|
||||
"Ctrl+휠 = 돌리기",
|
||||
],
|
||||
},
|
||||
groups: [
|
||||
[undoButton, redoButton],
|
||||
[viewButton, "rotate-ccw", "rotate-cw"],
|
||||
[markButton("stations", "측점"), markButton("slopes", "구간 길이 · 기울기"), measureButton],
|
||||
],
|
||||
});
|
||||
const toolbar = tools.root;
|
||||
toolbar.classList.add("d03-plan__tools");
|
||||
root.append(canvas, toolbar);
|
||||
const context = canvas.getContext("2d")!;
|
||||
@@ -187,6 +197,7 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
toMetric: (px, py) => screenToMetric(meta!, view, px, py),
|
||||
pxPerMeter: projector.pxPerMeter,
|
||||
view,
|
||||
...marks,
|
||||
uprightRad: rotation.uprightRad(),
|
||||
upright: (ctx, x, y, paint) => {
|
||||
const angle = rotation.uprightRad();
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
position: absolute;
|
||||
top: var(--spacing-8);
|
||||
right: var(--spacing-8);
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
/* 569-2 바탕 겹 단추 — 왼쪽 위 · 급경사 범례 — 왼쪽 아래 */
|
||||
|
||||
Reference in New Issue
Block a user