Add rel to Layer structure

This commit is contained in:
Igor Zinken
2026-03-20 19:00:34 +01:00
parent 5fd0502f08
commit ca0eaa83e8
3 changed files with 58 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2020-2025 - https://www.igorski.nl
* Igor Zinken 2020-2026 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -24,6 +24,11 @@ import type { Point } from "zcanvas";
import type { BlendModes } from "./blend-modes";
import type { LayerTypes } from "./layer-types";
export type LayerRel = {
type: "none" | "group" | "tile";
id?: string;
};
export type Layer = {
id: string;
name: string;
@@ -41,6 +46,7 @@ export type Layer = {
transform: Transform;
filters: Filters;
text: Text;
rel: LayerRel;
};
export type Transform = {

View File

@@ -1,7 +1,7 @@
/**
* The MIT License (MIT)
*
* Igor Zinken 2020-2025 - https://www.igorski.nl
* Igor Zinken 2020-2026 - https://www.igorski.nl
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
@@ -22,7 +22,7 @@
*/
import type { Rectangle } from "zcanvas";
import { LayerTypes, DEFAULT_LAYER_NAME, DEFAULT_TEXT_LAYER_NAME } from "@/definitions/layer-types";
import type { Layer } from "@/definitions/document";
import type { Layer, LayerRel } from "@/definitions/document";
import { imageToBase64, base64toCanvas } from "@/utils/canvas-util";
import TransformFactory, { type TransformProps } from "@/factories/transform-factory";
import FiltersFactory from "@/factories/filters-factory";
@@ -32,10 +32,11 @@ import type { TextProps } from "@/factories/text-factory";
let UID_COUNTER = 0;
export type LayerProps = Partial<Omit<Layer, "transform" | "filters" | "text">> & {
export type LayerProps = Partial<Omit<Layer, "transform" | "filters" | "text" | "rel">> & {
transform?: TransformProps;
filters?: FiltersProps;
text?: TextProps;
rel?: Partial<LayerRel>;
};
const LayerFactory = {
@@ -46,7 +47,7 @@ const LayerFactory = {
name = DEFAULT_LAYER_NAME,
type = LayerTypes.LAYER_GRAPHIC, transparent = true, source = null, mask = null,
left = 0, top = 0, maskX = 0, maskY = 0, width = 1, height = 1, visible = true,
transform = {}, filters = {}, text = {}
transform = {}, filters = {}, text = {}, rel = {},
}: LayerProps = {}): Layer {
return {
id: `layer_${( ++UID_COUNTER )}`,
@@ -65,6 +66,10 @@ const LayerFactory = {
text: TextFactory.create( text ),
transform: TransformFactory.create( transform ),
filters: FiltersFactory.create( filters ),
rel: {
type: "none",
...rel,
},
}
},
@@ -89,6 +94,10 @@ const LayerFactory = {
f: TransformFactory.serialize( layer.transform ),
fl: FiltersFactory.serialize( layer.filters ),
v: layer.visible,
r: {
t: layer.rel.type,
i: layer.rel.id,
},
};
},
@@ -116,6 +125,10 @@ const LayerFactory = {
text,
transform: TransformFactory.deserialize( layer.f ),
filters: FiltersFactory.deserialize( layer.fl ),
rel: layer.r ? {
type: layer.r.t,
id: layer.r.i,
} : {}
});
}
};

View File

@@ -45,6 +45,9 @@ describe( "Layer factory", () => {
text: mockText,
transform: mockTransform,
filters: mockFilters,
rel: {
type: "none",
},
});
});
@@ -73,7 +76,11 @@ describe( "Layer factory", () => {
visible: false,
text: { value: "Lorem ipsum" },
transform: { rotation: 270 },
filters: { contrast: .7 }
filters: { contrast: .7 },
rel: {
type: "group",
id: "Foo",
},
});
expect( layer ).toEqual({
id: expect.any( String ),
@@ -92,7 +99,11 @@ describe( "Layer factory", () => {
text: { value: "Lorem ipsum" },
transform: { rotation: 270 },
filters: { contrast: .7 },
})
rel: {
type: "group",
id: "Foo",
},
});
});
describe( "and providing a name to the Layer", () => {
@@ -131,7 +142,11 @@ describe( "Layer factory", () => {
visible: false,
text: { value: "Lorem ipsum" },
transform: { rotation: 270 },
filters: { contrast: .7 }
filters: { contrast: .7 },
rel: {
type: "tile",
id: "1",
},
});
const serializeTextSpy = vi.spyOn( TextFactory, "serialize" ).mockImplementation( args => args );
const deserializeTextSpy = vi.spyOn( TextFactory, "deserialize" ).mockImplementation( args => args );
@@ -160,6 +175,11 @@ describe( "Layer factory", () => {
expect( deserializeTransformSpy ).toHaveBeenCalledWith( layer.transform );
expect( deserializeFiltersSpy ).toHaveBeenCalledWith( layer.filters );
expect( deserialized.rel ).toEqual({
type: "tile",
id: "1",
});
// note id's are unique per created session instance and therefor will differ
expect({
...deserialized,
@@ -169,6 +189,17 @@ describe( "Layer factory", () => {
id: expect.any( String ),
});
});
it( "should deserialize with a default rel structure for legacy serialized layers", async () => {
const serialized = LayerFactory.serialize( LayerFactory.create());
delete serialized.r;
const deserialized = await LayerFactory.deserialize( serialized );
expect( deserialized.rel ).toEqual({
type: "none",
});
});
});
it( "should be able to return a rectangle for a Layer", () => {