109 lines
3.5 KiB
JavaScript
Executable File
109 lines
3.5 KiB
JavaScript
Executable File
import { CanvasSmbl } from '../infrastructure/canvas-smbl.js';
|
|
import { PathSmbl } from '../shapes/path-smbl.js';
|
|
import { ShapeSmbl } from '../shapes/shape-smbl.js';
|
|
import { canvasClear } from './canvas-clear.js';
|
|
|
|
const v = '1.1';
|
|
|
|
/** @param {Element} canvas */
|
|
export const serialize = (canvas) => serializeShapes(/** @type {Array<ShapeElement & PathElement>} */([...canvas.children]));
|
|
|
|
/** @param {Array<ShapeElement & PathElement>} shapes */
|
|
export function serializeShapes(shapes) {
|
|
/** @type {DiagramSerialized} */
|
|
const diagramSerialized = { v, s: [] };
|
|
for (const shape of shapes) {
|
|
if (shape[ShapeSmbl]) {
|
|
// shape
|
|
diagramSerialized.s.push(shape[ShapeSmbl].data);
|
|
} else {
|
|
// path
|
|
|
|
/** @param {PathEnd} pathEnd */
|
|
function pathSerialize(pathEnd) {
|
|
const shapeIndex = shapes.indexOf(pathEnd.shape?.shapeEl);
|
|
return (shapeIndex !== -1)
|
|
? { s: shapeIndex, k: pathEnd.shape.connectorKey }
|
|
: { p: pathEnd.data };
|
|
}
|
|
|
|
const pathData = shape[PathSmbl].data;
|
|
const pathJson = { type: 0, s: pathSerialize(pathData.s), e: pathSerialize(pathData.e) };
|
|
if (pathData.styles) { pathJson.c = pathData.styles; }
|
|
|
|
diagramSerialized.s.push(pathJson);
|
|
}
|
|
}
|
|
|
|
return diagramSerialized;
|
|
}
|
|
|
|
/**
|
|
* @param {CanvasElement} canvas
|
|
* @param {DiagramSerialized} data
|
|
* @param {Boolean=} dontClear
|
|
*/
|
|
export function deserialize(canvas, data, dontClear) {
|
|
if (data.v !== v) { alert('Wrong format'); return null; }
|
|
if (!dontClear) { canvasClear(canvas); }
|
|
|
|
/** @type {Map<ShapeData, ShapeElement>} */
|
|
const shapeDataToElem = new Map();
|
|
|
|
/** @param {ShapeData} shapeData */
|
|
function shapeEnsure(shapeData) {
|
|
let shapeEl = shapeDataToElem.get(shapeData);
|
|
if (!shapeEl) {
|
|
shapeEl = canvas[CanvasSmbl].shapeMap[shapeData.type].create(shapeData);
|
|
canvas.append(shapeEl);
|
|
shapeDataToElem.set(shapeData, shapeEl);
|
|
}
|
|
return shapeEl;
|
|
}
|
|
|
|
/** @param {number?} index */
|
|
const shapeByIndex = index => shapeEnsure(/** @type {ShapeData} */(data.s[index]));
|
|
|
|
/** @type {PathElement[]} */
|
|
const paths = [];
|
|
for (const shape of data.s) {
|
|
switch (shape.type) {
|
|
// path
|
|
case 0: {
|
|
/** @param {PathEndSerialized} pathEnd */
|
|
const pathDeserialize = pathEnd => pathEnd.p
|
|
? { data: pathEnd.p }
|
|
: { shape: { shapeEl: shapeByIndex(pathEnd.s), connectorKey: pathEnd.k } };
|
|
|
|
const path = canvas[CanvasSmbl].shapeMap[0].create({
|
|
styles: /** @type {PathSerialized} */(shape).c,
|
|
s: pathDeserialize(/** @type {PathSerialized} */(shape).s),
|
|
e: pathDeserialize(/** @type {PathSerialized} */(shape).e)
|
|
});
|
|
paths.push(path);
|
|
canvas.append(path);
|
|
break;
|
|
}
|
|
default: shapeEnsure(/** @type {ShapeData} */(shape)); break;
|
|
}
|
|
}
|
|
|
|
return [...shapeDataToElem.values(), ...paths];
|
|
}
|
|
|
|
/** @typedef {{v:string, s: Array<ShapeData | PathSerialized>}} DiagramSerialized */
|
|
|
|
/** @typedef { import("../shapes/shape-smbl").ShapeElement } ShapeElement */
|
|
/** @typedef { import('../shapes/shape-evt-proc').ShapeData } ShapeData */
|
|
|
|
/** @typedef { import("../shapes/path-smbl").PathElement } PathElement */
|
|
/** @typedef { import('../shapes/path').PathEndData } PathEndData */
|
|
/** @typedef { import('../shapes/path').PathEnd } PathEnd */
|
|
/** @typedef { import('../shapes/path').PathData } PathData */
|
|
|
|
/** @typedef { {s?:number, k?:string, p?:PathEndData} } PathEndSerialized */
|
|
/** @typedef { {type:number, c?:string, s:PathEndSerialized, e:PathEndSerialized} } PathSerialized */
|
|
|
|
/** @typedef { import('../shapes/shape-evt-proc').CanvasData } CanvasData */
|
|
/** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */
|