fix(M02): 구조물 도면 미리보기 특성·도면층 숨김 · CAD 빈 도면 불러오기 오류 고침
- 구조물 도면 미리보기(도면 정보 카드)에서 CAD 특성·도면층 패널(.cad-inspector)도 같이 숨김 - B07 CAD `layers` 칸이 없는 도면(빈 구조물 도면 · 「새 도면」 빈 도면 공통)을 열면 "Cannot read properties of undefined (reading 'length')" 로 죽던 것을 고침 (`layers` 없으면 새 도면층 하나로 채움) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7JS47SacjPxZ718QsZKyr
This commit is contained in:
+84
-84
@@ -1,22 +1,22 @@
|
||||
import { compact } from 'es-toolkit';
|
||||
import { ArcEntity, type ArcJsonData } from '../../entities/ArcEntity';
|
||||
import { CircleEntity, type CircleJsonData } from '../../entities/CircleEntity';
|
||||
import { type Entity, EntityName, type JsonEntity } from '../../entities/Entity';
|
||||
import { HatchEntity, type HatchJsonData } from '../../entities/HatchEntity';
|
||||
import { ImageEntity, type ImageJsonData } from '../../entities/ImageEntity.ts';
|
||||
import { LineEntity, type LineJsonData } from '../../entities/LineEntity';
|
||||
import { MeasurementEntity, type MeasurementJsonData } from '../../entities/MeasurementEntity.ts';
|
||||
import { PointEntity, type PointJsonData } from '../../entities/PointEntity';
|
||||
import { PolyLineEntity, type PolyLineJsonData } from '../../entities/PolyLineEntity.ts';
|
||||
import { RectangleEntity, type RectangleJsonData } from '../../entities/RectangleEntity';
|
||||
import { TableEntity, type TableJsonData } from '../../entities/TableEntity.ts';
|
||||
import { TextEntity, type TextJsonData } from '../../entities/TextEntity.ts';
|
||||
import { setActiveLayerId, setEntities, setLayers } from '../../state';
|
||||
import { getNewLayer } from '../get-new-layer.ts';
|
||||
import { compact } from "es-toolkit";
|
||||
import { ArcEntity, type ArcJsonData } from "../../entities/ArcEntity";
|
||||
import { CircleEntity, type CircleJsonData } from "../../entities/CircleEntity";
|
||||
import { type Entity, EntityName, type JsonEntity } from "../../entities/Entity";
|
||||
import { HatchEntity, type HatchJsonData } from "../../entities/HatchEntity";
|
||||
import { ImageEntity, type ImageJsonData } from "../../entities/ImageEntity.ts";
|
||||
import { LineEntity, type LineJsonData } from "../../entities/LineEntity";
|
||||
import { MeasurementEntity, type MeasurementJsonData } from "../../entities/MeasurementEntity.ts";
|
||||
import { PointEntity, type PointJsonData } from "../../entities/PointEntity";
|
||||
import { PolyLineEntity, type PolyLineJsonData } from "../../entities/PolyLineEntity.ts";
|
||||
import { RectangleEntity, type RectangleJsonData } from "../../entities/RectangleEntity";
|
||||
import { TableEntity, type TableJsonData } from "../../entities/TableEntity.ts";
|
||||
import { TextEntity, type TextJsonData } from "../../entities/TextEntity.ts";
|
||||
import { setActiveLayerId, setEntities, setLayers } from "../../state";
|
||||
import { getNewLayer } from "../get-new-layer.ts";
|
||||
import type {
|
||||
JsonDrawingFileDeserialized,
|
||||
JsonDrawingFileSerialized,
|
||||
} from './export-entities-to-json';
|
||||
JsonDrawingFileDeserialized,
|
||||
JsonDrawingFileSerialized,
|
||||
} from "./export-entities-to-json";
|
||||
|
||||
/**
|
||||
* Open a file selection dialog to select *.json files
|
||||
@@ -25,83 +25,83 @@ import type {
|
||||
* Set the entities in the state
|
||||
*/
|
||||
export function importEntitiesFromJsonFile(file: File | null | undefined) {
|
||||
return new Promise<void>((resolve) => {
|
||||
if (!file) return;
|
||||
return new Promise<void>((resolve) => {
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', async () => {
|
||||
const json = reader.result as string;
|
||||
const file = await getEntitiesAndLayersFromJsonString(json);
|
||||
setEntities(file.entities);
|
||||
setLayers(file.layers);
|
||||
setActiveLayerId(file.layers[0].id);
|
||||
resolve();
|
||||
});
|
||||
reader.readAsText(file, 'utf-8');
|
||||
});
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", async () => {
|
||||
const json = reader.result as string;
|
||||
const file = await getEntitiesAndLayersFromJsonString(json);
|
||||
setEntities(file.entities);
|
||||
setLayers(file.layers);
|
||||
setActiveLayerId(file.layers[0].id);
|
||||
resolve();
|
||||
});
|
||||
reader.readAsText(file, "utf-8");
|
||||
});
|
||||
}
|
||||
|
||||
export async function getEntitiesAndLayersFromJsonObject(
|
||||
data: JsonDrawingFileSerialized
|
||||
data: JsonDrawingFileSerialized,
|
||||
): Promise<JsonDrawingFileDeserialized> {
|
||||
const entityPromises: Promise<Entity | null>[] = compact(
|
||||
data.entities.map((entity) => {
|
||||
switch (entity.type) {
|
||||
case EntityName.Arc:
|
||||
return ArcEntity.fromJson(entity as JsonEntity<ArcJsonData>);
|
||||
case EntityName.Circle:
|
||||
return CircleEntity.fromJson(entity as JsonEntity<CircleJsonData>);
|
||||
case EntityName.Line:
|
||||
return LineEntity.fromJson(entity as JsonEntity<LineJsonData>);
|
||||
case EntityName.Point:
|
||||
return PointEntity.fromJson(entity as JsonEntity<PointJsonData>);
|
||||
case EntityName.Rectangle:
|
||||
return RectangleEntity.fromJson(entity as JsonEntity<RectangleJsonData>);
|
||||
case EntityName.Text:
|
||||
return TextEntity.fromJson(entity as JsonEntity<TextJsonData>);
|
||||
case EntityName.Measurement:
|
||||
return MeasurementEntity.fromJson(entity as JsonEntity<MeasurementJsonData>);
|
||||
case EntityName.Image:
|
||||
return ImageEntity.fromJson(entity as JsonEntity<ImageJsonData>);
|
||||
case EntityName.PolyLine:
|
||||
return PolyLineEntity.fromJson(entity as JsonEntity<PolyLineJsonData>);
|
||||
case EntityName.Hatch:
|
||||
return HatchEntity.fromJson(entity as JsonEntity<HatchJsonData>);
|
||||
case EntityName.Table:
|
||||
return TableEntity.fromJson(entity as JsonEntity<TableJsonData>);
|
||||
const entityPromises: Promise<Entity | null>[] = compact(
|
||||
data.entities.map((entity) => {
|
||||
switch (entity.type) {
|
||||
case EntityName.Arc:
|
||||
return ArcEntity.fromJson(entity as JsonEntity<ArcJsonData>);
|
||||
case EntityName.Circle:
|
||||
return CircleEntity.fromJson(entity as JsonEntity<CircleJsonData>);
|
||||
case EntityName.Line:
|
||||
return LineEntity.fromJson(entity as JsonEntity<LineJsonData>);
|
||||
case EntityName.Point:
|
||||
return PointEntity.fromJson(entity as JsonEntity<PointJsonData>);
|
||||
case EntityName.Rectangle:
|
||||
return RectangleEntity.fromJson(entity as JsonEntity<RectangleJsonData>);
|
||||
case EntityName.Text:
|
||||
return TextEntity.fromJson(entity as JsonEntity<TextJsonData>);
|
||||
case EntityName.Measurement:
|
||||
return MeasurementEntity.fromJson(entity as JsonEntity<MeasurementJsonData>);
|
||||
case EntityName.Image:
|
||||
return ImageEntity.fromJson(entity as JsonEntity<ImageJsonData>);
|
||||
case EntityName.PolyLine:
|
||||
return PolyLineEntity.fromJson(entity as JsonEntity<PolyLineJsonData>);
|
||||
case EntityName.Hatch:
|
||||
return HatchEntity.fromJson(entity as JsonEntity<HatchJsonData>);
|
||||
case EntityName.Table:
|
||||
return TableEntity.fromJson(entity as JsonEntity<TableJsonData>);
|
||||
|
||||
default:
|
||||
throw new Error(`Invalid entity type: ${entity.type}`);
|
||||
}
|
||||
})
|
||||
);
|
||||
default:
|
||||
throw new Error(`Invalid entity type: ${entity.type}`);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
const entities = compact(await Promise.all(entityPromises));
|
||||
// 순번이 아니라 id로 되돌린다 — compact가 null을 걷어 index가 어긋날 수 있다.
|
||||
const groupIdById = new Map(data.entities.map((entity) => [entity.id, entity.groupId]));
|
||||
for (const entity of entities) {
|
||||
const groupId = groupIdById.get(entity.id);
|
||||
if (groupId) entity.groupId = groupId;
|
||||
}
|
||||
let layers = data.layers;
|
||||
if (data.layers.length === 0) {
|
||||
layers = [getNewLayer()];
|
||||
}
|
||||
return {
|
||||
entities,
|
||||
layers,
|
||||
};
|
||||
const entities = compact(await Promise.all(entityPromises));
|
||||
// 순번이 아니라 id로 되돌린다 — compact가 null을 걷어 index가 어긋날 수 있다.
|
||||
const groupIdById = new Map(data.entities.map((entity) => [entity.id, entity.groupId]));
|
||||
for (const entity of entities) {
|
||||
const groupId = groupIdById.get(entity.id);
|
||||
if (groupId) entity.groupId = groupId;
|
||||
}
|
||||
let layers = data.layers;
|
||||
if (!layers || layers.length === 0) {
|
||||
layers = [getNewLayer()];
|
||||
}
|
||||
return {
|
||||
entities,
|
||||
layers,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getEntitiesAndLayersFromJsonString(
|
||||
json: string
|
||||
json: string,
|
||||
): Promise<JsonDrawingFileDeserialized> {
|
||||
const data = JSON.parse(json) as JsonDrawingFileSerialized;
|
||||
const data = JSON.parse(json) as JsonDrawingFileSerialized;
|
||||
|
||||
if (!data.entities) {
|
||||
throw new Error('Invalid JSON file');
|
||||
}
|
||||
if (!data.entities) {
|
||||
throw new Error("Invalid JSON file");
|
||||
}
|
||||
|
||||
// TODO use map limit to avoid overloading the event loop
|
||||
return await getEntitiesAndLayersFromJsonObject(data);
|
||||
// TODO use map limit to avoid overloading the event loop
|
||||
return await getEntitiesAndLayersFromJsonObject(data);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,8 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane
|
||||
if (!inner?.head || inner.getElementById("m02-struct-hide")) return;
|
||||
const style = inner.createElement("style");
|
||||
style.id = "m02-struct-hide";
|
||||
style.textContent = ".cad-titlebar, .cad-ribbon { display: none !important; }";
|
||||
style.textContent =
|
||||
".cad-titlebar, .cad-ribbon, .cad-inspector { display: none !important; }";
|
||||
inner.head.append(style);
|
||||
};
|
||||
frame.addEventListener("load", apply);
|
||||
|
||||
Reference in New Issue
Block a user