feat(B07): GROUP 묶음 JSON 저장·복원, 줌 로그 제거
- `groupId` 를 도면 JSON 에 실어 [저장] 뒤 다시 연 도면에서도 묶음 유지. 엔티티 13종의 `toJson` 대신 직렬화 한 곳(export/import)에서 붙이고, 복원은 순번이 아니라 id 로 — `compact` 가 null 을 걷어 index 가 어긋남. - `setScreenScale` 의 매 호출 `console.log` 제거 — 줌·팬마다 콘솔을 덮었음. - 검증: `group-id-roundtrip.test.ts` 신규, `npx vitest run` 87건 중 81 passed, 실패 6건은 작업 전과 동일한 기존 결함. `npm run build` 통과. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,7 +69,6 @@ export class ScreenCanvasDrawController implements DrawController {
|
||||
}
|
||||
|
||||
public setScreenScale(newScreenScale: number) {
|
||||
console.log(`set screen scale: ${newScreenScale}`);
|
||||
this.screenScale = newScreenScale;
|
||||
triggerReactUpdate(StateVariable.screenZoom);
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ export interface JsonEntity<TShapeJsonData = ShapeJsonData> {
|
||||
lineWidth: number;
|
||||
lineDash?: number[];
|
||||
layerId: string;
|
||||
/** GROUP 묶음 식별자 — 저장·복원에서 그대로 실어 나른다 */
|
||||
groupId?: string;
|
||||
shapeData: TShapeJsonData | null;
|
||||
children?: JsonEntity<ShapeJsonData>[];
|
||||
}
|
||||
|
||||
+5
-1
@@ -14,7 +14,11 @@ export async function exportEntitiesToJsonFile() {
|
||||
export async function exportEntitiesAndLayersToJsonString() {
|
||||
const entities = getEntities();
|
||||
|
||||
const jsonEntities = entities.map((entity) => entity.toJson());
|
||||
// groupId는 엔티티 13종의 toJson을 다 고치는 대신 여기 한 곳에서 붙인다.
|
||||
const jsonEntities = entities.map(async (entity) => {
|
||||
const json = await entity.toJson();
|
||||
return json && entity.groupId ? { ...json, groupId: entity.groupId } : json;
|
||||
});
|
||||
const jsonDrawingFile: JsonDrawingFileSerialized = {
|
||||
entities: compact(await Promise.all(jsonEntities)), // TODO use a mapLimit to avoid overloading the event loop
|
||||
layers: getLayers(),
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import { Point } from '@flatten-js/core';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { LineEntity } from '../../entities/LineEntity.ts';
|
||||
import { setEntities, setLayers } from '../../state.ts';
|
||||
import { exportEntitiesAndLayersToJsonString } from './export-entities-to-json.ts';
|
||||
import { getEntitiesAndLayersFromJsonString } from './import-entities-from-json.ts';
|
||||
|
||||
describe('groupId 저장·복원', () => {
|
||||
it('GROUP 묶음이 JSON 왕복 뒤에도 한 덩어리로 남는다', async () => {
|
||||
const layer = { id: 'layer-1', isLocked: false, isVisible: true, name: '작업' };
|
||||
const groupId = 'group-1';
|
||||
const first = new LineEntity(layer.id, new Point(0, 0), new Point(1, 0));
|
||||
const second = new LineEntity(layer.id, new Point(1, 0), new Point(1, 1));
|
||||
const loner = new LineEntity(layer.id, new Point(2, 2), new Point(3, 3));
|
||||
first.groupId = groupId;
|
||||
second.groupId = groupId;
|
||||
|
||||
setLayers([layer]);
|
||||
setEntities([first, second, loner]);
|
||||
|
||||
const restored = await getEntitiesAndLayersFromJsonString(
|
||||
await exportEntitiesAndLayersToJsonString()
|
||||
);
|
||||
const byId = new Map(restored.entities.map((entity) => [entity.id, entity]));
|
||||
|
||||
expect(byId.get(first.id)?.groupId).toBe(groupId);
|
||||
expect(byId.get(second.id)?.groupId).toBe(groupId);
|
||||
expect(byId.get(loner.id)?.groupId).toBeUndefined();
|
||||
});
|
||||
});
|
||||
+6
@@ -77,6 +77,12 @@ export async function getEntitiesAndLayersFromJsonObject(
|
||||
);
|
||||
|
||||
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()];
|
||||
|
||||
Reference in New Issue
Block a user