Для кого: авторы shapes и библиотек Stencil (внутри engine или во внешнем модуле).
Что получите: два способа создания библиотеки — классы и JSON — с end-to-end примерами.
Предварительные знания: Архитектура движка, typeName и сериализация cell-классов.
Библиотеки можно создавать двумя способами:
StencilLibItem) — быстро, на базе CustomCell и существующих прототиповlibs/yourlib/
shapes/
MyShape.ts
index.ts
YourLib.ts
Каждый класс фигуры объявляет static readonly typeName. Подробно: typeName и сериализация cell-классов.
import { CellParametric } from "@engine/entities/cell/CellParametric"
import { CellOptions } from "@etypes/Cell"
export class MyShape extends CellParametric {
static readonly typeName: string = "MyShape"
constructor(options?: CellOptions) {
super({ name: "Мой элемент", ...options })
}
}
import { Library } from "@engine/services/Stencil/libs/Library"
import * as Shapes from "./shapes"
export const yourlib = new Library("Имя вашей библиотеки", Object.values(Shapes))
Внутри engine — экспорт из libs/index.ts; библиотека попадает в registerStandardLibs().
Во внешнем модуле:
engine.services.Stencil?.register(yourlib)
engine.services.Stencil?.loadLibs()
При Library.register(eulerGraph) каждый shape регистрируется в elementsLib через registerElement.
Смотрите src/engine/services/Stencil/libs/electric/:
ElectricElement — база для электрических элементовBattery.ts — parametric _drawRules, typeName: "Battery"ElectricWire.ts — extends SegmentElectricLib.ts — new Library(..., Object.values(Shapes))Для CellParametric:
export class GaugeShape extends CellParametric {
static readonly typeName: string = "GaugeShape"
_drawRules = {
rect: () => ({
name: "rect",
args: [0, 0, this.width, this.height],
}),
}
getParamData() {
return [
{ name: "radius", label: "Радиус", type: "number", value: 10 },
]
}
onParamChange(paramName: string, value: number) {
if (paramName === "radius") {
this.recalcDrawPaths()
}
}
}
Изменения param для undo — через engine.services.Editor?.changeCustomParam(param, value), где param — объект ParamData из cell.paramData.
src/engine/services/Stencil/libsJSON/yourlib.ts:
import { StencilLib } from "@etypes/StencilItem"
export const yourlib: StencilLib = {
name: "Имя вашей библиотеки",
items: [],
}
type StencilLibItem = {
options: CellOptions | LinkOptions
name: string
customParams?: CustomParams
cellPrototype?: string // typeName базового класса, напр. "CustomCell"
}
Эталон: src/engine/services/Stencil/libsJSON/fastening/bolt.ts
export const bolt: StencilLibItem = {
name: "Болт ГОСТ 7798-70",
options: {
name: "Болт",
width: 100,
height: 100,
},
cellPrototype: "CustomCell",
customParams: {
param: { viewName: "top", diameter: 20 },
paramData: [
{ type: "select", name: "viewName", label: "Вид", items: [...], value: "top" },
],
},
}
Регистрация cell-классов не нужна для JSON-items — используются уже зарегистрированные прототипы (CustomCell, Cell, …).
Library |
JsonLibrary |
|
|---|---|---|
| Элементы | Классы (constructors) | StencilLibItem[] |
| registerElement | Да, для каждого shape | Нет |
| Пример | electricLib |
fastening через JsonLibrary |
registerStandardLibs() регистрирует оба типа из libs/ и libsJSON/.
typeNameclassNameLibrary.register + loadLibs вызваны при стартеnew Shape() → toJSON() → fromJSON() → те же поляcellPrototype указывают на зарегистрированный typeNametypeName — assertCellTypeName при регистрацииloadLibs без register — пустая панель StencilcellPrototype: "MyShape" для несуществующего typeName — элемент не создаётся