feat(D03): 연도 구역 마커 끌어 놓기 · 선 밖으로 끌어내 지움 · 긋는 해 걷음 · 갈래 시점 지정 (PLAN 585-3 · 요구 445 A6 · 446)
- 도구줄 「연도 마커」(공용 지도 도구줄 year-mark · 깃발 아이콘)를 선 위로 끌어 놓음 = 그 자리 구간을 둘로 — 구역만 나눔 · 해 그대로 - 끄는 동안 마름모 미리보기 · 선 끝 · 다른 마커 1 m 안 · 선 밖 = 경고 색 · 못 놓음 - 놓인 마커 끌기 = 경계 옮김 · 선 밖으로 끌어냄 · 오른쪽 누름 · Delete = 지움(앞 구간과 합침) · 같은 해 양쪽 = 속 빈 마름모 - 좌측 [연도 구분] · 「긋는 해」 걷음 · 새 선 = 사업연도 시작 해 · 새 갈래 = 붙은 자리 구간 해 - 속성 판 [갈래 시점 지정] = 다른 선에 닿은 끝을 시점(No.0)으로 갈래 · 꼬리에 닿은 머리 = 한 선 · 본선 = [방향 바꾸기] - 시험: 585-2 시험에 나눔 · 합침 · 갈래 해 · 갈래 시점 덧 · 530-3 갈래 해 · 553-4 속성 판 · 568-1 도구줄 목록 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,9 @@ import { createMapRotation } from "../B05_Profile/B05_Profile_UI_RouteEdit_Rotat
|
||||
import { fitCanvas, screenToMetric } from "../B05_Profile/B05_Profile_UI_RouteEdit_View";
|
||||
import type { Vertex } from "./logic/D03_PlanAnalysis_Plan";
|
||||
|
||||
/** 도구줄 「연도 마커」 끌어 놓기 자료 꼴(585-3). */
|
||||
export const YEAR_MARK_DRAG = "application/x-aislo-year-mark";
|
||||
|
||||
/** 측점 간격(m) — B 규칙 측점과 같음. */
|
||||
export const PLAN_STATION_INTERVAL_M = 20;
|
||||
/** 겹 그림 색(그림 전용 값 `--draw-*` · 밝음 · 어두움 같음) — 선 · 그리는 중 · 경고 · 글 테두리. */
|
||||
@@ -78,6 +81,9 @@ export interface PlanMapLayer {
|
||||
press?: (px: number, py: number, map: ScreenMap, button: 0 | 2, shift: boolean) => boolean;
|
||||
hover?: (px: number, py: number, map: ScreenMap) => void;
|
||||
release?: (map: ScreenMap) => void;
|
||||
/** 「연도 마커」를 끌고 지나감(참 = 받을 겹) · 놓음(참 = 받음) — 585-3. */
|
||||
dragOver?: (px: number, py: number, map: ScreenMap) => boolean;
|
||||
drop?: (px: number, py: number, map: ScreenMap) => boolean;
|
||||
leave?: () => void;
|
||||
}
|
||||
|
||||
@@ -94,6 +100,8 @@ export interface PlanTools {
|
||||
view3d: boolean;
|
||||
/** 거리재기 켜짐(눌림). */
|
||||
measure: boolean;
|
||||
/** 「연도 마커」 끌 수 있음(고칠 수 있고 선 있음). */
|
||||
yearMark: boolean;
|
||||
}
|
||||
|
||||
export interface PlanMap {
|
||||
@@ -161,6 +169,12 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
const redoButton = mapToolButton("redo", { onClick: events.onRedo });
|
||||
const viewButton = mapToolButton("view3d", { onClick: events.on3d });
|
||||
const measureButton = mapToolButton("measure", { onClick: events.onMeasure });
|
||||
const yearMarkButton = mapToolButton("year-mark", { disabled: true });
|
||||
yearMarkButton.draggable = true;
|
||||
yearMarkButton.addEventListener("dragstart", (event) => {
|
||||
event.dataTransfer?.setData(YEAR_MARK_DRAG, "1");
|
||||
if (event.dataTransfer) event.dataTransfer.effectAllowed = "copy";
|
||||
});
|
||||
const tools = createMapTools({
|
||||
label: "평면 도구",
|
||||
hint: {
|
||||
@@ -174,7 +188,8 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
"Shift+누름 = 구간 더함 · 뺌",
|
||||
"빈 곳 오른쪽으로 끌기 = 창 안 구간 · 왼쪽으로 = 걸친 구간까지",
|
||||
"고른 선 위 끌기 = 꺾임점 더해 옮김",
|
||||
"꺾임점 · 마크 끌기 = 옮김",
|
||||
"「연도 마커」 선 위로 끌어 놓기 = 구역 나눔",
|
||||
"꺾임점 · 마크 끌기 = 옮김 · 마크를 선 밖으로 = 지움(앞 구간과 합침)",
|
||||
"오른쪽 누름 = 꺾임점 · 마크 지움",
|
||||
"Delete = 고른 선 · 마크 지움",
|
||||
"가운데 끌기 = 옮기기",
|
||||
@@ -186,6 +201,7 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
[undoButton, redoButton],
|
||||
[viewButton, "rotate-ccw", "rotate-cw"],
|
||||
[markButton("stations", "측점"), markButton("slopes", "구간 길이 · 기울기"), measureButton],
|
||||
[yearMarkButton],
|
||||
],
|
||||
});
|
||||
const toolbar = tools.root;
|
||||
@@ -340,6 +356,30 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
for (const layer of layers) layer.leave?.();
|
||||
drawTop();
|
||||
});
|
||||
const markDrag = (event: DragEvent): boolean =>
|
||||
!!meta && !!event.dataTransfer?.types.includes(YEAR_MARK_DRAG);
|
||||
canvas.addEventListener("dragover", (event) => {
|
||||
if (!markDrag(event)) return;
|
||||
const [px, py] = at(event);
|
||||
const map = screenMap();
|
||||
if (layers.some((layer) => layer.dragOver?.(px, py, map))) {
|
||||
event.preventDefault();
|
||||
event.dataTransfer!.dropEffect = "copy";
|
||||
}
|
||||
drawTop();
|
||||
});
|
||||
canvas.addEventListener("drop", (event) => {
|
||||
if (!markDrag(event)) return;
|
||||
event.preventDefault();
|
||||
const [px, py] = at(event);
|
||||
const map = screenMap();
|
||||
layers.some((layer) => layer.drop?.(px, py, map));
|
||||
drawTop();
|
||||
});
|
||||
canvas.addEventListener("dragleave", () => {
|
||||
for (const layer of layers) layer.leave?.();
|
||||
drawTop();
|
||||
});
|
||||
canvas.addEventListener("contextmenu", (event) => {
|
||||
event.preventDefault();
|
||||
if (!meta) return;
|
||||
@@ -378,6 +418,7 @@ export function createPlanMap(events: PlanMapEvents): PlanMap {
|
||||
if (tools.view3d !== undefined) viewButton.disabled = !tools.view3d;
|
||||
if (tools.measure !== undefined)
|
||||
measureButton.setAttribute("aria-pressed", String(tools.measure));
|
||||
if (tools.yearMark !== undefined) yearMarkButton.disabled = !tools.yearMark;
|
||||
},
|
||||
redraw: drawTop,
|
||||
redrawBase: draw,
|
||||
|
||||
Reference in New Issue
Block a user