处理图形Assets加载结构

添加风机图形和绘制
初步添加动画功能(不稳定,可能会有不兼容的修改)
This commit is contained in:
walker 2023-05-08 18:19:04 +08:00
parent fbc3a70cda
commit f649cb4a3d
22 changed files with 1404 additions and 1106 deletions

View File

@ -5,6 +5,7 @@ package graphicData;
message RtssGraphicStorage {
Canvas canvas = 1;
repeated Link links = 2;
repeated IscsFan iscsFans = 3;
}
message Canvas {
@ -61,3 +62,8 @@ message Link {
string lineColor = 6; // 线
repeated Point points = 7; //
}
message IscsFan {
CommonInfo common = 1;
string code = 2;
}

View File

@ -0,0 +1,87 @@
import * as pb_1 from 'google-protobuf';
import {
ChildTransform,
GraphicData,
GraphicTransform,
IChildTransform,
IGraphicTransform,
} from 'src/jlgraphic';
import { toStorageTransform } from '..';
import { graphicData } from '../protos/draw_data_storage';
export interface ICommonInfo {
id: string;
graphicType: string;
transform: IGraphicTransform;
childTransforms: IChildTransform[];
}
export interface IProtoGraphicData extends pb_1.Message {
common: ICommonInfo;
code: string;
}
export abstract class BaseGraphicData implements GraphicData {
_data: IProtoGraphicData;
constructor(data: IProtoGraphicData) {
this._data = data;
}
getData<D extends IProtoGraphicData>(): D {
return this._data as D;
}
get id(): string {
return this._data.common.id;
}
set id(v: string) {
this._data.common.id = v;
}
get graphicType(): string {
return this._data.common.graphicType;
}
set graphicType(v: string) {
this._data.common.graphicType = v;
}
get transform(): GraphicTransform {
return GraphicTransform.from(this._data.common.transform);
}
set transform(v: GraphicTransform) {
this._data.common.transform = toStorageTransform(v);
}
get childTransforms(): ChildTransform[] | undefined {
const cts: ChildTransform[] = [];
if (this._data.common.childTransforms) {
this._data.common.childTransforms.forEach((ct) => {
cts.push(ChildTransform.from(ct));
});
}
return cts;
}
set childTransforms(v: ChildTransform[] | undefined) {
if (v) {
const cts: graphicData.ChildTransform[] = [];
v.forEach((ct) =>
cts.push(
new graphicData.ChildTransform({
...ct,
transform: toStorageTransform(ct.transform),
})
)
);
this._data.common.childTransforms = cts;
} else {
this._data.common.childTransforms = [];
}
}
clone(): GraphicData {
throw new Error('Method not implemented.');
}
copyFrom(gd: BaseGraphicData): void {
pb_1.Message.copyInto(gd._data, this._data);
}
eq(other: BaseGraphicData): boolean {
return pb_1.Message.equals(this._data, other._data);
}
}

View File

@ -0,0 +1,38 @@
import * as pb_1 from 'google-protobuf';
import { IIscsFanData } from 'src/graphics/iscs-fan/IscsFan';
import { graphicData } from '../protos/draw_data_storage';
import { BaseGraphicData } from './BaseGraphicData';
export class IscsFanData extends BaseGraphicData implements IIscsFanData {
constructor(data?: graphicData.IscsFan) {
let fan;
if (data) {
fan = data;
} else {
fan = new graphicData.IscsFan({
common: new graphicData.CommonInfo(),
});
}
super(fan);
}
public get data(): graphicData.IscsFan {
return this.getData<graphicData.IscsFan>();
}
get code(): string {
return this.data.code;
}
set code(v: string) {
this.data.code = v;
}
clone(): IscsFanData {
return new IscsFanData(this.data.cloneMessage());
}
copyFrom(data: IscsFanData): void {
pb_1.Message.copyInto(data.data, this.data);
}
eq(other: IscsFanData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
}

View File

@ -1,21 +1,26 @@
import * as pb_1 from 'google-protobuf';
import { IPointData } from 'pixi.js';
import { ILinkData } from 'src/graphics/link/Link';
import { ChildTransform, GraphicTransform } from 'src/jlgraphic';
import { toStorageTransform } from '..';
import { graphicData } from '../protos/draw_data_storage';
import { BaseGraphicData } from './BaseGraphicData';
export class LinkData implements ILinkData {
data: graphicData.Link;
export class LinkData extends BaseGraphicData implements ILinkData {
constructor(data?: graphicData.Link) {
if (data) {
this.data = data;
} else {
this.data = new graphicData.Link({
let link;
if (!data) {
link = new graphicData.Link({
common: new graphicData.CommonInfo(),
});
} else {
link = data;
}
super(link);
}
public get data(): graphicData.Link {
return this.getData<graphicData.Link>();
}
get code(): string {
return this.data.code;
}
@ -63,47 +68,4 @@ export class LinkData implements ILinkData {
eq(other: LinkData): boolean {
return pb_1.Message.equals(this.data, other.data);
}
get id(): string {
return this.data.common.id;
}
set id(v: string) {
this.data.common.id = v;
}
get graphicType(): string {
return this.data.common.graphicType;
}
set graphicType(v: string) {
this.data.common.graphicType = v;
}
get transform(): GraphicTransform {
return GraphicTransform.from(this.data.common.transform);
}
set transform(v: GraphicTransform) {
this.data.common.transform = toStorageTransform(v);
}
get childTransforms(): ChildTransform[] | undefined {
const cts: ChildTransform[] = [];
if (this.data.common.childTransforms) {
this.data.common.childTransforms.forEach((ct) => {
cts.push(ChildTransform.from(ct));
});
}
return cts;
}
set childTransforms(v: ChildTransform[] | undefined) {
if (v) {
const cts: graphicData.ChildTransform[] = [];
v.forEach((ct) =>
cts.push(
new graphicData.ChildTransform({
...ct,
transform: toStorageTransform(ct.transform),
})
)
);
this.data.common.childTransforms = cts;
} else {
this.data.common.childTransforms = [];
}
}
}

View File

@ -12,6 +12,9 @@ import {
} from 'src/jlgraphic';
import { LinkData } from './graphics/LinkInteraction';
import { graphicData } from './protos/draw_data_storage';
import { IscsFanDraw } from 'src/graphics/iscs-fan/IscsFanDrawAssistant';
import { IscsFanData } from './graphics/IscsFanInteraction';
import { IscsFan } from 'src/graphics/iscs-fan/IscsFan';
export function fromStoragePoint(p: graphicData.Point): Point {
return new Point(p.x, p.y);
@ -46,13 +49,15 @@ export function toStorageTransform(
export function initDrawApp(app: JlDrawApp) {
app.setOptions({
drawAssistants: [
new LinkDraw(app, {
newData: () => {
return new LinkData();
},
new LinkDraw(app, () => {
return new LinkData();
}),
new IscsFanDraw(app, () => {
return new IscsFanData();
}),
],
});
app.addKeyboardListener(
new KeyListener({
value: 'KeyL',
@ -61,6 +66,25 @@ export function initDrawApp(app: JlDrawApp) {
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyF',
onPress: () => {
app.interactionPlugin(IscsFan.Type).resume();
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyR',
onPress: () => {
app.queryStore.queryByType<IscsFan>(IscsFan.Type).forEach((fan) => {
fan._run = !fan._run;
fan.repaint();
});
},
})
);
app.addKeyboardListener(
new KeyListener({
value: 'KeyS',
@ -86,6 +110,9 @@ export function saveDrawDatas(app: JlDrawApp) {
if (Link.Type === g.type) {
const linkData = (g as Link).saveData();
storage.links.push((linkData as LinkData).data);
} else if (IscsFan.Type === g.type) {
const IscsFanData = (g as IscsFan).saveData();
storage.iscsFans.push((IscsFanData as IscsFanData).data);
}
});
const base64 = fromUint8Array(storage.serialize());
@ -96,6 +123,7 @@ export function saveDrawDatas(app: JlDrawApp) {
export function loadDrawDatas(app: GraphicApp) {
// localStorage.removeItem(StorageKey);
const base64 = localStorage.getItem(StorageKey);
// console.log('加载数据', base64);
if (base64) {
const storage = graphicData.RtssGraphicStorage.deserialize(
toUint8Array(base64)
@ -106,6 +134,9 @@ export function loadDrawDatas(app: GraphicApp) {
storage.links.forEach((link) => {
datas.push(new LinkData(link));
});
storage.iscsFans.forEach((fan) => {
datas.push(new IscsFanData(fan));
});
app.loadGraphic(datas);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
import {
GraphicAnimation,
GraphicData,
JlGraphic,
JlGraphicTemplate,
} from 'src/jlgraphic';
import fanBorder from './assets/fan-border.png';
import fanBlue from './assets/fan-blue.png';
import fanGray from './assets/fan-gray.png';
import fanGreen from './assets/fan-green.png';
import fanRed from './assets/fan-red.png';
import fanYellow from './assets/fan-yellow.png';
import { Assets, Sprite, Texture } from 'pixi.js';
interface FanTextures {
border: Texture;
blue: Texture;
gray: Texture;
green: Texture;
red: Texture;
yellow: Texture;
}
export interface IIscsFanData extends GraphicData {
get code(): string;
set code(v: string);
}
export class IscsFan extends JlGraphic {
static Type = 'IscsFan';
_border: Sprite;
_fan: Sprite;
fanTextures: FanTextures;
_run = false;
constructor(fanTextures: FanTextures) {
super(IscsFan.Type);
this.fanTextures = fanTextures;
this._border = new Sprite();
this._border.texture = this.fanTextures.border;
this._border.anchor.set(0.5);
this._fan = new Sprite();
this._fan.texture = this.fanTextures.gray;
this._fan.anchor.set(0.5);
this.addChild(this._border);
this.addChild(this._fan);
}
doRepaint(): void {
if (this._run) {
this._fan.texture = this.fanTextures.green;
// 动画
this.addAnimation(
GraphicAnimation.init({
name: 'fan_run',
run: (dt: number) => {
this._fan.angle = (this._fan.angle + dt * 3) % 360;
},
}).resume()
);
} else {
this.removeAnimation('fan_run');
this._fan.rotation = 0;
this._fan.texture = this.fanTextures.gray;
}
}
}
export class IscsFanTemplate extends JlGraphicTemplate<IscsFan> {
fanTextures?: FanTextures;
constructor() {
super(IscsFan.Type);
}
new(): IscsFan {
if (this.fanTextures) {
return new IscsFan(this.fanTextures);
}
throw new Error('资源未加载/加载失败');
}
async loadAssets(): Promise<FanTextures> {
Assets.addBundle('iscsFan', {
border: fanBorder,
blue: fanBlue,
gray: fanGray,
green: fanGreen,
red: fanRed,
yellow: fanYellow,
});
this.fanTextures = await Assets.loadBundle('iscsFan');
return this.fanTextures as FanTextures;
}
}

View File

@ -0,0 +1,55 @@
import { FederatedMouseEvent, Point } from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicTransform,
JlDrawApp,
} from 'src/jlgraphic';
import { IIscsFanData, IscsFan, IscsFanTemplate } from './IscsFan';
export class IscsFanDraw extends GraphicDrawAssistant<
IscsFanTemplate,
IIscsFanData
> {
_iscsFan: IscsFan | null = null;
constructor(app: JlDrawApp, createData: () => IIscsFanData) {
const template = new IscsFanTemplate();
super(app, template, createData, IscsFan.Type, '');
}
bind(): void {
super.bind();
if (!this._iscsFan) {
this._iscsFan = this.graphicTemplate.new();
this.container.addChild(this._iscsFan);
}
}
public get iscsFan(): IscsFan {
if (!this._iscsFan) {
throw new Error('风机绘制逻辑异常');
}
return this._iscsFan;
}
redraw(cp: Point): void {
this.iscsFan.position.copyFrom(cp);
}
onLeftUp(e: FederatedMouseEvent): void {
this.iscsFan.position.copyFrom(this.toCanvasCoordinates(e.global));
this.createAndStore(false);
}
onRightUp(): void {
this.finish();
}
prepareData(data: IIscsFanData): boolean {
// 变换设置必须新建变换赋值,不能直接修改变换数据
const transfrom = GraphicTransform.default();
transfrom.position = this.iscsFan.position.clone();
data.transform = transfrom;
return true;
}
onEsc(): void {
this.finish();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -34,8 +34,7 @@ export interface ILinkDrawOptions {
newData: () => ILinkData;
}
export class LinkDraw extends GraphicDrawAssistant<LinkTemplate> {
_options: ILinkDrawOptions;
export class LinkDraw extends GraphicDrawAssistant<LinkTemplate, ILinkData> {
points: Point[] = [];
graphic: Graphics = new Graphics();
@ -60,18 +59,14 @@ export class LinkDraw extends GraphicDrawAssistant<LinkTemplate> {
},
});
constructor(app: JlDrawApp, options: ILinkDrawOptions) {
super(app, new LinkTemplate(), Link.Type, '轨道Link');
constructor(app: JlDrawApp, createData: () => ILinkData) {
super(app, new LinkTemplate(), createData, Link.Type, '轨道Link');
this.container.addChild(this.graphic);
this._options = options;
this.graphicTemplate.curve = true;
new LinkPointsEditPlugin(app);
}
newLinkData(): ILinkData {
return this._options.newData();
}
bind(): void {
super.bind();
this.app.addKeyboardListener(this.keyqListener, this.keyzListener);
@ -158,28 +153,25 @@ export class LinkDraw extends GraphicDrawAssistant<LinkTemplate> {
}
}
}
prepareData(): ILinkData | null {
prepareData(data: ILinkData): boolean {
const template = this.graphicTemplate;
if (
(!template.curve && this.points.length < 2) ||
(template.curve && this.points.length < 4)
) {
console.log('Link绘制因点不够取消绘制');
return null;
return false;
}
if (template.curve) {
this.points.pop();
}
const data = this.newLinkData();
data.id = this.nextId();
data.graphicType = Link.Type;
data.curve = template.curve;
data.segmentsCount = template.segmentsCount;
data.points = this.points;
data.lineWidth = template.lineWidth;
data.lineColor = template.lineColor;
data.segmentsCount = template.segmentsCount;
return data;
return true;
}
}

View File

View File

@ -10,7 +10,7 @@ import {
Point,
} from 'pixi.js';
import { GraphicIdGenerator } from '../core/IdGenerator';
import { JlGraphic, GraphicData, GraphicTemplate } from '../core/JlGraphic';
import { GraphicData, GraphicTemplate, JlGraphic } from '../core/JlGraphic';
import { BoundsGraphic, TransformPoints } from '../graphic';
import { JlOperation } from '../operation/JlOperation';
import {
@ -35,33 +35,40 @@ import {
*
*/
export abstract class GraphicDrawAssistant<
GT extends GraphicTemplate
GT extends GraphicTemplate,
GD extends GraphicData
> extends AppInteractionPlugin {
_isDrawAssistant = true;
app: JlDrawApp;
type: string; // 图形对象类型
description?: string; // 描述
icon: string; // 界面显示的图标
container: Container = new Container();
graphicTemplate: GT;
createGraphicData: () => GD;
escListener: KeyListener = new KeyListener({
value: 'Escape',
onPress: () => {
this.createAndStore(true);
onRelease: () => {
this.onEsc();
},
});
onEsc() {
this.createAndStore(true);
}
constructor(
graphicApp: JlDrawApp,
graphicTemplate: GT,
createGraphicData: () => GD,
icon: string,
description?: string
) {
super(graphicTemplate.type, graphicApp);
this.app = graphicApp;
this.graphicTemplate = graphicTemplate;
this.type = graphicTemplate.type;
this.graphicTemplate = graphicTemplate;
this.createGraphicData = createGraphicData;
this.icon = icon;
this.description = description;
this.app.registerGraphicTemplates(this.graphicTemplate);
@ -131,7 +138,7 @@ export abstract class GraphicDrawAssistant<
*/
abstract redraw(cp: Point): void;
abstract prepareData(): GraphicData | null;
abstract prepareData(data: GD): boolean;
toCanvasCoordinates(p: Point): Point {
return this.app.toCanvasCoordinates(p);
@ -148,8 +155,10 @@ export abstract class GraphicDrawAssistant<
* App
*/
createAndStore(finish: boolean): JlGraphic | null {
const data = this.prepareData();
if (!data) {
const data = this.createGraphicData();
data.id = this.nextId();
data.graphicType = this.graphicTemplate.type;
if (!this.prepareData(data)) {
if (finish) {
this.finish();
}
@ -158,7 +167,6 @@ export abstract class GraphicDrawAssistant<
const template = this.graphicTemplate;
const g = template.new();
g.loadData(data);
g.id = this.nextId();
this.storeGraphic(g);
if (finish) {
this.finish(g);
@ -183,11 +191,13 @@ export enum DrawAppEvent {
propertiesupdate = 'propertiesupdate', // 图形对象数据变更
}
export type DrawAssistant = GraphicDrawAssistant<GraphicTemplate, GraphicData>;
export interface IDrawAppOptions {
/**
*
*/
drawAssistants: GraphicDrawAssistant<GraphicTemplate>[];
drawAssistants: DrawAssistant[];
}
export type DrawAppOptions = GraphicAppOptions & IDrawAppOptions;
@ -212,7 +222,7 @@ export class JlDrawApp extends GraphicApp {
fontName: 'coordinates',
});
drawAssistants: GraphicDrawAssistant<GraphicTemplate>[] = [];
drawAssistants: DrawAssistant[] = [];
selectedData: GraphicData | ICanvasProperties | null;
@ -244,14 +254,14 @@ export class JlDrawApp extends GraphicApp {
});
}
getDrawAssistant(graphicType: string): GraphicDrawAssistant<GraphicTemplate> {
getDrawAssistant<DA extends DrawAssistant>(graphicType: string): DA {
const sda = this.drawAssistants
.filter((da) => da.type === graphicType)
.pop();
if (!sda) {
throw new Error(`未找到图形绘制助手: ${graphicType}`);
}
return sda;
return sda as DA;
}
private appDragRecord() {

View File

@ -432,6 +432,16 @@ export class GraphicApp extends EventEmitter<GraphicAppEvents> {
tool.resume();
// 视口移动插件
ViewportMovePlugin.new(this);
this.app.ticker.add((dt: number) => {
this.queryStore.getAllGraphics().forEach((g) => {
g.animationMap.forEach((animation) => {
if (animation.running) {
animation.run(dt);
}
});
});
});
}
setOptions(options: GraphicAppOptions) {
@ -458,8 +468,6 @@ export class GraphicApp extends EventEmitter<GraphicAppEvents> {
registerGraphicTemplates(...graphicTemplates: GraphicTemplate[]) {
graphicTemplates.forEach((graphicTemplate) => {
this.graphicTemplateMap.set(graphicTemplate.type, graphicTemplate);
// 加载资源
graphicTemplate.loadAsserts();
});
}
@ -597,8 +605,11 @@ export class GraphicApp extends EventEmitter<GraphicAppEvents> {
* @param protos
* @param options /
*/
loadGraphic(protos: GraphicData[]) {
// console.log('开始加载proto数据', protos);
async loadGraphic(protos: GraphicData[]) {
for (const item of this.graphicTemplateMap) {
await item[1].loadAssets();
}
console.log('开始加载proto数据', protos);
// 加载数据到图形存储
protos.forEach((proto) => {
const template = this.getGraphicTemplatesByType(proto.graphicType);

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
import { Viewport } from 'pixi-viewport';
@ -451,9 +452,9 @@ export interface GraphicData {
copyFrom(data: GraphicData): void;
/**
*
* @param data
* @param other
*/
eq(data: GraphicData): boolean;
eq(other: GraphicData): boolean;
}
/**
@ -478,6 +479,63 @@ export interface GraphicState {
eq(data: GraphicState): boolean;
}
export interface GraphicAnimationOptions {
name: string;
/**
*
*/
path?: IPointData[];
/**
* ()moveToAndFro互斥
*/
cycleMove?: boolean;
/**
* ()cycleMove互斥
*/
moveToAndFro?: boolean;
run?: (dt: number) => void;
}
export class GraphicAnimation {
options: GraphicAnimationOptions;
_running: boolean;
_finish: boolean;
constructor(options: GraphicAnimationOptions) {
this.options = options;
this._running = false;
this._finish = false;
}
static init(options: GraphicAnimationOptions) {
return new GraphicAnimation(options);
}
pause(): GraphicAnimation {
this._running = false;
return this;
}
resume(): GraphicAnimation {
this._running = true;
return this;
}
public get name(): string {
return this.options.name;
}
public get running(): boolean {
return this._running;
}
run(dt: number): GraphicAnimation {
if (this.options.run) {
this.options.run(dt);
}
return this;
}
}
/**
*
*/
@ -488,6 +546,7 @@ export abstract class JlGraphic extends Container {
private _code = ''; // 业务编号/名称,用于标识图形对象,具有业务意义
_datas?: GraphicData; // 图形数据
_states?: GraphicState; // 图形状态数据
animationMap: Map<string, GraphicAnimation> = new Map();
private _relationManage?: RelationManage; // 图形关系管理
private _queryStore?: GraphicQueryStore; // 图形对象查询仓库
@ -498,6 +557,13 @@ export abstract class JlGraphic extends Container {
this.filters;
}
addAnimation(animation: GraphicAnimation): void {
this.animationMap.set(animation.name, animation);
}
removeAnimation(name: string): void {
this.animationMap.delete(name);
}
/**
*
* @param selected
@ -803,6 +869,7 @@ export abstract class JlGraphic extends Container {
*
*/
abstract doRepaint(): void;
/**
*
*/
@ -838,7 +905,7 @@ export abstract class JlGraphicTemplate<G extends JlGraphic> {
/**
*
*/
loadAsserts(): void {}
async loadAssets(): Promise<any> {}
/**
*

View File

@ -153,6 +153,7 @@ export class JlGraphicAppKeyboardPlugin {
* @param keyListener
*/
removeKeyListener(keyListener: KeyListener) {
keyListener.onRemove();
const map = this.getOrInit(keyListener.value);
const old = map.get(keyListener.identifier);
map.delete(keyListener.identifier);
@ -343,4 +344,8 @@ export class KeyListener {
}
}
}
onRemove(): void {
// 重置按下状态
this.isPress = false;
}
}

View File

@ -1,8 +0,0 @@
/**
*
* @param obj
* @returns
*/
export function isProxy(obj: any): boolean {
return !!(obj && obj['__Proxy']);
}

View File

@ -2,7 +2,6 @@ import { Point, Rectangle } from 'pixi.js';
export * from './GraphicUtils';
export * from './IntersectUtils';
export * from './ObjectUtils';
export const UP: Point = new Point(0, -1);
export const DOWN: Point = new Point(0, 1);