目录结构及编译调整

This commit is contained in:
Yuan 2023-12-12 17:31:07 +08:00
parent 218b1b5922
commit f44ecb69b8
107 changed files with 5994 additions and 6696 deletions

42
lib/app/BasicOperation.d.ts vendored Normal file
View File

@ -0,0 +1,42 @@
import { GraphicData, JlGraphic } from '../core';
import { JlOperation } from '../operation';
import { ICanvasProperties, IGraphicApp, IJlCanvas } from './JlGraphicApp';
/**
*
*/
export declare class UpdateCanvasOperation extends JlOperation {
obj: IJlCanvas;
old: ICanvasProperties;
data: ICanvasProperties;
description: string;
constructor(app: IGraphicApp, obj: IJlCanvas, old: ICanvasProperties, data: ICanvasProperties);
undo(): JlGraphic[];
redo(): JlGraphic[];
}
/**
*
*/
export declare class GraphicCreateOperation extends JlOperation {
obj: JlGraphic[];
description: string;
constructor(app: IGraphicApp, obj: JlGraphic[]);
undo(): JlGraphic[] | void;
redo(): JlGraphic[];
}
/**
*
*/
export declare class GraphicDeleteOperation extends JlOperation {
obj: JlGraphic[];
constructor(app: IGraphicApp, obj: JlGraphic[]);
undo(): JlGraphic[];
redo(): void;
}
export declare class GraphicDataUpdateOperation extends JlOperation {
obj: JlGraphic[];
oldData: GraphicData[];
newData: GraphicData[];
constructor(app: IGraphicApp, obj: JlGraphic[], oldData: GraphicData[], newData: GraphicData[]);
undo(): void | JlGraphic[];
redo(): void | JlGraphic[];
}

150
lib/app/JlDrawApp.d.ts vendored Normal file
View File

@ -0,0 +1,150 @@
import { BitmapFont, BitmapText, Container, FederatedMouseEvent, Point } from 'pixi.js';
import { GraphicData, GraphicTemplate, JlGraphic } from '../core/JlGraphic';
import { AppInteractionPlugin, InteractionPlugin, KeyListener } from '../plugins';
import { GraphicApp, GraphicAppOptions, ICanvasProperties, IGraphicApp, IJlCanvas } from './JlGraphicApp';
/**
*
*/
export declare abstract class GraphicDrawAssistant<GT extends GraphicTemplate, GD extends GraphicData> extends AppInteractionPlugin {
readonly __GraphicDrawAssistant = true;
app: IDrawApp;
type: string;
description: string;
icon: string;
container: Container;
graphicTemplate: GT;
escListener: KeyListener;
onEsc(): void;
constructor(graphicApp: IDrawApp, graphicTemplate: GT, icon: string, description: string);
get canvas(): IJlCanvas;
bind(): void;
unbind(): void;
onLeftDown(e: FederatedMouseEvent): void;
onMouseMove(e: FederatedMouseEvent): void;
onLeftUp(e: FederatedMouseEvent): void;
onRightDown(e: FederatedMouseEvent): void;
onRightUp(e: FederatedMouseEvent): void;
onRightClick(e: FederatedMouseEvent): void;
/**
* id
*/
nextId(): string;
clearCache(): void;
/**
*
* @param cp
*/
abstract redraw(cp: Point): void;
abstract prepareData(data: GD): boolean;
toCanvasCoordinates(p: Point): Point;
/**
*
*/
storeGraphic(...graphics: JlGraphic[]): void;
/**
* App
*/
createAndStore(finish: boolean): JlGraphic | null;
/**
*
*/
finish(...graphics: JlGraphic[]): void;
}
/**
*
*/
export type DrawAssistant = GraphicDrawAssistant<GraphicTemplate, GraphicData>;
/**
*
*/
export type DrawAppOptions = GraphicAppOptions;
/**
*
*/
export interface IDrawApp extends IGraphicApp {
/**
*
*/
get drawing(): boolean;
/**
*
*/
set drawing(value: boolean);
/**
*
* @param options
*/
setOptions(options: DrawAppOptions): void;
/**
*
*/
getDrawAssistant<DA extends DrawAssistant>(graphicType: string): DA;
/**
*
* @param data
*/
updateCanvasAndRecord(data: ICanvasProperties): void;
/**
*
* @param g
* @param data
*/
updateGraphicAndRecord(g: JlGraphic, data: GraphicData): void;
/**
* form表单对象
* @param form
*/
bindFormData(form: GraphicData): void;
/**
* form表单对象
* @param form
*/
unbindFormData(form: GraphicData): void;
}
/**
*
*/
export declare class JlDrawApp extends GraphicApp implements IDrawApp {
font: BitmapFont;
coordinates: BitmapText;
scaleText: BitmapText;
drawAssistants: DrawAssistant[];
_drawing: boolean;
private debouncedFormDataUpdator;
get drawing(): boolean;
set drawing(value: boolean);
constructor(options: DrawAppOptions);
setOptions(options: DrawAppOptions): void;
registerInteractionPlugin(...plugins: InteractionPlugin[]): void;
getDrawAssistant<DA extends DrawAssistant>(graphicType: string): DA;
private appOperationRecord;
/**
*
*/
private appendDrawStatesDisplay;
bindKeyboardOperation(): void;
/**
* ,
* @param graphic
*/
beforeGraphicStore(graphic: JlGraphic): void;
formData: GraphicData | undefined;
/**
* form表单对象
* @param form
*/
bindFormData(form: GraphicData): void;
/**
* form绑定
* @param form
*/
unbindFormData(form: GraphicData): void;
private formDataSyncListen;
/**
* 使debounce限流
*/
private handleFormDataUpdate;
private doFormDataUpdate;
updateCanvasAndRecord(data: ICanvasProperties): void;
updateGraphicAndRecord(g: JlGraphic, data: GraphicData): void;
}

601
lib/app/JlGraphicApp.d.ts vendored Normal file
View File

@ -0,0 +1,601 @@
/// <reference types="node" />
import EventEmitter from 'eventemitter3';
import { Viewport } from 'pixi-viewport';
import { Application, Container, DisplayObject, Graphics, Point } from 'pixi.js';
import { GraphicQueryStore } from '../core/GraphicStore';
import { GraphicData, GraphicState, GraphicTemplate, GraphicTransform, JlGraphic } from '../core/JlGraphic';
import { AbsorbablePosition } from '../graphic';
import { AppWsMsgBroker, GraphicQuery, ICreateOnNotFound, type AppStateSubscription, type MessageCliOption } from '../message';
import { OperationRecord } from '../operation/JlOperation';
import { AnimationManager, IMouseToolOptions } from '../plugins';
import { GraphicCopyPlugin } from '../plugins/CopyPlugin';
import { AppDragEvent, InteractionPlugin } from '../plugins/InteractionPlugin';
import { JlGraphicAppKeyboardPlugin, KeyListener } from '../plugins/KeyboardPlugin';
import { ContextMenu, ContextMenuPlugin } from '../ui/ContextMenu';
import { MenuItemOptions } from '../ui/Menu';
export declare const AppConsts: {
viewportname: string;
canvasname: string;
AssistantAppendsName: string;
assistantElementColor: string;
};
/**
*
*/
export interface ICanvasProperties {
width: number;
height: number;
backgroundColor: string;
viewportTransform: GraphicTransform;
}
export declare class CanvasData implements ICanvasProperties {
width: number;
height: number;
backgroundColor: string;
viewportTransform: GraphicTransform;
constructor(properties?: ICanvasProperties);
copyFrom(properties: ICanvasProperties): boolean;
clone(): CanvasData;
}
export interface IJlCanvas extends Container {
/**
*
*/
get properties(): ICanvasProperties;
/**
*
*/
get scene(): IGraphicScene;
/**
*
* @param properties
*/
update(properties: ICanvasProperties): void;
/**
*
* @param appends
*/
addAssistantAppends(...appends: DisplayObject[]): void;
/**
*
* @param appends
*/
removeAssistantAppends(...appends: DisplayObject[]): void;
/**
*
*/
saveData(): ICanvasProperties;
}
export declare class JlCanvas extends Container implements IJlCanvas {
__JlCanvas: boolean;
type: string;
scene: IGraphicScene;
_properties: CanvasData;
bg: Graphics;
nonInteractiveContainer: Container;
assistantAppendContainer: Container;
constructor(scene: IGraphicScene, properties?: CanvasData);
/**
* /
*/
repaint(): void;
get width(): number;
get height(): number;
get backgroundColor(): string;
doRepaint(): void;
get properties(): CanvasData;
saveData(): CanvasData;
update(properties: ICanvasProperties): void;
addChild<U extends DisplayObject[]>(...children: U): U[0];
removeChild<U extends DisplayObject[]>(...children: U): U[0];
/**
* Child
*/
addNonInteractiveChild(...obj: DisplayObject[]): void;
removeGraphic(...obj: DisplayObject[]): void;
/**
* Child
*/
removeNonInteractiveChild(...obj: DisplayObject[]): void;
addAssistantAppends(...appends: DisplayObject[]): void;
removeAssistantAppends(...appends: DisplayObject[]): void;
/**
*
*/
pauseInteractiveChildren(): void;
/**
*
*/
resumeInteractiveChildren(): void;
}
/**
*
*/
export declare class SelectedChangeEvent {
graphic: JlGraphic;
select: boolean;
constructor(graphic: JlGraphic, select: boolean);
}
/**
*
*/
export interface GraphicAppEvents extends GlobalMixins.GraphicAppEvents {
graphicstored: [graphic: JlGraphic];
graphicdeleted: [graphic: JlGraphic];
postdataloaded: [];
loadfinish: [];
'interaction-plugin-resume': [plugin: InteractionPlugin];
'interaction-plugin-pause': [plugin: InteractionPlugin];
'options-update': [options: GraphicAppOptions];
graphicselectedchange: [graphic: JlGraphic, selected: boolean];
graphicchildselectedchange: [child: DisplayObject, selected: boolean];
graphicselected: [graphics: JlGraphic[]];
'viewport-scaled': [vp: Viewport];
drag_op_start: [event: AppDragEvent];
drag_op_move: [event: AppDragEvent];
drag_op_end: [event: AppDragEvent];
'pre-menu-handle': [menu: MenuItemOptions];
'post-menu-handle': [menu: MenuItemOptions];
'websocket-connect-state-change': [connected: boolean];
'websocket-error': [err: Error];
destroy: [app: IGraphicApp];
}
/**
*
*/
export interface IGraphicStorage {
/**
*
*/
canvasProperty?: ICanvasProperties;
/**
*
*/
datas: GraphicData[];
}
/**
* App构造参数
*/
export interface IGraphicAppConfig {
/**
*
* @returns
*/
dataLoader?: () => Promise<IGraphicStorage>;
/**
* 100
*/
maxOperationRecords?: number;
/**
*
*/
threshold?: number;
/**
*
*/
mouseToolOptions?: IMouseToolOptions;
/**
*
*/
absorbablePositions?: AbsorbablePosition[];
/**
* true
*/
cullable?: boolean;
/**
*
*/
isSupportDeletion?: (g: JlGraphic) => boolean;
/**
* ,
*/
assistantElementColor?: string;
}
/**
*
*/
export interface IInteractiveGraphicOptions {
/**
* Excludes同时只能存在一个
*/
interactiveGraphicTypeIncludes?: string[];
/**
* Includes同时只能存在一个
*/
interactiveGraphicTypeExcludes?: string[];
}
export type GraphicAppOptions = IGraphicAppConfig & IInteractiveGraphicOptions;
/**
*
*/
export interface IGraphicScene extends EventEmitter<GraphicAppEvents> {
/**
*
*/
get app(): GraphicApp;
/**
* pixijs应用对象
*/
get pixi(): Application;
/**
*
*/
get viewport(): Viewport;
/**
*
*/
get canvas(): IJlCanvas;
/**
* dom
*/
get dom(): HTMLElement | undefined;
/**
*
*/
get queryStore(): GraphicQueryStore;
/**
*
*/
get selectedGraphics(): JlGraphic[];
/**
*
*/
get animationManager(): AnimationManager;
/**
*
*/
get appOptions(): GraphicAppOptions;
/**
*
* @param options
*/
setOptions(options: GraphicAppOptions): void;
/**
*
* @param menu
*/
registerMenu(menu: ContextMenu): void;
/**
*
* @param p
*/
toCanvasCoordinates(p: Point): Point;
/**
* /()
*/
reload(): Promise<void>;
/**
*
*/
forceReload(): Promise<void>;
/**
* dom
* @param dom
*/
bindDom(dom: HTMLElement): void;
/**
* dom节点移除
*/
unbindDom(): void;
/**
*
* @param graphicTemplates
*/
registerGraphicTemplates(...graphicTemplates: GraphicTemplate[]): void;
/**
*
* @param graphicStates
*/
handleGraphicStates(graphicStates: GraphicState[], queryer?: GraphicQuery, createOnNotFound?: ICreateOnNotFound): void;
/**
*
* @param type
*/
getGraphicTemplatesByType<GT extends GraphicTemplate>(type: string): GT;
/**
*
* @param graphics
*/
addGraphics(...graphics: JlGraphic[]): void;
/**
*
* @param graphics
*/
deleteGraphics(...graphics: JlGraphic[]): JlGraphic[];
/**
*
*/
detectRelations(): void;
/**
*
* @param plugins
*/
registerInteractionPlugin(...plugins: InteractionPlugin[]): void;
/**
*
*/
pauseAppInteractionPlugins(): void;
/**
* name获取交互插件
* @param name
*/
interactionPlugin<P = InteractionPlugin>(name: string): P;
/**
*
* @param graphics
*/
updateSelected(...graphics: JlGraphic[]): void;
/**
*
*/
selectAllGraphics(): void;
/**
* 使
* @param group
*/
makeGraphicCenterShow(...group: JlGraphic[]): void;
/**
*
*/
destroy(): void;
/**
* websocket消息
*/
subscribe(sub: AppStateSubscription): void;
/**
* websocket订阅
*/
unsubscribe(destination: string): void;
}
declare abstract class GraphicSceneBase extends EventEmitter<GraphicAppEvents> implements IGraphicScene {
private graphicStore;
_options: GraphicAppOptions;
pixi: Application;
viewport: Viewport;
canvas: JlCanvas;
_loaded: boolean;
_dom?: HTMLElement;
_viewportResizer?: NodeJS.Timeout;
graphicTemplateMap: Map<string, GraphicTemplate>;
interactionPluginMap: Map<string, InteractionPlugin>;
graphicCopyPlugin: GraphicCopyPlugin;
animationManager: AnimationManager;
menuPlugin: ContextMenuPlugin;
private debounceEmitFunc;
wsMsgBroker: AppWsMsgBroker;
constructor(options: GraphicAppOptions);
get appOptions(): GraphicAppOptions;
abstract get app(): GraphicApp;
get dom(): HTMLElement | undefined;
get queryStore(): GraphicQueryStore;
get selectedGraphics(): JlGraphic[];
private load;
/**
*
*/
reload(): Promise<void>;
forceReload(): Promise<void>;
/**
*
* @param options
*/
setOptions(options: GraphicAppOptions): void;
toCanvasCoordinates(p: Point): Point;
/**
*
* @param menu
*/
registerMenu(menu: ContextMenu): void;
/**
*
* @param graphicTemplates
*/
registerGraphicTemplates(...graphicTemplates: GraphicTemplate[]): void;
getGraphicTemplatesByType<GT extends GraphicTemplate>(type: string): GT;
private updateViewport;
/**
*
*/
private pause;
/**
*
*/
private resume;
bindDom(dom: HTMLElement): void;
unbindDom(): void;
/**
* ,GraphicApp默认添加到无交互容器,DrawApp默认添加到交互容器,
* @param protos
* @param options /
*/
loadGraphic(protos: GraphicData[]): Promise<void>;
/**
*
* @param graphic
*/
beforeGraphicStore(graphic: JlGraphic): void;
/**
*
* @param graphic
*/
private doAddGraphics;
private doDeleteGraphics;
/**
*
* @param graphics
*/
addGraphics(...graphics: JlGraphic[]): void;
/**
*
* @param graphics
*/
deleteGraphics(...graphics: JlGraphic[]): JlGraphic[];
/**
*
*/
detectRelations(): void;
/**
*
*/
selectAllGraphics(filter?: (g: JlGraphic) => boolean): void;
/**
*
*/
updateSelected(...graphics: JlGraphic[]): void;
private doEmitAppGraphicSelected;
/**
*
* @param param
*/
updateCanvas(param: ICanvasProperties): void;
/**
* 使()
*/
makeGraphicCenterShow(...group: JlGraphic[]): void;
/**
* ,
*/
registerInteractionPlugin(...plugins: InteractionPlugin[]): void;
/**
*
* @param name
* @returns
*/
interactionPlugin<P = InteractionPlugin>(name: string): P;
/**
*
*/
pauseAppInteractionPlugins(): void;
private doPauseInteractionPlugin;
/**
*
*/
removeInteractionPlugin(plugin: InteractionPlugin): void;
private checkWsMsgCli;
/**
* websocket消息
*/
subscribe(sub: AppStateSubscription): void;
/**
* websocket订阅
*/
unsubscribe(destination: string): void;
/**
*
* @param graphicStates
*/
handleGraphicStates(graphicStates: GraphicState[], queryer?: GraphicQuery, createOnNotFound?: ICreateOnNotFound): void;
/**
*
*/
destroy(): void;
}
/**
*
*/
export interface IGraphicApp extends IGraphicScene {
get opRecord(): OperationRecord;
/**
*
* @param code
* @returns
*/
initScene(code: string, options: GraphicAppOptions): IGraphicScene;
/**
*
* @param code
* @returns
*/
getScene(code: string): IGraphicScene;
/**
*
* @param dom
*/
switchScene(code: string, dom: HTMLElement): void;
/**
* code场景
* @param code
*/
removeScene(code: string): void;
/**
*
* @param graphics
*/
addGraphicAndRecord(...graphics: JlGraphic[]): void;
/**
*
* @param graphics
*/
deleteGraphicAndRecord(...graphics: JlGraphic[]): void;
/**
* websocket消息客户端
*/
enableWsMassaging(options: MessageCliOption): void;
/**
* ,
* @param keyListeners
*/
addKeyboardListener(...keyListeners: KeyListener[]): void;
/**
*
* @param keyListeners
*/
removeKeyboardListener(...keyListeners: KeyListener[]): void;
}
/**
* app基类
*/
export declare class GraphicApp extends GraphicSceneBase implements IGraphicApp {
/**
*
*/
scenes: Map<string, JlScene>;
opRecord: OperationRecord;
keyboardPlugin: JlGraphicAppKeyboardPlugin;
constructor(options: GraphicAppOptions);
get app(): GraphicApp;
setOptions(options: GraphicAppOptions): void;
addGraphicAndRecord(...graphics: JlGraphic[]): void;
deleteGraphicAndRecord(...graphics: JlGraphic[]): void;
/**
*
* @param code
* @returns
*/
initScene(code: string, options: GraphicAppOptions): IGraphicScene;
/**
*
* @param code
* @returns
*/
getScene(code: string): IGraphicScene;
switchScene(code: string, dom: HTMLElement): void;
removeScene(code: string): void;
/**
* websocket消息客户端
*/
enableWsMassaging(options: MessageCliOption): void;
/**
* ,
* @param keyListeners
*/
addKeyboardListener(...keyListeners: KeyListener[]): void;
/**
*
* @param keyListeners
*/
removeKeyboardListener(...keyListeners: KeyListener[]): void;
/**
*
*/
destroy(): void;
}
/**
*
*/
export default class JlScene extends GraphicSceneBase {
code: string;
app: GraphicApp;
constructor(app: GraphicApp, code: string, options: GraphicAppOptions);
}
export {};

17
lib/app/index.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import { DrawAppOptions, DrawAssistant, GraphicDrawAssistant, IDrawApp } from './JlDrawApp';
import { AppConsts, GraphicAppOptions, ICanvasProperties, IGraphicApp, IGraphicScene, IGraphicStorage, IJlCanvas } from './JlGraphicApp';
import { GraphicDataUpdateOperation } from './BasicOperation';
/**
* app
* @param options
* @returns
*/
export declare function newGraphicApp(options: GraphicAppOptions): IGraphicApp;
/**
* app
* @param options
* @returns
*/
export declare function newDrawApp(options: DrawAppOptions): IDrawApp;
export { AppConsts, GraphicDrawAssistant, GraphicDataUpdateOperation };
export type { DrawAssistant, ICanvasProperties, IDrawApp, IGraphicApp, IGraphicScene, IGraphicStorage, IJlCanvas, };

82
lib/core/GraphicRelation.d.ts vendored Normal file
View File

@ -0,0 +1,82 @@
import { JlGraphic } from './JlGraphic';
/**
*
*/
export declare class GraphicRelationParam {
g: JlGraphic;
param: any;
constructor(g: JlGraphic, param?: any);
isTheGraphic(g: JlGraphic): boolean;
getGraphic<G extends JlGraphic>(): G;
getParam<P>(): P;
equals(other: GraphicRelationParam): boolean;
}
/**
*
*/
export declare class GraphicRelation {
rp1: GraphicRelationParam;
rp2: GraphicRelationParam;
constructor(rp1: GraphicRelationParam, rp2: GraphicRelationParam);
contains(g: JlGraphic): boolean;
/**
*
* @param g
* @returns
*/
getRelationParam(g: JlGraphic): GraphicRelationParam;
/**
*
* @param g
* @returns
*/
getOtherRelationParam(g: JlGraphic): GraphicRelationParam;
/**
*
* @param g
* @returns graphic
*/
getOtherGraphic<G extends JlGraphic>(g: JlGraphic): G;
equals(orp1: GraphicRelationParam, orp2: GraphicRelationParam): boolean;
isEqualOther(other: GraphicRelation): boolean;
}
/**
*
*/
export declare class RelationManage {
relations: GraphicRelation[];
isContainsRelation(rp1: GraphicRelationParam, rp2: GraphicRelationParam): boolean;
addRelation(rp1: GraphicRelationParam | JlGraphic, rp2: GraphicRelationParam | JlGraphic): void;
/**
*
* @param g
* @returns
*/
getRelationsOfGraphic(g: JlGraphic): GraphicRelation[];
/**
*
* @param g
* @param type
* @returns
*/
getRelationsOfGraphicAndOtherType(g: JlGraphic, type: string): GraphicRelation[];
/**
*
* @param relation
*/
private deleteRelation;
/**
*
* @param g
*/
deleteRelationOfGraphic(g: JlGraphic): void;
/**
*
* @param g
*/
deleteRelationOfGraphicAndOtherType(g: JlGraphic, type: string): void;
/**
*
*/
clear(): void;
}

90
lib/core/GraphicStore.d.ts vendored Normal file
View File

@ -0,0 +1,90 @@
import { RelationManage } from './GraphicRelation';
import { JlGraphic } from './JlGraphic';
export interface GraphicQueryStore {
/**
*
*/
getAllGraphics(): JlGraphic[];
/**
* id获取图形
*/
queryById<T extends JlGraphic>(id: string): T;
/**
* id模糊查询图形
* @param id
*/
queryByIdAmbiguous(id: string): JlGraphic[];
/**
*
*/
queryByType<T extends JlGraphic>(type: string): T[];
/**
* code查询
* @param code
*/
queryByCode(code: string): JlGraphic[] | undefined;
/**
* code模糊查询图形
* @param code
* @param type
*/
queryByCodeAmbiguous(code: string): JlGraphic[];
/**
* id或code查询图形
* @param v
*/
queryByIdOrCode(v: string): JlGraphic[];
/**
* id或code及类型查询图形
* @param v
* @param type
*/
queryByIdOrCodeAndType(v: string, type: string): JlGraphic[];
/**
* code和类型获取图形
* @param code
* @param type
*/
queryByCodeAndType<T extends JlGraphic>(code: string, type: string): T | undefined;
/**
* code和类型模糊查询图形
* @param code
* @param type
*/
queryByCodeAndTypeAmbiguous<T extends JlGraphic>(code: string, type: string): T[];
}
/**
*
*/
export declare class GraphicStore implements GraphicQueryStore {
store: Map<string, JlGraphic>;
relationManage: RelationManage;
constructor();
/**
*
*/
getAllGraphics(): JlGraphic[];
queryById<T extends JlGraphic>(id: string): T;
queryByIdAmbiguous(id: string): JlGraphic[];
queryByType<T extends JlGraphic>(type: string): T[];
queryByCode(code: string): JlGraphic[] | undefined;
queryByCodeAmbiguous(code: string): JlGraphic[];
queryByIdOrCode(s: string): JlGraphic[];
queryByIdOrCodeAndType(s: string, type: string): JlGraphic[];
queryByCodeAndType<T extends JlGraphic>(code: string, type: string): T | undefined;
queryByCodeAndTypeAmbiguous<T extends JlGraphic>(code: string, type: string): T[];
/**
*
* @param graphics
*/
storeGraphics(graphic: JlGraphic): boolean;
/**
*
* @param graph
*/
deleteGraphics(graphic: JlGraphic): JlGraphic | undefined;
/**
*
*/
clear(): void;
}

12
lib/core/IdGenerator.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
/**
* ID生成器
*/
export declare class IdGenerator {
serial: number;
type: string;
constructor(type: string);
next(): string;
getType(): string;
initSerial(serial: number): void;
}
export declare const GraphicIdGenerator: IdGenerator;

284
lib/core/JlGraphic.d.ts vendored Normal file
View File

@ -0,0 +1,284 @@
import { Container, DisplayObject, IPointData, Rectangle } from 'pixi.js';
import { GraphicRelation, RelationManage } from './GraphicRelation';
import { GraphicQueryStore } from './GraphicStore';
export interface IGraphicTransform {
position: IPointData;
scale: IPointData;
rotation: number;
skew: IPointData;
}
/**
*
*/
export declare class GraphicTransform {
position: IPointData;
scale: IPointData;
rotation: number;
skew: IPointData;
constructor(position: IPointData, scale: IPointData, rotation: number, skew: IPointData);
static default(): GraphicTransform;
static fromObject(obj: DisplayObject): GraphicTransform;
static from(transform: IGraphicTransform | undefined): GraphicTransform;
}
export interface IChildTransform {
name: string;
transform: IGraphicTransform;
}
/**
*
*/
export declare class ChildTransform {
name: string;
transform: GraphicTransform;
constructor(name: string, transform: GraphicTransform);
static fromChild(child: DisplayObject): ChildTransform;
static from(ct: IChildTransform): ChildTransform;
}
/**
*
*/
export interface GraphicData {
get id(): string;
set id(v: string);
get graphicType(): string;
set graphicType(v: string);
get transform(): GraphicTransform;
set transform(v: GraphicTransform);
get childTransforms(): ChildTransform[] | undefined;
set childTransforms(v: ChildTransform[] | undefined);
/**
*
*/
clone(): GraphicData;
/**
*
* @param data
*/
copyFrom(data: GraphicData): void;
/**
*
* @param other
*/
eq(other: GraphicData): boolean;
}
/**
*
*/
export interface GraphicState {
get code(): string;
get graphicType(): string;
remove?: boolean;
/**
*
*/
clone(): GraphicState;
/**
*
* @param data
*/
copyFrom(data: GraphicState): void;
/**
*
* @param data
*/
eq(data: GraphicState): boolean;
}
export interface GraphicAnimationOptions {
name: string;
run?: (dt: number) => void;
}
export declare class GraphicAnimation {
options: GraphicAnimationOptions;
_running: boolean;
/**
*
*/
_xSpeed: number;
constructor(options: GraphicAnimationOptions);
static init(options: GraphicAnimationOptions): GraphicAnimation;
pause(): GraphicAnimation;
resume(): GraphicAnimation;
get name(): string;
get running(): boolean;
get xSpeed(): number;
set xSpeed(v: number);
run(dt: number): GraphicAnimation;
}
/**
*
*/
export declare abstract class JlGraphic extends Container {
readonly __JlGraphic: true;
readonly type: string;
private _id;
private _code;
_datas?: GraphicData;
_states?: GraphicState;
private _relationManage?;
private _queryStore?;
constructor(type: string);
/**
*
* @param animation
*/
addAnimation(animation: GraphicAnimation): void;
removeAnimation(name: string): void;
animation(name: string): GraphicAnimation | undefined;
removeAllAnimation(): void;
/**
*
* @param selected
* @returns
*/
updateSelected(selected: boolean): boolean;
invertSelected(): void;
fireSelected(): void;
hasSelectedChilds(): boolean;
setChildSelected(child: DisplayObject): boolean;
invertChildSelected(child: DisplayObject): boolean;
removeAllChildSelected(): void;
fireChildSelected(child: DisplayObject): void;
exitChildEdit(): void;
/**
* id/code
*/
isIdOrCode(s: string): boolean;
/**
* idid
*/
get id(): string;
/**
* idid
*/
set id(v: string);
/**
* codecode在图形数据或图形状态中
*/
get code(): string;
/**
* codecode在图形数据或图形状态中
*/
set code(v: string);
getDatas<D extends GraphicData>(): D;
getStates<S extends GraphicState>(): S;
get queryStore(): GraphicQueryStore;
set queryStore(v: GraphicQueryStore);
get relationManage(): RelationManage;
set relationManage(v: RelationManage);
/**
*
* @param g
*/
buildRelation(): void;
/**
*
*/
loadRelations(): void;
/**
*
* @returns
*/
getAllRelations(): GraphicRelation[];
/**
*
* @param type
* @returns
*/
queryRelationByType(type: string): GraphicRelation[];
/**
*
* @param type
*/
deleteRelationByType(type: string): void;
/**
* datas中
*/
saveRelations(): void;
/**
*
* @returns
*/
saveData<D extends GraphicData>(): D;
/**
*
* @returns
*/
private buildChildTransforms;
/**
*
* @param data
*/
loadData(data: GraphicData): void;
private loadTransformFrom;
/**
*
* @param data
* @returns
*/
updateData(data: GraphicData): boolean;
/**
*
*/
onDataChange(newVal: GraphicData, old?: GraphicData): void;
/**
*
* @param state
*/
loadState(state: GraphicState): void;
/**
*
* @param state
* @returns
*/
updateStates(state: GraphicState): boolean;
/**
*
*/
onStateChange(newVal: GraphicState, old?: GraphicState): void;
repaint(): void;
/**
*
*/
abstract doRepaint(): void;
/**
*
*/
onDelete(): void;
/**
* ,,-
* @param box
* @returns
*/
boxIntersectCheck(box: Rectangle): boolean;
}
export type CreateData = () => GraphicData;
export type CreateState = () => GraphicState;
export interface IGraphicTemplateOptions {
dataTemplate?: GraphicData;
stateTemplate?: GraphicState;
}
/**
*
*/
export declare abstract class JlGraphicTemplate<G extends JlGraphic> {
readonly type: string;
options: IGraphicTemplateOptions;
constructor(type: string, options: IGraphicTemplateOptions);
get datas(): GraphicData;
get states(): GraphicState;
/**
*
*/
abstract new(): G;
/**
*
*/
loadAssets(): Promise<any>;
/**
*
* @param graphic
* @returns
*/
clone(graphic: G): G;
}
export type GraphicTemplate = JlGraphicTemplate<JlGraphic>;

91
lib/graphic/AbsorbablePosition.d.ts vendored Normal file
View File

@ -0,0 +1,91 @@
import { Container, DisplayObject, Graphics, IPointData, Point } from 'pixi.js';
import { VectorGraphic } from './VectorGraphic';
/**
*
*/
export interface AbsorbablePosition extends Container {
/**
* ()
* @param other
*/
isOverlapping(other: AbsorbablePosition): boolean;
/**
*
* @param other
* @returns >0<0另一个吸附范围大=0两个吸附范围一样大
*/
compareTo(other: AbsorbablePosition): number;
/**
*
* @param objs
* @returns truefalse
*/
tryAbsorb(...objs: DisplayObject[]): void;
}
/**
*
*/
export declare const AbsorbablePointParam: {
lineWidth: number;
lineColor: string;
fillColor: string;
radius: number;
};
/**
*
*/
export default class AbsorbablePoint extends Graphics implements AbsorbablePosition, VectorGraphic {
_point: Point;
absorbRange: number;
scaledListenerOn: boolean;
/**
*
* @param point
* @param absorbRange
*/
constructor(point: IPointData, absorbRange?: number);
compareTo(other: AbsorbablePosition): number;
isOverlapping(other: AbsorbablePosition): boolean;
tryAbsorb(...objs: DisplayObject[]): void;
updateOnScaled(): void;
}
/**
* 线
*/
export declare class AbsorbableLine extends Graphics implements AbsorbablePosition {
p1: Point;
p2: Point;
absorbRange: number;
_color: string;
/**
*
* @param p1
* @param p2
* @param absorbRange
*/
constructor(p1: IPointData, p2: IPointData, absorbRange?: number);
isOverlapping(other: AbsorbablePosition): boolean;
compareTo(other: AbsorbablePosition): number;
redraw(): void;
tryAbsorb(...objs: DisplayObject[]): void;
}
/**
*
*/
export declare class AbsorbableCircle extends Graphics implements AbsorbablePosition {
absorbRange: number;
p0: Point;
radius: number;
_color: string;
/**
*
* @param p
* @param radius
* @param absorbRange
*/
constructor(p: IPointData, radius: number, absorbRange?: number);
isOverlapping(other: AbsorbablePosition): boolean;
compareTo(other: AbsorbablePosition): number;
redraw(): void;
tryAbsorb(...objs: DisplayObject[]): void;
}

39
lib/graphic/DashedLine.d.ts vendored Normal file
View File

@ -0,0 +1,39 @@
import { Container, IPointData, Point } from 'pixi.js';
export interface IDashedLineOptions {
/**
* ,4
*/
length?: number;
/**
* ,0
*/
startSpace?: number;
/**
* ,4
*/
space?: number;
/**
* 线,1
*/
lineWidth?: number;
/**
* 线,
*/
color?: string;
}
interface ICompleteDashedLineOptions extends IDashedLineOptions {
length: number;
startSpace: number;
space: number;
lineWidth: number;
color: string;
}
export declare class DashedLine extends Container {
p1: Point;
p2: Point;
_options: ICompleteDashedLineOptions;
constructor(p1: IPointData, p2: IPointData, options?: IDashedLineOptions);
setOptions(options: IDashedLineOptions): void;
redraw(): void;
}
export {};

23
lib/graphic/DraggablePoint.d.ts vendored Normal file
View File

@ -0,0 +1,23 @@
import { Graphics, IPointData } from 'pixi.js';
import { VectorGraphic } from './VectorGraphic';
/**
*
*/
export declare const DraggablePointParam: {
lineWidth: number;
lineColor: number;
fillColor: number;
radius: number;
};
/**
*
*/
export declare class DraggablePoint extends Graphics implements VectorGraphic {
scaledListenerOn: boolean;
/**
*
* @param point
*/
constructor(point: IPointData);
updateOnScaled(): void;
}

8
lib/graphic/VectorGraphic.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import { DisplayObject } from 'pixi.js';
export interface VectorGraphic extends DisplayObject {
scaledListenerOn: boolean;
updateOnScaled(): void;
}
export declare class VectorGraphicUtil {
static handle(obj: VectorGraphic): void;
}

16
lib/graphic/VectorText.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
import { ICanvas, ITextStyle, Text, TextStyle } from 'pixi.js';
import { VectorGraphic } from '.';
/**
* .fontSize
*/
export declare class VectorText extends Text implements VectorGraphic {
vectorFontSize: number;
scaled: number;
scaledListenerOn: boolean;
constructor(text?: string | number, style?: Partial<ITextStyle> | TextStyle, canvas?: ICanvas);
updateOnScaled(): void;
/**
*
*/
setVectorFontSize(fontSize: number): void;
}

File diff suppressed because it is too large Load Diff

17
lib/math/Constants.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
/**
*
*/
export declare const epsilon = 0.00001;
/**
* 0
* @param v
* @returns
*/
export declare function isZero(v: number): boolean;
/**
*
* @param f1
* @param f2
* @returns
*/
export declare function floatEquals(f1: number, f2: number): boolean;

91
lib/math/Vector2.d.ts vendored Normal file
View File

@ -0,0 +1,91 @@
export default class Vector2 {
constructor(values?: [number, number]);
static from(p: {
x: number;
y: number;
}): Vector2;
private values;
static readonly zero: Vector2;
static readonly one: Vector2;
get x(): number;
set x(value: number);
get y(): number;
set y(value: number);
get xy(): [number, number];
set xy(values: [number, number]);
at(index: number): number;
reset(): void;
copy(dest?: Vector2): Vector2;
negate(dest?: Vector2): Vector2;
equals(vector: Vector2, threshold?: number): boolean;
length(): number;
squaredLength(): number;
add(vector: Vector2): Vector2;
subtract(vector: Vector2): Vector2;
multiply(vector: Vector2): Vector2;
divide(vector: Vector2): Vector2;
scale(value: number, dest?: Vector2): Vector2;
normalize(dest?: Vector2): Vector2;
/**
*
* @param vector
* @param vector2
* @returns
*/
static dot(vector: Vector2, vector2: Vector2): number;
/**
*
* @param vector
* @param vector2
* @returns
*/
static distance(vector: Vector2, vector2: Vector2): number;
/**
*
* @param vector
* @param vector2
* @returns
*/
static squaredDistance(vector: Vector2, vector2: Vector2): number;
/**
* v2->v1的方向的单位向量
* @param v1
* @param v2
* @param dest
* @returns
*/
static direction(v1: Vector2, v2: Vector2, dest?: Vector2): Vector2;
static mix(vector: Vector2, vector2: Vector2, time: number, dest?: Vector2): Vector2;
/**
*
* @param vector
* @param vector2
* @param dest
* @returns
*/
static sum(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2;
/**
*
* @param vector
* @param vector2
* @param dest
* @returns
*/
static difference(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2;
/**
*
* @param vector
* @param vector2
* @param dest
* @returns
*/
static product(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2;
/**
*
* @param vector
* @param vector2
* @param dest
* @returns
*/
static quotient(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2;
}

2
lib/math/index.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
export * from './Constants';
export * from './Vector2';

52
lib/message/BasicMessageClient.d.ts vendored Normal file
View File

@ -0,0 +1,52 @@
import EventEmitter from 'eventemitter3';
import { IGraphicScene } from '../app';
import { CompleteMessageCliOption, IMessageClient } from './MessageBroker';
export interface MessageClientEvents {
connected: [ctx: any];
disconnected: [ctx: any];
error: [err: any];
}
export type HandleMessage = (data: any) => void;
export interface IMessageHandler {
/**
* id
*/
get App(): IGraphicScene;
/**
*
* @param data
*/
handle(data: any): void;
}
export declare abstract class MessageClient extends EventEmitter<MessageClientEvents> implements IMessageClient {
options: CompleteMessageCliOption;
subClients: SubscriptionClient[];
constructor(options: CompleteMessageCliOption);
/**
*
* @param destination
* @param handle
*/
abstract subscribe(destination: string, handle: HandleMessage): boolean;
unsubscribe(destination: string): void;
abstract unsubscribe0(destination: string): void;
getOrNewSubClient(destination: string): SubscriptionClient;
addSubscription(destination: string, handler: IMessageHandler): void;
removeSubscription(destination: string, handle: IMessageHandler): void;
abstract get connected(): boolean;
abstract close(): void;
}
export declare class SubscriptionClient {
mc: MessageClient;
destination: string;
protocol: 'json' | 'protobuf';
handlers: IMessageHandler[];
subscripted: boolean;
constructor(mc: MessageClient, destination: string, protocal: 'json' | 'protobuf');
addHandler(handler: IMessageHandler): void;
removeHandler(handler: IMessageHandler): void;
trySubscribe(): void;
unsubscribe(): void;
handleMessage(data: any): void;
onDisconnect(): void;
}

146
lib/message/MessageBroker.d.ts vendored Normal file
View File

@ -0,0 +1,146 @@
import EventEmitter from 'eventemitter3';
import { IGraphicScene } from '../app';
import { GraphicQueryStore, GraphicState, JlGraphic } from '../core';
import { IMessageHandler, MessageClientEvents } from './BasicMessageClient';
export declare enum ClientEngine {
Stomp = 0,
MQTT = 1
}
export interface MessageCliOption {
/**
*
*/
engine?: ClientEngine;
/**
* ,protobuf
*/
protocol?: 'json' | 'protobuf';
/**
* websocket url地址
*/
wsUrl: string;
/**
* token
*/
token?: string;
/**
* ()
*/
clientName?: string;
/**
* ,30,ms
*/
connectTimeout?: number;
/**
* ,60,s
*/
heartbeat?: number;
/**
* ,2,ms
*/
retryPeriod?: number;
/**
* ,100
*/
retryTimes?: number;
}
export interface CompleteMessageCliOption extends MessageCliOption {
protocol: 'json' | 'protobuf';
connectTimeout: number;
heartbeat: number;
retryPeriod: number;
retryTimes: number;
}
export interface IMessageClient extends EventEmitter<MessageClientEvents> {
/**
*
* @param destination
* @param handler
*/
addSubscription(destination: string, handler: IMessageHandler): void;
/**
*
* @param destination
* @param handler
*/
removeSubscription(destination: string, handler: IMessageHandler): void;
/**
*
*/
get connected(): boolean;
/**
*
*/
close(): void;
}
export declare class WsMsgCli {
private static client;
private static options;
private static appMsgBroker;
static new(options: MessageCliOption): void;
static isInitiated(): boolean;
static emitConnectStateChangeEvent(connected: boolean): void;
static isConnected(): boolean;
static registerSubscription(destination: string, handler: IMessageHandler): void;
static unregisterSubscription(destination: string, handler: IMessageHandler): void;
static registerAppMsgBroker(broker: AppWsMsgBroker): void;
static removeAppMsgBroker(broker: AppWsMsgBroker): void;
static hasAppMsgBroker(): boolean;
/**
* websocket连接
*/
static close(): void;
}
export type GraphicStateMessageConvert = (message: Uint8Array) => GraphicState[];
export type GraphicQuery = (state: GraphicState, store: GraphicQueryStore) => JlGraphic | undefined;
export type SubscriptionMessageHandle = (message: Uint8Array) => void;
export interface ICreateOnNotFound {
graphicTypes?: string[];
}
export interface AppStateSubscription {
/**
*
*/
destination: string;
/**
*
*/
messageConverter?: GraphicStateMessageConvert;
/**
* ,code和type查询图形对象
*/
graphicQueryer?: GraphicQuery;
/**
*
*
*/
createOnNotFound?: ICreateOnNotFound;
/**
*
*/
messageHandle?: SubscriptionMessageHandle;
}
declare class AppMessageHandler implements IMessageHandler {
app: IGraphicScene;
sub: AppStateSubscription;
constructor(app: IGraphicScene, subOptions: AppStateSubscription);
get App(): IGraphicScene;
handle(data: any): void;
}
/**
* APP的websocket消息代理
*/
export declare class AppWsMsgBroker {
app: IGraphicScene;
subscriptions: Map<string, AppMessageHandler>;
constructor(app: IGraphicScene);
subscribe(sub: AppStateSubscription): void;
unsbuscribe(destination: string): void;
unsubscribeAll(): void;
resubscribeAll(): void;
/**
* Stomp客户端移除此消息代理
*/
close(): void;
}
export {};

13
lib/message/MqttBroker.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
import mqtt from 'mqtt';
import { HandleMessage, MessageClient } from './BasicMessageClient';
import { CompleteMessageCliOption } from './MessageBroker';
export declare class MqttMsgClient extends MessageClient {
cli: mqtt.MqttClient;
retryTimes: number;
subMsgHandler: Map<string, HandleMessage>;
constructor(options: CompleteMessageCliOption);
subscribe(destination: string, handle: HandleMessage): boolean;
unsubscribe0(destination: string): void;
get connected(): boolean;
close(): void;
}

11
lib/message/WsMsgBroker.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
import { Client as StompClient } from '@stomp/stompjs';
import { HandleMessage, MessageClient } from './BasicMessageClient';
import { CompleteMessageCliOption } from './MessageBroker';
export declare class StompMessagingClient extends MessageClient {
cli: StompClient;
constructor(options: CompleteMessageCliOption);
get connected(): boolean;
subscribe(destination: string, handle: HandleMessage): boolean;
unsubscribe0(destination: string): void;
close(): void;
}

42
lib/operation/JlOperation.d.ts vendored Normal file
View File

@ -0,0 +1,42 @@
import { IGraphicApp } from '../app/JlGraphicApp';
import { JlGraphic } from '../core/JlGraphic';
/**
*
*/
export declare abstract class JlOperation {
type: string;
app: IGraphicApp;
obj?: any;
data?: any;
description?: string;
constructor(app: IGraphicApp, type: string);
undo1(): void;
redo1(): void;
abstract undo(): JlGraphic[] | void;
abstract redo(): JlGraphic[] | void;
}
/**
*
*/
export declare class OperationRecord {
undoStack: JlOperation[];
redoStack: JlOperation[];
private maxLen;
constructor(maxLen?: number);
get hasUndo(): boolean;
get hasRedo(): boolean;
setMaxLen(v: number): void;
/**
*
* @param op
*/
record(op: JlOperation): void;
/**
*
*/
undo(): void;
/**
*
*/
redo(): void;
}

48
lib/plugins/AnimationManager.d.ts vendored Normal file
View File

@ -0,0 +1,48 @@
import { IGraphicScene } from '../app';
import { GraphicAnimation, JlGraphic } from '../core';
/**
*
*/
export declare class AnimationManager {
app: IGraphicScene;
_pause: boolean;
/**
* key - graphic.id
*/
graphicAnimationMap: Map<string, Map<string, GraphicAnimation>>;
constructor(app: IGraphicScene);
private run;
pause(): void;
resume(): void;
destroy(): void;
/**
* map
* @param graphic
* @returns
*/
animationMap(graphic: JlGraphic): Map<string, GraphicAnimation>;
/**
*
* @param graphic
* @param animation
*/
registerAnimation(graphic: JlGraphic, animation: GraphicAnimation): void;
/**
*
* @param graphic
* @param name
*/
unregisterAnimation(graphic: JlGraphic, name: string): void;
/**
*
* @param graphic
*/
unregisterGraphicAnimations(graphic: JlGraphic): void;
/**
*
* @param graphic
* @param name
* @returns
*/
animation(graphic: JlGraphic, name: string): GraphicAnimation | undefined;
}

82
lib/plugins/CommonMousePlugin.d.ts vendored Normal file
View File

@ -0,0 +1,82 @@
import { DisplayObject, FederatedMouseEvent, Graphics, Point } from 'pixi.js';
import { IGraphicScene } from '../app';
import { JlGraphic } from '../core';
import { AppDragEvent, AppInteractionPlugin } from './InteractionPlugin';
type GraphicSelectFilter = (graphic: JlGraphic) => boolean;
export interface IMouseToolOptions {
/**
* ,
*/
boxSelect?: boolean;
/**
* (),
*/
viewportDrag?: boolean;
/**
*
*/
viewportDragLeft?: boolean;
/**
* ,
*/
wheelZoom?: boolean;
/**
*
*/
selectFilter?: GraphicSelectFilter;
}
declare class CompleteMouseToolOptions implements IMouseToolOptions {
boxSelect: boolean;
viewportDrag: boolean;
viewportDragLeft: boolean;
wheelZoom: boolean;
selectFilter?: GraphicSelectFilter | undefined;
constructor();
update(options: IMouseToolOptions): void;
}
/**
*
*/
export declare class CommonMouseTool extends AppInteractionPlugin {
static Name: string;
static SelectBox: string;
options: CompleteMouseToolOptions;
box: Graphics;
leftDownTarget: DisplayObject | null;
drag: boolean;
graphicSelect: boolean;
rightTarget: DisplayObject | null;
constructor(scene: IGraphicScene);
static new(app: IGraphicScene): CommonMouseTool;
bind(): void;
unbind(): void;
onDragStart(event: AppDragEvent): void;
onDragMove(event: AppDragEvent): void;
onDragEnd(event: AppDragEvent): void;
setLeftCursor(e: FederatedMouseEvent): void;
resumeLeftCursor(): void;
setCursor(e: FederatedMouseEvent): void;
resumeCursor(): void;
onMouseDown(e: FederatedMouseEvent): void;
/**
*
* @param e
*/
onMouseUp(e: FederatedMouseEvent): void;
/**
*
*/
clearCache(): void;
get boxSelect(): boolean | undefined;
get selectFilter(): GraphicSelectFilter | undefined;
/**
*
*/
boxSelectDraw(start: Point, end: Point): void;
/**
*
* @returns
*/
boxSelectGraphicCheck(): void;
}
export {};

23
lib/plugins/CopyPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,23 @@
import { Container, FederatedPointerEvent, Point } from 'pixi.js';
import { IGraphicScene } from '../app';
import { JlGraphic } from '../core';
import { KeyListener } from './KeyboardPlugin';
/**
*
*/
export declare class GraphicCopyPlugin {
container: Container;
scene: IGraphicScene;
keyListeners: KeyListener[];
copys: JlGraphic[];
start?: Point;
running: boolean;
moveLimit?: 'x' | 'y';
constructor(scene: IGraphicScene);
updateMoveLimit(limit?: 'x' | 'y'): void;
init(): void;
clear(): void;
onPointerMove(e: FederatedPointerEvent): void;
onFinish(): void;
cancle(): void;
}

82
lib/plugins/GraphicEditPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,82 @@
import { Container, DisplayObject, Graphics, IDestroyOptions, IPointData } from 'pixi.js';
import { JlGraphic } from '../core';
import { DraggablePoint } from '../graphic';
export declare abstract class GraphicEditPlugin<DO extends DisplayObject = DisplayObject> extends Container {
graphic: DO;
constructor(g: DO);
destroy(options?: boolean | IDestroyOptions | undefined): void;
abstract updateEditedPointsPosition(): void;
hideAll(): void;
showAll(): void;
}
export interface ILineGraphic extends JlGraphic {
get linePoints(): IPointData[];
set linePoints(points: IPointData[]);
}
export declare abstract class LineEditPlugin extends GraphicEditPlugin<ILineGraphic> {
linePoints: IPointData[];
editedPoints: DraggablePoint[];
constructor(g: ILineGraphic);
destroy(options?: boolean | IDestroyOptions | undefined): void;
reset(): void;
abstract initEditPoints(): void;
}
export declare function getWayLineIndex(points: IPointData[], p: IPointData): {
start: number;
end: number;
};
export declare function getWaypointRangeIndex(points: IPointData[], curve: boolean, p: IPointData, lineWidth: number): {
start: number;
end: number;
};
export type onEditPointCreate = (g: ILineGraphic, dp: DraggablePoint, index: number) => void;
export interface IEditPointOptions {
/**
*
*/
onEditPointCreate?: onEditPointCreate;
}
/**
* 线(线)
*/
export declare class PolylineEditPlugin extends LineEditPlugin {
static Name: string;
options: IEditPointOptions;
constructor(g: ILineGraphic, options?: IEditPointOptions);
initEditPoints(): void;
updateEditedPointsPosition(): void;
}
export interface BezierCurveEditPointOptions extends IEditPointOptions {
auxiliaryLineColor?: string;
smooth?: boolean;
symmetry?: boolean;
}
export interface ICompleteBezierCurveEditPointOptions extends BezierCurveEditPointOptions {
smooth: boolean;
}
export declare function addWayPoint(graphic: ILineGraphic, curve: boolean, start: number, end: number, p: IPointData): void;
export declare function addLineWayPoint(graphic: ILineGraphic, start: number, end: number, p: IPointData): void;
export declare function addPolygonSegmentingPoint(graphic: ILineGraphic, start: number, end: number, knife?: number): void;
export declare function addBezierWayPoint(graphic: ILineGraphic, start: number, end: number, p: IPointData): void;
export declare function removeWayPoint(graphic: ILineGraphic, curve: boolean, i: number): void;
export declare function removeLineWayPoint(graphic: ILineGraphic, i: number): void;
export declare function removeBezierWayPoint(graphic: ILineGraphic, i: number): void;
/**
* (),线线
* @param graphic
* @param curve
*/
export declare function clearWayPoint(graphic: ILineGraphic, curve: boolean): void;
/**
* 线
*/
export declare class BezierCurveEditPlugin extends LineEditPlugin {
static Name: string;
options: ICompleteBezierCurveEditPointOptions;
auxiliaryLines: Graphics[];
constructor(g: ILineGraphic, options?: BezierCurveEditPointOptions);
reset(): void;
initEditPoints(): void;
drawAuxiliaryLine(line: Graphics, p1: IPointData, p2: IPointData): void;
updateEditedPointsPosition(): void;
}

207
lib/plugins/GraphicTransformPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,207 @@
import { Container, DisplayObject, Graphics, IDestroyOptions, Point } from 'pixi.js';
import { AppDragEvent, InteractionPluginBase, KeyListener } from '.';
import { IGraphicScene } from '../app';
import { AbsorbablePosition, VectorText } from '../graphic';
import { DraggablePoint } from '../graphic/DraggablePoint';
import { DebouncedFunction } from '../utils';
export declare class ShiftData {
/**
*
*/
startPosition: Point;
/**
*
*/
lastPosition?: Point;
/**
*
*/
currentPosition?: Point;
constructor(startPosition: Point, currentPosition?: Point, lastPosition?: Point);
static new(startPosition: Point, currentPosition?: Point, lastPosition?: Point): ShiftData;
get dx(): number;
get dy(): number;
get dsx(): number;
get dsy(): number;
}
export declare class ScaleData {
start: Point;
current?: Point;
last?: Point;
constructor(start: Point, current?: Point, last?: Point);
static new(start: Point, current?: Point, last?: Point): ScaleData;
}
export type TransformData = ShiftData | null;
/**
*
*/
export declare class GraphicTransformEvent {
/**
*
*/
target: DisplayObject;
type: 'shift' | 'rotate' | 'scale' | 'skew';
data: TransformData;
constructor(target: DisplayObject, type: 'shift' | 'rotate' | 'scale' | 'skew', data: TransformData);
getData<D extends TransformData>(): D;
static shift(target: DisplayObject, data: ShiftData): GraphicTransformEvent;
static scale(target: DisplayObject): GraphicTransformEvent;
static rotate(target: DisplayObject): GraphicTransformEvent;
static skew(target: DisplayObject): GraphicTransformEvent;
isShift(): boolean;
isRotate(): boolean;
isScale(): boolean;
isSkew(): boolean;
}
export declare class GraphicTransformPlugin extends InteractionPluginBase {
static Name: string;
/**
*
*/
absorbablePositions?: AbsorbablePosition[];
apContainer: Container;
static AbsorbablePosisiontsName: string;
constructor(app: IGraphicScene);
/**
*
* @param positions
* @returns
*/
filterAbsorbablePositions(positions: AbsorbablePosition[]): AbsorbablePosition[];
static new(app: IGraphicScene): GraphicTransformPlugin;
bind(): void;
unbind(): void;
getDraggedTargets(e: AppDragEvent): DisplayObject[];
onDragStart(e: AppDragEvent): void;
onDragMove(e: AppDragEvent): void;
onDragEnd(e: AppDragEvent): void;
/**
*
*/
clearCache(): void;
onGraphicSelectedChange(g: DisplayObject, selected: boolean): void;
}
/**
*
*/
export declare class TransformPoints extends Container {
static Name: string;
static MinLength: number;
static LeftTopName: string;
static TopName: string;
static RightTopName: string;
static RightName: string;
static RightBottomName: string;
static BottomName: string;
static LeftBottomName: string;
static LeftName: string;
static RotateName: string;
obj: DisplayObject;
ltScalePoint: DraggablePoint;
ltLocal: Point;
tScalePoint: DraggablePoint;
tLocal: Point;
tCanvas: Point;
rtScalePoint: DraggablePoint;
rtLocal: Point;
rScalePoint: DraggablePoint;
rLocal: Point;
rbScalePoint: DraggablePoint;
rbLocal: Point;
bScalePoint: DraggablePoint;
bLocal: Point;
lbScalePoint: DraggablePoint;
lbLocal: Point;
lScalePoint: DraggablePoint;
lLocal: Point;
originScale: Point;
scalePivot: Point;
/**
*
*/
rotatePoint: DraggablePoint;
/**
*
*/
rotatePivot: Point;
/**
*
*/
rotateLastPoint: Point;
/**
*
*/
startAngle: number;
/**
*
*/
angleAssistantText: VectorText;
/**
*
*/
angleStep: number;
/**
*
*/
rotateAngleStepKeyListeners: KeyListener[];
constructor(obj: DisplayObject);
onObjTransformStart(): void;
onObjTransformEnd(): void;
onGraphicRepaint(): void;
/**
*
* @param de
*/
onRotateStart(de: GraphicTransformEvent): void;
updateAngleAssistantText(de: GraphicTransformEvent): void;
/**
*
* @param de
*/
onRotateMove(de: GraphicTransformEvent): void;
/**
*
* @param de
*/
onRotateEnd(): void;
/**
*
*/
onScaleDragStart(): void;
onScaleDragMove(e: GraphicTransformEvent): void;
onScaleDragEnd(): void;
hideOthers(dg: DisplayObject): void;
hideAll(): void;
showAll(): void;
getObjBounds(): {
width: number;
height: number;
};
/**
* cursor
* @returns
*/
update(): void;
updateRotatePoint(): void;
updateScalePoints(): void;
}
/**
* 使
*/
export declare class BoundsGraphic extends Graphics {
static Name: string;
static BoundsLineStyle: {
width: number;
color: string;
alpha: number;
};
obj: DisplayObject;
debouncedRedraw: DebouncedFunction<() => void>;
constructor(graphic: DisplayObject);
onObjTransformStart(): void;
onObjTransformEnd(): void;
onGraphicRepaint(): void;
destroy(options?: boolean | IDestroyOptions | undefined): void;
redraw(): void;
doRedraw(): void;
}

173
lib/plugins/InteractionPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,173 @@
/// <reference types="node" />
import { DisplayObject, FederatedMouseEvent, FederatedPointerEvent, Point } from 'pixi.js';
import { IGraphicScene } from '../app/JlGraphicApp';
import { JlGraphic } from '../core/JlGraphic';
export declare enum InteractionPluginType {
App = "app",
Graphic = "graphic",
Other = "other"
}
/**
*
*/
export interface InteractionPlugin {
readonly _type: string;
name: string;
app: IGraphicScene;
/**
*
*/
resume(): void;
/**
*
*/
pause(): void;
/**
*
*/
isActive(): boolean;
isAppPlugin(): boolean;
isOtherPlugin(): boolean;
isGraphicPlugin(): boolean;
}
export declare abstract class InteractionPluginBase implements InteractionPlugin {
readonly _type: string;
name: string;
app: IGraphicScene;
_pause: boolean;
constructor(app: IGraphicScene, name: string, type: string);
/**
*
*/
resume(): void;
/**
*
*/
pause(): void;
abstract bind(): void;
abstract unbind(): void;
/**
*
*/
isActive(): boolean;
isGraphicPlugin(): boolean;
isAppPlugin(): boolean;
isOtherPlugin(): boolean;
}
export declare abstract class OtherInteractionPlugin extends InteractionPluginBase {
constructor(app: IGraphicScene, name: string);
}
export declare class AppDragEvent {
app: IGraphicScene;
type: 'start' | 'move' | 'end';
target: DisplayObject;
original: FederatedPointerEvent;
start: Point;
constructor(app: IGraphicScene, type: 'start' | 'move' | 'end', target: DisplayObject, original: FederatedPointerEvent, start: Point);
get isMouse(): boolean;
get isLeftButton(): boolean;
get isRightButton(): boolean;
get isMiddleButton(): boolean;
get isTouch(): boolean;
/**
* ()
*/
get end(): Point;
get dx(): number;
get dy(): number;
get dsx(): number;
get dsy(): number;
/**
*
*/
toTargetShiftLen(target: DisplayObject): {
dx: number;
dy: number;
};
}
/**
*
*/
export declare class DragPlugin extends OtherInteractionPlugin {
static Name: string;
private threshold;
target: DisplayObject | null;
start: Point | null;
startClientPoint: Point | null;
drag: boolean;
constructor(app: IGraphicScene);
static new(app: IGraphicScene): DragPlugin;
bind(): void;
unbind(): void;
onPointerDown(e: FederatedPointerEvent): void;
onPointerMove(e: FederatedPointerEvent): void;
onPointerUp(e: FederatedPointerEvent): void;
/**
*
*/
clearCache(): void;
}
/**
*
*/
export declare class ViewportMovePlugin extends OtherInteractionPlugin {
static Name: string;
static MoveInterval: number;
static TriggerRange: number;
static DefaultMoveSpeed: number;
moveHandler: NodeJS.Timeout | null;
moveSpeedx: number;
moveSpeedy: number;
constructor(app: IGraphicScene);
static new(app: IGraphicScene): ViewportMovePlugin;
pause(): void;
bind(): void;
unbind(): void;
startMove(moveSpeedx: number, moveSpeedy: number): void;
stopMove(): void;
private calculateBoundaryMoveSpeed;
calculateMoveSpeed(dd: number): number;
viewportMove(e: FederatedMouseEvent): void;
}
/**
*
*/
export declare abstract class AppInteractionPlugin extends InteractionPluginBase {
constructor(name: string, app: IGraphicScene);
/**
* app交互插件同时只能生效一个
*/
resume(): void;
}
/**
* ,
*/
export declare abstract class GraphicInteractionPlugin<G extends JlGraphic> implements InteractionPlugin {
readonly _type = InteractionPluginType.Graphic;
app: IGraphicScene;
name: string;
_pause: boolean;
constructor(name: string, app: IGraphicScene);
isActive(): boolean;
isAppPlugin(): boolean;
isOtherPlugin(): boolean;
isGraphicPlugin(): boolean;
resume(): void;
pause(): void;
/**
*
*/
abstract filter(...grahpics: JlGraphic[]): G[] | undefined;
binds(list?: G[]): void;
unbinds(list?: G[]): void;
/**
*
* @param g
*/
abstract bind(g: G): void;
/**
*
* @param g
*/
abstract unbind(g: G): void;
}

81
lib/plugins/KeyboardPlugin.d.ts vendored Normal file
View File

@ -0,0 +1,81 @@
import { IGraphicApp } from '../app/JlGraphicApp';
export declare class GlobalKeyboardHelper {
appKeyboardPluginMap: JlGraphicAppKeyboardPlugin[];
constructor();
registerGAKPlugin(plugin: JlGraphicAppKeyboardPlugin): void;
removeGAKPlugin(plugin: JlGraphicAppKeyboardPlugin): void;
}
export declare class JlGraphicAppKeyboardPlugin {
app: IGraphicApp;
/**
* Map<key.code|key.key|key.keyCode, Map<KeyListener.identifier, KeyListener>>
*/
keyListenerMap: Map<number | string, Map<string, KeyListener>>;
keyListenerStackMap: Map<string, KeyListener[]>;
constructor(app: IGraphicApp);
private getOrInit;
private getOrInitStack;
/**
*
* @param keyListener
*/
addKeyListener(keyListener: KeyListener): void;
/**
*
* @param keyListener
*/
removeKeyListener(keyListener: KeyListener): void;
getKeyListenerBy(key: string | number): Map<string, KeyListener> | undefined;
getKeyListener(e: KeyboardEvent): Map<string, KeyListener> | undefined;
isKeyListened(key: string | number): boolean;
/**
*
*/
getAllListenedKeys(): string[];
}
type KeyboardKeyHandler = (e: KeyboardEvent, app: IGraphicApp) => void;
export declare enum CombinationKey {
Ctrl = "Ctrl",
Alt = "Alt",
Shift = "Shift"
}
export interface KeyListenerOptions {
value: string | number;
combinations?: CombinationKey[];
global?: boolean;
onPress?: KeyboardKeyHandler;
pressTriggerAsOriginalEvent?: boolean;
onRelease?: KeyboardKeyHandler;
}
export interface ICompleteKeyListenerOptions {
value: string | number;
combinations: CombinationKey[];
global: boolean;
onPress?: KeyboardKeyHandler;
pressTriggerAsOriginalEvent: boolean;
onRelease?: KeyboardKeyHandler;
}
export declare class KeyListener {
readonly options: ICompleteKeyListenerOptions;
private isPress;
constructor(options: KeyListenerOptions);
static create(options: KeyListenerOptions): KeyListener;
get value(): string | number;
get combinations(): string[];
get identifier(): string;
get global(): boolean | undefined;
get onPress(): KeyboardKeyHandler | undefined;
set onPress(v: KeyboardKeyHandler | undefined);
get onRelease(): KeyboardKeyHandler | undefined;
set onRelease(v: KeyboardKeyHandler | undefined);
get pressTriggerEveryTime(): boolean;
set pressTriggerEveryTime(v: boolean);
press(e: KeyboardEvent, app: IGraphicApp): void;
/**
*
*/
checkCombinations(e: KeyboardEvent): boolean;
release(e: KeyboardEvent, app: IGraphicApp): void;
onRemove(): void;
}
export {};

164
lib/ui/ContextMenu.d.ts vendored Normal file
View File

@ -0,0 +1,164 @@
/// <reference types="node" />
import { Container, Graphics, Point, Rectangle, Text } from 'pixi.js';
import { IGraphicScene } from '../app';
import { OutOfBound } from '../utils';
import { MenuCompletionItemStyle, MenuCompletionOptions, MenuCompletionStyleOptions, MenuGroupOptions, MenuItemOptions, MenuOptions } from './Menu';
export declare class ContextMenuPlugin {
app: IGraphicScene;
contextMenuMap: Map<string, ContextMenu>;
constructor(app: IGraphicScene);
registerMenu(menu: ContextMenu): void;
/**
*
*/
get screenWidth(): number;
/**
*
*/
get screenHeight(): number;
/**
*
* @param menu
* @param global
*/
open(menu: ContextMenu, global: Point): void;
/**
*
* @param menu
*/
close(menu: ContextMenu): void;
/**
*
*/
closeAll(): void;
/**
*
* @param menu
* @param global
* @returns
*/
oob(menu: ContextMenu, global: Point): OutOfBound;
}
/**
* ,
*/
export declare class ContextMenu extends Container {
_plugin?: ContextMenuPlugin;
parentMenuItem?: ContextMenuItem;
openedSubMenu?: ContextMenu;
menuOptions: MenuCompletionOptions;
opened: boolean;
bg: Graphics;
title?: Text;
groups: MenuGroup[];
private padding;
_active: boolean;
timeoutCloseHandle?: NodeJS.Timeout;
constructor(menuOptions: MenuOptions, parentMenuItem?: ContextMenuItem);
static init(options: MenuOptions): ContextMenu;
get style(): MenuCompletionStyleOptions;
/**
*
*/
get parentMenu(): ContextMenu | undefined;
/**
*
*/
get rootMenu(): ContextMenu;
/**
*
* @returns
*/
hasActiveItem(): boolean;
get active(): boolean;
set active(v: boolean);
onActiveChanged(): void;
setOptions(menuOptions: MenuOptions): void;
/**
*
*/
init(): void;
initGroups(): void;
initTitle(): void;
private calculateBorderInfo;
updateBg(): void;
update(): void;
get menuName(): string;
get plugin(): ContextMenuPlugin;
set plugin(v: ContextMenuPlugin);
/**
*
*/
open(global: Point): void;
/**
*
*/
close(): void;
/**
*
* @param subMenu
* @param global
*/
private openSub;
}
declare class MenuGroup extends Container {
private gutter;
config: MenuGroupOptions;
menu: ContextMenu;
items: ContextMenuItem[];
constructor(menu: ContextMenu, config: MenuGroupOptions);
private init;
hasActiveItem(): boolean;
get maxItemNameWidth(): number;
get maxShortcutWidth(): number;
get totalGutter(): number;
get totalHeight(): number;
update(): void;
updateItemBox(maxItemWidth: number): void;
}
/**
*
*/
declare class ContextMenuItem extends Container {
menu: ContextMenu;
config: MenuItemOptions;
/**
*
*/
nameText: Text;
/**
*
*/
shortcutKeyText?: Text;
private gutter;
arrowText?: Text;
box: Graphics;
subMenu?: ContextMenu;
_active: boolean;
constructor(menu: ContextMenu, config: MenuItemOptions);
registerEventHandler(): void;
get active(): boolean;
set active(v: boolean);
onActiveChanged(): void;
get textWidth(): number;
get nameGraphic(): Text;
get totalHeight(): number;
get nameBounds(): Rectangle;
get shortcutKeyBounds(): Rectangle;
get style(): MenuCompletionItemStyle;
private checkPadding;
private toWholePadding;
get paddingTop(): number;
get paddingBottom(): number;
get paddingLeft(): number;
get paddingRight(): number;
get hoverColor(): string;
get fontSize(): number;
get fontColor(): string;
initShortcutKeyText(): Text | undefined;
initSubMenu(): void;
updateBackground(width: number, height: number): void;
updateBox(width: number, height: number): void;
update(): void;
}
export {};

146
lib/ui/Menu.d.ts vendored Normal file
View File

@ -0,0 +1,146 @@
/**
*
*/
export interface MenuOptions {
/**
*
*/
name: string;
/**
*
*/
title?: string;
/**
*
*/
groups: MenuGroupOptions[];
/**
*
*/
style?: MenuStyleOptions;
}
/**
*
*/
export interface MenuGroupOptions {
/**
*
*/
name?: string;
/**
*
*/
items: MenuItemOptions[];
}
export interface MenuCompletionOptions extends MenuOptions {
style: MenuCompletionStyleOptions;
}
/**
*
*/
export interface MenuStyleOptions {
/**
*
*/
titleStyle?: MenuItemStyle;
/**
*
*/
backgroundColor?: string;
/**
* 线,1,0线
*/
borderWidth?: number;
/**
*
*/
borderColor?: string;
/**
* ,0
*/
borderRoundRadius?: number;
/**
*
*/
itemStyle?: MenuItemStyle;
}
export interface MenuCompletionStyleOptions extends MenuStyleOptions {
titleStyle: MenuItemStyle;
backgroundColor: string;
border: boolean;
borderWidth: number;
borderColor: string;
borderRoundRadius: number;
itemStyle: MenuCompletionItemStyle;
}
export interface MenuItemOptions {
/**
*
*/
name: string;
/**
* ,
*/
disabled?: boolean;
/**
* ,
*/
visible?: boolean;
/**
*
*/
shortcutKeys?: string[];
/**
*
*/
handler?: () => void;
fontColor?: string;
/**
*
*/
subMenu?: MenuOptions;
}
export interface MenuItemStyle {
/**
*
*/
fontSize: number;
/**
*
*/
fontColor?: string;
/**
* hover颜色
*/
hoverColor?: string;
/**
*
*/
disabledFontColor?: string;
/**
*
*/
padding: number[] | number;
}
export interface MenuCompletionItemStyle extends MenuItemStyle {
/**
*
*/
fontColor: string;
/**
*
*/
hoverColor: string;
/**
*
*/
disabledFontColor: string;
}
/**
*
*/
export declare const DefaultWhiteStyleOptions: MenuCompletionStyleOptions;
/**
*
*/
export declare const DefaultWhiteMenuOptions: MenuCompletionOptions;

232
lib/utils/GraphicUtils.d.ts vendored Normal file
View File

@ -0,0 +1,232 @@
import { Container, DisplayObject, IPointData, Point, Rectangle } from 'pixi.js';
/**
*
* @param obj
* @param handler
*/
export declare function recursiveParents(obj: DisplayObject, handler: (parent: Container) => void): void;
/**
*
* @param obj
* @param finder
* @returns
*/
export declare function recursiveFindParent(obj: DisplayObject, finder: (parent: Container) => boolean): Container | null;
/**
*
* @param container
* @param handler
*/
export declare function recursiveChildren(container: Container, handler: (child: DisplayObject) => void): void;
/**
*
*/
export declare function recursiveFindChild(container: Container, finder: (child: DisplayObject) => boolean): DisplayObject | null;
export interface BezierParam {
p1: IPointData;
p2: IPointData;
cp1: IPointData;
cp2: IPointData;
}
/**
* 线
* @param points
*/
export declare function assertBezierPoints(points: IPointData[]): void;
/**
* 线
* @param points
* @returns
*/
export declare function convertToBezierParams(points: IPointData[]): BezierParam[];
/**
* 线
* @param basePoints
* @param segmentsCount
* @returns
*/
export declare function calculateBezierPoints(basePoints: IPointData[], segmentsCount: number): Point[];
/**
* 线
* @param basePoints
* @param segmentsCount
* @returns
*/
export declare function calculateOneBezierPoints(p1: IPointData, p2: IPointData, cp1: IPointData, cp2: IPointData, segmentsCount: number): Point[];
/**
*
*/
export declare function getRectangleCenter(rectangle: Rectangle): Point;
/**
* , PS: 计算的是较大包围框的中心
* @param rect1
* @param rect2
* @returns
*/
export declare function getCenterOfTwoRectangle(rect1: Rectangle, rect2: Rectangle): Point;
/**
*
* @param obj
* @returns
*/
export declare function serializeTransform(obj: DisplayObject): number[];
/**
*
* @param obj
* @param transform
*/
export declare function deserializeTransformInto(obj: DisplayObject, transform: number[]): void;
/**
* 线
* @param p1
* @param p2
* @param thick
* @returns
*/
export declare function convertLineToPolygonPoints(p1: IPointData, p2: IPointData, thick: number): IPointData[];
/**
*
* @param rect
* @returns
*/
export declare function convertRectangleToPolygonPoints(rect: Rectangle): IPointData[];
/**
* 线
* @param p1
* @param p2
* @returns
*/
export declare function calculateLineMidpoint(p1: IPointData, p2: IPointData): Point;
/**
* 线--线
* @param p1
* @param p2
* @param knife
* @returns
*/
export declare function calculateLineSegmentingPoint(p1: IPointData, p2: IPointData, knife: number): IPointData[];
/**
* 线
* @param p1
* @param p2
* @param p
*/
export declare function calculateDistanceFromPointToLine(p1: IPointData, p2: IPointData, p: IPointData): number;
/**
* 线
* @param p
* @param p1
* @param p2
*/
export declare function calculateFootPointFromPointToLine(p1: IPointData, p2: IPointData, p: IPointData): Point;
/**
* 线
* 1线
* 2线
* 3线e
* 4(Intersection)projectPoint的长度(sideLength)
* 5sideLength和这侧端点到projectPoint距离的比例(ratio)
* 6projectPoint +/- ratio * e =
* @param p0
* @param radius
* @param p1 线1
* @param p2 线2
* @returns 2/1/0
*/
export declare function calculateIntersectionPointOfCircleAndLine(p0: IPointData, radius: number, p1: IPointData, p2: IPointData): Point[];
/**
*
* @param p0
* @param radius
* @param p
* @returns
*/
export declare function calculateIntersectionPointOfCircleAndPoint(p0: IPointData, radius: number, p: IPointData): Point;
/**
*
* @param bp
* @param p
* @param distance p到基准点的距离,
* @returns
*/
export declare function calculateMirrorPoint(bp: IPointData, p: IPointData, distance?: number): Point;
/**
*
* @param pa 线
* @param pb 线
* @param p
* @param distance
* @returns
*/
export declare function calculateMirrorPointBasedOnAxis(pa: IPointData, pb: IPointData, p: IPointData, distance?: number): Point;
/**
* 线,0
* @param p1
* @param p2
* @returns [0, 360)
*/
export declare function angleToAxisx(p1: IPointData, p2: IPointData): number;
/**
* 线,pc与pa,pb的夹角
* @param pa
* @param pb
* @param pc
* @returns , [-180, 180]
*/
export declare function angleOfIncludedAngle(pa: IPointData, pb: IPointData, pc: IPointData): number;
/**
* 线
* @param point1
* @param point2
* @returns
*/
export declare function getNormalVector(point1: IPointData, point2: IPointData): number[];
/**
*
* @param point
* @param normal
* @param length
* @returns
*/
export declare function movePointAlongNormal(point: IPointData, normal: number[], length: number): Point;
/**
* 线(线 )
* @param line1
* @param line2
* @returns
*/
export declare function getIntersectionPoint(line1: number[], line2: number[]): Point;
/**
* 线
* @param p1
* @param p2
* @param pa
* @param pb
* @returns
*/
export declare function isParallelLines(p1: IPointData, p2: IPointData, pa: IPointData, pb: IPointData): boolean;
/**
* 线
* @param p1
* @param p2
* @param p
* @returns
*/
export declare function isPointOnLine(p1: IPointData, p2: IPointData, p: IPointData): boolean;
/**
* 线
* @param line1
* @param line2
* @returns
*/
export declare function isLineContainOther(line1: {
p1: IPointData;
p2: IPointData;
}, line2: {
p1: IPointData;
p2: IPointData;
}): boolean;
/** 均分线段, 返回各线段端点 */
export declare function splitLineEvenly(p1: IPointData, p2: IPointData, count: number): IPointData[][];
export declare function splitPolyline(points: IPointData[], count: number): IPointData[][];
export declare function getParallelOfPolyline(points: IPointData[], offset: number, side: 'L' | 'R'): IPointData[];

119
lib/utils/IntersectUtils.d.ts vendored Normal file
View File

@ -0,0 +1,119 @@
import { IPointData, Rectangle } from 'pixi.js';
/**
* 线
* @param pa 线a端坐标
* @param pb 线b端坐标
* @param p
* @param lineWidth 线
* @param exact 使线线8
* @returns
*/
export declare function linePoint(pa: IPointData, pb: IPointData, p: IPointData, lineWidth: number, exact?: boolean): boolean;
/**
* 线
* @param points 线
* @param p
* @param lineWidth 线
*/
export declare function polylinePoint(points: IPointData[], p: IPointData, lineWidth: number): boolean;
/**
* 线线
* @param pa 线1a端坐标
* @param pb 线1b端坐标
* @param p1 线2a端坐标
* @param p2 线2b端坐标
* @returns
*/
export declare function lineLine(pa: IPointData, pb: IPointData, p1: IPointData, p2: IPointData): boolean;
/**
*
* @param p
* @param rect
* @returns
*/
export declare function pointBox(p: IPointData, rect: Rectangle): boolean;
/**
* 线
* @param pa 线a端坐标
* @param pb 线b端坐标
* @param rect
* @returns
*/
export declare function lineBox(pa: IPointData, pb: IPointData, rect: Rectangle): boolean;
/**
* 线
* @param points
* @param rect
* @returns false / 线
*/
export declare function polylineBox(points: IPointData[], rect: Rectangle): boolean;
/**
*
* @param p1
* @param p2
* @param tolerance
* @returns
*/
export declare function pointPoint2(p1: IPointData, p2: IPointData, tolerance: number): boolean;
/**
*
* @param x1
* @param y1
* @param x2
* @param y2
* @param tolerance /
* @returns
*/
export declare function pointPoint(x1: number, y1: number, x2: number, y2: number, tolerance: number): boolean;
/**
*
* @param x1
* @param y1
* @param x2
* @param y2
* @returns
*/
export declare function distance(x1: number, y1: number, x2: number, y2: number): number;
/**
*
* @param p1
* @param p2
* @returns
*/
export declare function distance2(p1: IPointData, p2: IPointData): number;
/**
*
* @param x1 x
* @param y1 y
* @param r1
* @param x2 x
* @param y2 y
* @returns
*/
export declare function circlePoint(x1: number, y1: number, r1: number, x2: number, y2: number): boolean;
/**
* --
*/
export declare function circlePoint2(x1: number, y1: number, r1: number, x2: number, y2: number, tolerance: number): boolean;
/**
*
*/
export declare function pointPolygon(p: IPointData, points: IPointData[], lineWidth: number): boolean;
/**
* 线
* @param p1
* @param p2
* @param points
* @param tolerance 线
* @returns
*/
export declare function linePolygon(p1: IPointData, p2: IPointData, points: IPointData[], lineWidth: number, polygonWidth: number): boolean;
/**
* 线
* @param polylinePoints 线
* @param polygonPoints
* @param polylineWidth 线线
* @param polygonWidth 线
* @returns
*/
export declare function polylinePolygon(polylinePoints: IPointData[], polygonPoints: IPointData[], polylineWidth: number, polygonWidth: number): boolean;

5
lib/utils/debounce.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
export interface DebouncedFunction<F extends (...args: any[]) => any> {
(context: ThisParameterType<F>, ...args: Parameters<F>): void;
cancel: () => void;
}
export declare function debounce<F extends (...args: Parameters<F>) => any>(fn: F, waitMs?: number): DebouncedFunction<F>;

26
lib/utils/index.d.ts vendored Normal file
View File

@ -0,0 +1,26 @@
import { Point, Rectangle } from 'pixi.js';
export * from './GraphicUtils';
export * from './IntersectUtils';
export * from './debounce';
export declare const UP: Point;
export declare const DOWN: Point;
export declare const LEFT: Point;
export declare const RIGHT: Point;
/**
*
*/
export declare class OutOfBound {
left: boolean;
top: boolean;
right: boolean;
bottom: boolean;
constructor(left: boolean, top: boolean, right: boolean, bottom: boolean);
static check(rect: Rectangle, bound: Rectangle): OutOfBound;
static none(): OutOfBound;
static leftOut(): OutOfBound;
static topOut(): OutOfBound;
static rightOut(): OutOfBound;
static bottomOut(): OutOfBound;
static leftTopOut(): OutOfBound;
static rightBottomOut(): OutOfBound;
}

View File

@ -6,7 +6,7 @@
"author": "walker <shengxuqiang@joylink.club>", "author": "walker <shengxuqiang@joylink.club>",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/jlgraphic", "main": "lib",
"scripts": { "scripts": {
"build": "rollup -c rollup.config.ts --configPlugin typescript" "build": "rollup -c rollup.config.ts --configPlugin typescript"
}, },

View File

@ -3,14 +3,21 @@ import typescript from '@rollup/plugin-typescript'
const config: RollupOptions = { const config: RollupOptions = {
input: 'src/jlgraphic/index.ts', input: 'src/index.ts',
output: { output: {
file: 'lib/index.js', dir: 'lib',
format: 'cjs', format: 'esm',
}, },
external: [
'pixi.js', 'pixi-viewport', '@stomp/stompjs', 'mqtt', 'eventemitter3'
],
logLevel: 'debug',
plugins: [ plugins: [
typescript({ typescript({
declaration: true,
declarationDir: 'lib',
include: ['src/**/*'],
tsconfig: './tsconfig.json',
}) })
], ],
} }

View File

@ -719,7 +719,6 @@ abstract class GraphicSceneBase
* @param options * @param options
*/ */
setOptions(options: GraphicAppOptions) { setOptions(options: GraphicAppOptions) {
// console.log('更新选项', options);
if (this._options) { if (this._options) {
this._options = Object.assign(this._options, options); this._options = Object.assign(this._options, options);
} else { } else {
@ -807,13 +806,6 @@ abstract class GraphicSceneBase
this.pixi.resizeTo = dom; this.pixi.resizeTo = dom;
dom.appendChild(this.pixi.view as unknown as Node); dom.appendChild(this.pixi.view as unknown as Node);
this._viewportResizer = setInterval(() => { this._viewportResizer = setInterval(() => {
// console.log(
// 'dom resize ',
// dom.style.width,
// dom.style.height,
// dom.clientWidth,
// dom.clientHeight
// );
this.updateViewport(dom.clientWidth, dom.clientHeight); this.updateViewport(dom.clientWidth, dom.clientHeight);
}, 1000); }, 1000);
// 恢复 // 恢复
@ -838,7 +830,6 @@ abstract class GraphicSceneBase
for (const item of this.graphicTemplateMap) { for (const item of this.graphicTemplateMap) {
await item[1].loadAssets(); await item[1].loadAssets();
} }
// console.log('开始加载proto数据', protos);
// 加载数据到图形存储 // 加载数据到图形存储
protos.forEach((proto) => { protos.forEach((proto) => {
const template = this.getGraphicTemplatesByType(proto.graphicType); const template = this.getGraphicTemplatesByType(proto.graphicType);
@ -855,7 +846,6 @@ abstract class GraphicSceneBase
.map((g) => g.id) .map((g) => g.id)
.sort((a, b) => a - b) .sort((a, b) => a - b)
.pop() ?? 0; .pop() ?? 0;
// console.log('最大值', max)
GraphicIdGenerator.initSerial(max); GraphicIdGenerator.initSerial(max);
// 数据加载完成后 // 数据加载完成后
this.emit('postdataloaded'); this.emit('postdataloaded');
@ -900,11 +890,9 @@ abstract class GraphicSceneBase
} }
if (graphic.eventMode == 'static' || graphic.eventMode == 'dynamic') { if (graphic.eventMode == 'static' || graphic.eventMode == 'dynamic') {
// 添加为可交互 // 添加为可交互
// console.log(`type=${graphic.type}的图形添加到交互容器`);
this.canvas.addChild(graphic); this.canvas.addChild(graphic);
} else { } else {
// 添加到不可交互容器 // 添加到不可交互容器
// console.log(`type=${graphic.type}的图形添加到无交互容器`);
this.canvas.addNonInteractiveChild(graphic); this.canvas.addNonInteractiveChild(graphic);
} }
graphic.repaint(); graphic.repaint();
@ -1253,7 +1241,6 @@ export class GraphicApp extends GraphicSceneBase implements IGraphicApp {
constructor(options: GraphicAppOptions) { constructor(options: GraphicAppOptions) {
super(options); super(options);
// console.log('创建图形App')
this.opRecord = new OperationRecord(); this.opRecord = new OperationRecord();
// 绑定键盘监听 // 绑定键盘监听
this.keyboardPlugin = new JlGraphicAppKeyboardPlugin(this); this.keyboardPlugin = new JlGraphicAppKeyboardPlugin(this);
@ -1264,7 +1251,6 @@ export class GraphicApp extends GraphicSceneBase implements IGraphicApp {
} }
setOptions(options: GraphicAppOptions) { setOptions(options: GraphicAppOptions) {
// console.log('更新选项', options);
if (options.maxOperationRecords && options.maxOperationRecords > 0) { if (options.maxOperationRecords && options.maxOperationRecords > 0) {
this.opRecord.setMaxLen(options.maxOperationRecords); this.opRecord.setMaxLen(options.maxOperationRecords);
} }

View File

@ -20,7 +20,6 @@ export class IdGenerator {
} }
initSerial(serial: number): void { initSerial(serial: number): void {
// console.log(serial)
this.serial = serial; this.serial = serial;
} }
} }

4
src/core/index.ts Normal file
View File

@ -0,0 +1,4 @@
export * from './JlGraphic';
export * from './IdGenerator';
export * from './GraphicRelation';
export * from './GraphicStore';

5
src/graphic/index.ts Normal file
View File

@ -0,0 +1,5 @@
export * from './VectorGraphic';
export * from './VectorText';
export * from './DraggablePoint';
export * from './AbsorbablePosition';
export * from './DashedLine';

View File

@ -1,51 +0,0 @@
import { Graphics } from 'pixi.js';
export function drawArrow(
polygon: Graphics,
x: number,
y: number,
length: number,
radius: number,
lineWidth: number
) {
const trianglAcme = { x, y };
const triangleP1 = {
x: x - radius - Math.sin(Math.PI / 6),
y: y + Math.cos(Math.PI / 6) * radius,
};
const triangleP2 = {
x: x - radius - Math.sin(Math.PI / 6),
y: y - Math.cos(Math.PI / 6) * radius,
};
const lineP1 = {
x: x - radius - Math.sin(Math.PI / 6),
y: y + lineWidth / 2,
};
const lineP2 = {
x: x - length,
y: y + lineWidth / 2,
};
const lineP3 = {
x: x - length,
y: y - lineWidth / 2,
};
const lineP4 = {
x: x - radius - Math.sin(Math.PI / 6),
y: y - lineWidth / 2,
};
polygon.drawPolygon(
trianglAcme.x,
trianglAcme.y,
triangleP1.x,
triangleP1.y,
lineP1.x,
lineP1.y,
lineP2.x,
lineP2.y,
lineP3.x,
lineP3.y,
lineP4.x,
lineP4.y,
triangleP2.x,
triangleP2.y
);
}

View File

@ -1,139 +0,0 @@
import {
GraphicAnimation,
GraphicData,
GraphicState,
JlGraphic,
JlGraphicTemplate,
} from 'src/jlgraphic';
import ISCS_FAN_Assets from './iscs-fan-spritesheet.png';
import ISCS_FAN_JSON from './iscs-fan-data.json';
import { Assets, Sprite, Spritesheet, 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 interface IIscsFanState extends GraphicState {
get state(): number;
set state(v: number);
}
export class IscsFan extends JlGraphic {
static Type = 'IscsFan';
_border: Sprite;
_fan: Sprite;
fanTextures: FanTextures;
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);
}
get states(): IIscsFanState {
return this.getStates<IIscsFanState>();
}
doRepaint(): void {
if (this.states.state === 0) {
// 停止
this.stopFanRun();
this._fan.rotation = 0;
this._fan.texture = this.fanTextures.gray;
} else if (this.states.state === 1) {
// 正常运行
this._fan.texture = this.fanTextures.green;
// 动画
this.initFanRun();
} else if (this.states.state === 2) {
// 报警运行
this._fan.texture = this.fanTextures.yellow;
// 动画
this.initFanRun();
} else if (this.states.state === 3) {
// 故障
this.stopFanRun();
this._fan.rotation = 0;
this._fan.texture = this.fanTextures.red;
} else if (this.states.state === 4) {
// 通信故障
// 停止
this.stopFanRun();
this._fan.rotation = 0;
this._fan.texture = this.fanTextures.blue;
}
}
initFanRun() {
// 动画
const name = 'fan_run';
let fanRun = this.animation(name);
if (!fanRun) {
fanRun = GraphicAnimation.init({
name: 'fan_run',
run: (dt: number) => {
this._fan.angle = (this._fan.angle + dt) % 360;
},
});
this.addAnimation(fanRun);
}
const speed = Math.round(Math.random() * 10) + 1;
fanRun.xSpeed = speed;
fanRun.resume();
}
stopFanRun() {
const name = 'fan_run';
const fanRun = this.animation(name);
if (fanRun) {
fanRun.pause();
}
}
}
export class IscsFanTemplate extends JlGraphicTemplate<IscsFan> {
fanTextures?: FanTextures;
constructor(dataTemplate: IIscsFanData, stateTemplate: IIscsFanState) {
super(IscsFan.Type, {
dataTemplate,
stateTemplate,
});
}
new(): IscsFan {
if (this.fanTextures) {
const g = new IscsFan(this.fanTextures);
g.loadData(this.datas);
g.loadState(this.states);
return g;
}
throw new Error('资源未加载/加载失败');
}
async loadAssets(): Promise<FanTextures> {
const texture = await Assets.load(ISCS_FAN_Assets);
const iscsFanSheet = new Spritesheet(texture, ISCS_FAN_JSON);
const result = await iscsFanSheet.parse();
this.fanTextures = {
border: result['fan-border.png'],
blue: result['fan-blue.png'],
gray: result['fan-gray.png'],
green: result['fan-green.png'],
red: result['fan-red.png'],
yellow: result['fan-yellow.png'],
};
return this.fanTextures as FanTextures;
}
}

View File

@ -1,109 +0,0 @@
import { FederatedMouseEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
JlDrawApp,
JlGraphic,
} from 'src/jlgraphic';
import { IIscsFanData, IscsFan, IscsFanTemplate } from './IscsFan';
export class IscsFanDraw extends GraphicDrawAssistant<
IscsFanTemplate,
IIscsFanData
> {
_iscsFan: IscsFan | null = null;
constructor(app: JlDrawApp, template: IscsFanTemplate) {
super(app, template, IscsFan.Type, '风机');
IscsFanInteraction.init(app);
}
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);
}
prepareData(data: IIscsFanData): boolean {
data.transform = this.iscsFan.saveTransform();
return true;
}
onEsc(): void {
this.finish();
}
}
export class IscsFanInteraction extends GraphicInteractionPlugin<IscsFan> {
static Name = 'iscs_fan_transform';
constructor(app: JlDrawApp) {
super(IscsFanInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new IscsFanInteraction(app);
}
filter(...grahpics: JlGraphic[]): IscsFan[] | undefined {
return grahpics
.filter((g) => g.type === IscsFan.Type)
.map((g) => g as IscsFan);
}
bind(g: IscsFan): void {
g.eventMode = 'static';
g.cursor = 'pointer';
// g.scalable = true;
g.rotatable = true;
g.on('drag-start', () => {
console.log('风机拖拽');
});
g.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
g.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(g),
});
}
});
}
unbind(g: IscsFan): void {
g.eventMode = 'none';
// g.scalable = false;
g.rotatable = false;
}
}
function buildAbsorbablePositions(
g: IscsFan
): AbsorbablePosition[] | undefined {
const app = g.getGraphicApp();
const canvas = app.canvas;
const store = app.queryStore;
const aps: AbsorbablePosition[] = [];
store.queryByType(IscsFan.Type).forEach((fan) => {
if (fan.id === g.id) return;
const p = fan.position;
aps.push(
new AbsorbableLine(new Point(0, p.y), new Point(canvas.width, p.y))
);
aps.push(
new AbsorbableLine(new Point(p.x, 0), new Point(p.x, canvas.height))
);
});
return aps;
}

View File

@ -1,66 +0,0 @@
{"frames": {
"fan-blue.png":
{
"frame": {"x":0,"y":0,"w":41,"h":41},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":41,"h":41},
"sourceSize": {"w":41,"h":41},
"anchor": {"x":0.5,"y":0.5}
},
"fan-border.png":
{
"frame": {"x":41,"y":0,"w":41,"h":41},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":41,"h":41},
"sourceSize": {"w":41,"h":41},
"anchor": {"x":0.5,"y":0.5}
},
"fan-gray.png":
{
"frame": {"x":82,"y":0,"w":41,"h":41},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":41,"h":41},
"sourceSize": {"w":41,"h":41},
"anchor": {"x":0.5,"y":0.5}
},
"fan-green.png":
{
"frame": {"x":123,"y":0,"w":41,"h":41},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":41,"h":41},
"sourceSize": {"w":41,"h":41},
"anchor": {"x":0.5,"y":0.5}
},
"fan-red.png":
{
"frame": {"x":164,"y":0,"w":41,"h":41},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":41,"h":41},
"sourceSize": {"w":41,"h":41},
"anchor": {"x":0.5,"y":0.5}
},
"fan-yellow.png":
{
"frame": {"x":205,"y":0,"w":41,"h":41},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":41,"h":41},
"sourceSize": {"w":41,"h":41},
"anchor": {"x":0.5,"y":0.5}
}},
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "1.1",
"image": "test-iscs-fan.png",
"format": "RGBA8888",
"size": {"w":246,"h":41},
"scale": "1",
"smartupdate": "$TexturePacker:SmartUpdate:e7620bd2d73cc0b3e2deea9704e7eefc:f129a1d9e4b9ba57720b3861c22b155b:eb2d421f7759984b7713aa4aa5354134$"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,104 +0,0 @@
import { Color, Graphics, IPointData } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
convertToBezierParams,
} from 'src/jlgraphic';
import { ILineGraphic } from 'src/jlgraphic/plugins/GraphicEditPlugin';
export interface ILinkData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get curve(): boolean; // 是否曲线
set curve(v: boolean);
get segmentsCount(): number; // 曲线分段数
set segmentsCount(v: number);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
get lineWidth(): number; // 线宽
set lineWidth(v: number);
get lineColor(): string; // 线色
set lineColor(v: string);
clone(): ILinkData;
copyFrom(data: ILinkData): void;
eq(other: ILinkData): boolean;
}
export class Link extends JlGraphic implements ILineGraphic {
static Type = 'Link';
lineGraphic: Graphics;
constructor() {
super(Link.Type);
this.lineGraphic = new Graphics();
this.addChild(this.lineGraphic);
}
get datas(): ILinkData {
return this.getDatas<ILinkData>();
}
doRepaint(): void {
if (this.datas.points.length < 2) {
throw new Error('Link坐标数据异常');
}
this.lineGraphic.clear();
this.lineGraphic.lineStyle(
this.datas.lineWidth,
new Color(this.datas.lineColor)
);
if (this.datas.curve) {
// 曲线
const bps = convertToBezierParams(this.datas.points);
bps.forEach((bp) => {
this.lineGraphic.drawBezierCurve(
bp.p1,
bp.p2,
bp.cp1,
bp.cp2,
this.datas.segmentsCount
);
});
} else {
// 直线
const start = this.getStartPoint();
this.lineGraphic.moveTo(start.x, start.y);
for (let i = 0; i < this.datas.points.length; i++) {
const p = this.datas.points[i];
this.lineGraphic.lineTo(p.x, p.y);
}
}
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
getStartPoint(): IPointData {
return this.datas.points[0];
}
getEndPoint(): IPointData {
return this.datas.points[this.datas.points.length - 1];
}
}
export class LinkTemplate extends JlGraphicTemplate<Link> {
curve: boolean;
lineWidth: number;
lineColor: string;
segmentsCount: number;
constructor(dataTemplate: ILinkData) {
super(Link.Type, {
dataTemplate,
});
this.lineWidth = 2;
this.lineColor = '#000000';
this.curve = false;
this.segmentsCount = 10;
}
new(): Link {
return new Link();
}
}

View File

@ -1,451 +0,0 @@
import {
Color,
DisplayObject,
FederatedMouseEvent,
FederatedPointerEvent,
Graphics,
IHitArea,
Point,
} from 'pixi.js';
import {
AbsorbablePosition,
DraggablePoint,
IGraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
IDrawApp,
JlGraphic,
KeyListener,
calculateMirrorPoint,
convertToBezierParams,
linePoint,
pointPolygon,
} from 'src/jlgraphic';
import AbsorbablePoint, {
AbsorbableCircle,
} from 'src/jlgraphic/graphic/AbsorbablePosition';
import {
BezierCurveEditPlugin,
ILineGraphic,
PolylineEditPlugin,
addWayPoint,
clearWayPoint,
getWaypointRangeIndex,
removeBezierWayPoint,
removeLineWayPoint,
} from 'src/jlgraphic/plugins/GraphicEditPlugin';
import { ContextMenu } from 'src/jlgraphic/ui/ContextMenu';
import { MenuItemOptions, MenuOptions } from 'src/jlgraphic/ui/Menu';
import { ILinkData, Link, LinkTemplate } from './Link';
export interface ILinkDrawOptions {
newData: () => ILinkData;
}
export class LinkDraw extends GraphicDrawAssistant<LinkTemplate, ILinkData> {
points: Point[] = [];
graphic: Graphics = new Graphics();
// 快捷切曲线绘制
keyqListener: KeyListener = new KeyListener({
value: 'KeyQ',
global: true,
onPress: () => {
if (this.points.length == 0) {
this.graphicTemplate.curve = true;
}
},
});
// 快捷切直线绘制
keyzListener: KeyListener = new KeyListener({
value: 'KeyZ',
global: true,
onPress: () => {
if (this.points.length == 0) {
this.graphicTemplate.curve = false;
}
},
});
constructor(app: IDrawApp, template: LinkTemplate) {
super(app, template, Link.Type, '轨道Link');
this.container.addChild(this.graphic);
this.graphicTemplate.curve = true;
LinkPointsEditPlugin.init(app);
}
bind(): void {
super.bind();
this.app.addKeyboardListener(this.keyqListener, this.keyzListener);
}
unbind(): void {
super.unbind();
this.app.removeKeyboardListener(this.keyqListener, this.keyzListener);
}
clearCache(): void {
this.points = [];
this.graphic.clear();
}
onRightClick(): void {
this.createAndStore(true);
}
onLeftDown(e: FederatedPointerEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
if (this.graphicTemplate.curve) {
if (this.points.length == 0) {
this.points.push(p);
} else {
this.points.push(p, p.clone());
}
} else {
this.points.push(p);
}
}
onLeftUp(e: FederatedMouseEvent): void {
const template = this.graphicTemplate;
if (template.curve) {
const mp = this.toCanvasCoordinates(e.global);
if (this.points.length == 1) {
this.points.push(new Point(mp.x, mp.y));
} else if (this.points.length > 1) {
const cp2 = this.points[this.points.length - 2];
const p = this.points[this.points.length - 1];
cp2.copyFrom(calculateMirrorPoint(p, mp));
this.points.push(mp);
}
}
}
redraw(p: Point): void {
if (this.points.length < 1) return;
this.graphic.clear();
const template = this.graphicTemplate;
this.graphic.lineStyle(template.lineWidth, new Color(template.lineColor));
const ps = [...this.points];
if (template.curve) {
// 曲线
if (ps.length == 1) {
this.graphic.moveTo(ps[0].x, ps[0].y);
this.graphic.lineTo(p.x, p.y);
} else {
if ((ps.length + 1) % 3 == 0) {
ps.push(p.clone(), p.clone());
} else {
const cp = ps[ps.length - 2];
const p1 = ps[ps.length - 1];
const mp = calculateMirrorPoint(p1, p);
cp.copyFrom(mp);
}
const bps = convertToBezierParams(ps);
bps.forEach((bp) =>
this.graphic.drawBezierCurve(
bp.p1,
bp.p2,
bp.cp1,
bp.cp2,
template.segmentsCount
)
);
}
} else {
ps.push(p);
// 直线
this.graphic.moveTo(ps[0].x, ps[0].y);
for (let i = 1; i < ps.length; i++) {
const p = ps[i];
this.graphic.lineTo(p.x, p.y);
}
}
}
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 false;
}
if (template.curve) {
this.points.pop();
}
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 true;
}
}
export class LinkGraphicHitArea implements IHitArea {
link: Link;
constructor(link: Link) {
this.link = link;
}
contains(x: number, y: number): boolean {
const p = new Point(x, y);
if (this.link.datas.curve) {
// 曲线
const bps = convertToBezierParams(this.link.datas.points);
for (let i = 0; i < bps.length; i++) {
const bp = bps[i];
if (
pointPolygon(
p,
[bp.p1, bp.cp1, bp.cp2, bp.p2],
this.link.datas.lineWidth
)
) {
return true;
}
}
} else {
// 直线
for (let i = 1; i < this.link.datas.points.length; i++) {
const p1 = this.link.datas.points[i - 1];
const p2 = this.link.datas.points[i];
if (linePoint(p1, p2, p, this.link.datas.lineWidth)) {
return true;
}
}
}
return false;
}
}
/**
*
* @param link
* @returns
*/
function buildAbsorbablePositions(link: Link): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const links = link.queryStore.queryByType<Link>(Link.Type);
links.forEach((other) => {
if (other.id == link.id) {
return;
}
const apa = new AbsorbablePoint(
other.localToCanvasPoint(other.getStartPoint())
);
const apb = new AbsorbablePoint(
other.localToCanvasPoint(other.getEndPoint())
);
aps.push(apa, apb);
});
aps.push(new AbsorbableCircle(new Point(450, 410), 30));
return aps;
}
/**
*
* @param g
* @param dp
* @param index
*/
function onPolylineEditPointCreate(
g: ILineGraphic,
dp: DraggablePoint,
index: number
): void {
const link = g as Link;
if (index === 0 || index == link.datas.points.length - 1) {
// 端点
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
link.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(link),
});
}
});
}
dp.on('rightclick', (e: FederatedMouseEvent) => {
// dp.getGraphicApp().openContextMenu(EditPointContextMenu.DefaultMenu);
// 路径中的点
const app = dp.getGraphicApp();
app.registerMenu(EditPointContextMenu);
removeWaypointConfig.handler = () => {
removeLineWayPoint(link, index);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(link, false);
};
EditPointContextMenu.open(e.global);
});
}
function onCurveEditPointCreate(
g: ILineGraphic,
dp: DraggablePoint,
index: number
): void {
const link = g as Link;
if (index === 0 || index == link.datas.points.length - 1) {
// 端点
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
link.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(link),
});
}
});
}
const c = index % 3;
dp.on('rightclick', (e: FederatedMouseEvent) => {
// dp.getGraphicApp().openContextMenu(EditPointContextMenu.DefaultMenu);
if (c === 0) {
// 路径中的点
const app = dp.getGraphicApp();
app.registerMenu(EditPointContextMenu);
removeWaypointConfig.handler = () => {
removeBezierWayPoint(link, index);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(link, true);
};
EditPointContextMenu.open(e.global);
}
});
}
export const addWaypointConfig: MenuItemOptions = {
name: '添加路径点',
};
export const addWaySegmentingConfig: MenuItemOptions = {
name: '细分',
};
export const removeWaypointConfig: MenuItemOptions = {
name: '移除路径点',
};
export const clearWaypointsConfig: MenuItemOptions = {
name: '清除所有路径点',
};
const menuOptions: MenuOptions = {
name: '图形编辑点菜单',
groups: [
{
items: [removeWaypointConfig, clearWaypointsConfig],
},
],
};
const EditPointContextMenu = ContextMenu.init(menuOptions);
const LinkEditMenu: ContextMenu = ContextMenu.init({
name: '轨道编辑菜单',
groups: [
{
items: [addWaypointConfig, clearWaypointsConfig],
},
],
});
/**
* link路径编辑
*/
export class LinkPointsEditPlugin extends GraphicInteractionPlugin<Link> {
static Name = 'LinkPointsDrag';
constructor(app: IGraphicApp) {
super(LinkPointsEditPlugin.Name, app);
app.registerMenu(LinkEditMenu);
}
static init(app: IGraphicApp): LinkPointsEditPlugin {
return new LinkPointsEditPlugin(app);
}
filter(...grahpics: JlGraphic[]): Link[] | undefined {
return grahpics.filter((g) => g.type == Link.Type) as Link[];
}
bind(g: Link): void {
g.lineGraphic.eventMode = 'static';
g.lineGraphic.cursor = 'pointer';
g.lineGraphic.hitArea = new LinkGraphicHitArea(g);
g.on('_rightclick', this.onContextMenu, this);
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
}
unbind(g: Link): void {
g.off('_rightclick', this.onContextMenu, this);
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const link = target.getGraphic() as Link;
this.app.updateSelected(link);
const p = link.getGraphicApp().toCanvasCoordinates(e.global);
console.log('右键坐标', p);
addWaypointConfig.handler = () => {
const linePoints = link.linePoints;
console.log('添加路径点', linePoints, p);
const { start, end } = getWaypointRangeIndex(
linePoints,
link.datas.curve,
p,
link.datas.lineWidth
);
addWayPoint(link, link.datas.curve, start, end, p);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(link, link.datas.curve);
};
LinkEditMenu.open(e.global);
}
onSelected(g: DisplayObject): void {
const link = g as Link;
let lep;
if (link.datas.curve) {
// 曲线
lep = link.getAssistantAppend<BezierCurveEditPlugin>(
BezierCurveEditPlugin.Name
);
if (!lep) {
lep = new BezierCurveEditPlugin(link, {
onEditPointCreate: onCurveEditPointCreate,
});
link.addAssistantAppend(lep);
}
} else {
// 直线
lep = link.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (!lep) {
lep = new PolylineEditPlugin(link, {
onEditPointCreate: onPolylineEditPointCreate,
});
link.addAssistantAppend(lep);
}
}
lep.showAll();
}
onUnselected(g: DisplayObject): void {
const link = g as Link;
let lep;
if (link.datas.curve) {
// 曲线
lep = link.getAssistantAppend<BezierCurveEditPlugin>(
BezierCurveEditPlugin.Name
);
} else {
// 直线
lep = link.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
}
if (lep) {
lep.hideAll();
}
}
}

View File

@ -1,203 +0,0 @@
import { Color, Graphics, IPointData, Rectangle } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
getRectangleCenter,
} from 'src/jlgraphic';
export interface IPlatformData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get hasdoor(): boolean; // 是否有屏蔽门
set hasdoor(v: boolean);
get trainDirection(): string; // 行驶方向--屏蔽门上下
set trainDirection(v: string);
get lineWidth(): number; // 线宽
set lineWidth(v: number);
get lineColor(): string; // 站台线色
set lineColor(v: string);
get lineColorDoor(): string; // 屏蔽门线色
set lineColorDoor(v: string);
get point(): IPointData; // 位置坐标
set point(point: IPointData);
get width(): number; // 宽度
set width(v: number);
get height(): number; // 高度
set height(v: number);
clone(): IPlatformData;
copyFrom(data: IPlatformData): void;
eq(other: IPlatformData): boolean;
}
//站台颜色
export enum PlatformColorEnum {
blue = '0x0fe81f', //站台的颜色
lightBlue = '0x55d15d',
yellow = '0xfbff00',
white = '0xffffff',
lozengeRed = '0xff0000', //站台旁的菱形图标
whiteNumbers = '0xffffff', //站台旁白色数字
HCharYellow = '0xfbff00', //站台旁的H字符
HCharWhite = '0xffffff',
HCharRed = '0xff0000',
doorBlue = '0x008000', //屏蔽门的颜色
doorRed = '0xff0000',
}
const platformConsts = {
width: 60,
height: 20,
lineWidth: 3,
besideFontSize: 12,
doorOpenSpacing: 5,
doorPlatformSpacing: 10,
besideSpacing: 10,
};
export class Platform extends JlGraphic {
static Type = 'Platform';
platformGraphic: Graphics;
doorGraphic: Graphics;
doorCloseGraphic: Graphics;
besideGraphic: Graphics;
codeGraph: VectorText = new VectorText(''); //站台旁数字、字符
constructor() {
super(Platform.Type);
this.platformGraphic = new Graphics();
this.doorGraphic = new Graphics();
this.doorCloseGraphic = new Graphics();
this.besideGraphic = new Graphics();
this.addChild(this.platformGraphic);
this.addChild(this.doorGraphic);
this.addChild(this.doorCloseGraphic);
this.addChild(this.besideGraphic);
this.addChild(this.codeGraph);
this.codeGraph.setVectorFontSize(platformConsts.besideFontSize);
}
get datas(): IPlatformData {
return this.getDatas<IPlatformData>();
}
doRepaint(): void {
const width = this.datas.width;
const height = this.datas.height;
//屏蔽门
const doorGraphic = this.doorGraphic;
const doorCloseGraphic = this.doorCloseGraphic;
doorGraphic.clear();
doorCloseGraphic.clear();
if (this.datas.hasdoor) {
doorGraphic.lineStyle(
this.datas.lineWidth,
new Color(this.datas.lineColorDoor)
);
doorGraphic.moveTo(-width / 2 - this.datas.lineWidth / 2, 0);
doorGraphic.lineTo(-platformConsts.doorOpenSpacing, 0);
doorGraphic.moveTo(platformConsts.doorOpenSpacing, 0);
doorGraphic.lineTo(width / 2 + this.datas.lineWidth / 2, 0);
//屏蔽门闭合
doorCloseGraphic.lineStyle(
this.datas.lineWidth,
new Color(this.datas.lineColorDoor)
);
doorCloseGraphic.moveTo(-platformConsts.doorOpenSpacing, 0);
doorCloseGraphic.lineTo(platformConsts.doorOpenSpacing, 0);
doorGraphic.position.set(
0,
-height / 2 - platformConsts.doorPlatformSpacing
);
doorCloseGraphic.position.set(
0,
-height / 2 - platformConsts.doorPlatformSpacing
);
}
//站台
const platformGraphic = this.platformGraphic;
platformGraphic.clear();
platformGraphic.lineStyle(
this.datas.lineWidth,
new Color(this.datas.lineColor)
);
platformGraphic.beginFill(this.datas.lineColor, 1);
platformGraphic.drawRect(0, 0, this.datas.width, this.datas.height);
platformGraphic.endFill;
const rectP = new Rectangle(0, 0, this.datas.width, this.datas.height);
platformGraphic.pivot = getRectangleCenter(rectP);
this.position.set(this.datas.point.x, this.datas.point.y);
//站台旁菱形图标
const besideGraphic = this.besideGraphic;
besideGraphic.clear();
besideGraphic.lineStyle(1, new Color(PlatformColorEnum.lozengeRed));
besideGraphic.drawRect(0, 0, this.datas.height / 4, this.datas.height / 4);
const rect = new Rectangle(
0,
0,
this.datas.height / 4,
this.datas.height / 4
);
besideGraphic.pivot = getRectangleCenter(rect);
besideGraphic.rotation = Math.PI / 4;
besideGraphic.position.set(
-width / 2 - this.datas.lineWidth / 2 - platformConsts.besideSpacing,
0
);
//站台旁的数字、字符
const codeGraph = this.codeGraph;
codeGraph.text = 'H';
codeGraph.anchor.set(0.5);
codeGraph.position.set(
-width / 2 - this.datas.lineWidth / 2 - platformConsts.besideSpacing,
0
);
codeGraph.style.fill = PlatformColorEnum.HCharYellow;
//站台方向
if (this.datas.trainDirection == 'right') {
doorGraphic.position.set(
0,
height / 2 + platformConsts.doorPlatformSpacing
);
doorCloseGraphic.position.set(
0,
height / 2 + platformConsts.doorPlatformSpacing
);
besideGraphic.position.set(
width / 2 + this.datas.lineWidth / 2 + platformConsts.besideSpacing,
0
);
codeGraph.position.set(
width / 2 + this.datas.lineWidth / 2 + platformConsts.besideSpacing,
0
);
}
//子元素显隐
doorCloseGraphic.visible = false;
/* besideGraphic.visible = false;
codeGraph.visible = false; */
}
}
export class PlatformTemplate extends JlGraphicTemplate<Platform> {
hasdoor: boolean;
trainDirection: string;
lineWidth: number;
lineColor: string;
lineColorDoor: string;
width: number;
height: number;
constructor() {
super(Platform.Type, {});
this.hasdoor = true;
this.trainDirection = 'left';
this.lineWidth = platformConsts.lineWidth;
this.lineColor = PlatformColorEnum.yellow;
this.lineColorDoor = PlatformColorEnum.doorBlue;
this.width = platformConsts.width;
this.height = platformConsts.height;
}
new(): Platform {
return new Platform();
}
}

View File

@ -1,123 +0,0 @@
import {
Color,
FederatedPointerEvent,
Graphics,
Point,
Rectangle,
} from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicInteractionPlugin,
IDrawApp,
JlGraphic,
getRectangleCenter,
} from 'src/jlgraphic';
import { IPlatformData, Platform, PlatformTemplate } from './Platform';
export interface IPlatformDrawOptions {
newData: () => IPlatformData;
}
export class PlatformDraw extends GraphicDrawAssistant<
PlatformTemplate,
IPlatformData
> {
point: Point = new Point(0, 0);
platformGraphic: Graphics = new Graphics();
doorGraphic: Graphics = new Graphics();
constructor(app: IDrawApp, createData: () => IPlatformData) {
super(app, new PlatformTemplate(), '', '站台Platform');
this.container.addChild(this.platformGraphic);
this.container.addChild(this.doorGraphic);
this.graphicTemplate.hasdoor = true;
platformInteraction.init(app);
}
bind(): void {
super.bind();
}
unbind(): void {
super.unbind();
}
clearCache(): void {
this.platformGraphic.clear();
this.doorGraphic.clear();
}
onLeftDown(e: FederatedPointerEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
this.point = p;
this.createAndStore(true);
}
redraw(p: Point): void {
const template = this.graphicTemplate;
//屏蔽门
if (template.hasdoor) {
const doorGraphic = this.doorGraphic;
doorGraphic.clear();
doorGraphic.lineStyle(
template.lineWidth,
new Color(template.lineColorDoor)
);
const width = template.width;
const height = template.height;
doorGraphic.moveTo(-width / 2 - template.lineWidth / 2, -height / 2 - 10);
doorGraphic.lineTo(width / 2 + template.lineWidth / 2, -height / 2 - 10);
doorGraphic.position.set(p.x, p.y);
}
//站台
const platformGraphic = this.platformGraphic;
platformGraphic.clear();
this.point.set(p.x, p.y);
const rect = new Rectangle(0, 0, template.width, template.height);
platformGraphic.pivot = getRectangleCenter(rect);
platformGraphic.lineStyle(template.lineWidth, template.lineColor);
platformGraphic.beginFill(template.lineColor, 1);
platformGraphic.drawRect(0, 0, template.width, template.height);
platformGraphic.endFill;
platformGraphic.position.set(this.point.x, this.point.y);
}
prepareData(data: IPlatformData): boolean {
const template = this.graphicTemplate;
data.hasdoor = template.hasdoor;
data.trainDirection = template.trainDirection;
data.point = this.point;
data.lineWidth = template.lineWidth;
data.lineColor = template.lineColor;
data.lineColorDoor = template.lineColorDoor;
data.width = template.width;
data.height = template.height;
return true;
}
}
export class platformInteraction extends GraphicInteractionPlugin<Platform> {
static Name = 'platform_transform';
constructor(app: IDrawApp) {
super(platformInteraction.Name, app);
}
static init(app: IDrawApp) {
return new platformInteraction(app);
}
filter(...grahpics: JlGraphic[]): Platform[] | undefined {
return grahpics
.filter((g) => g.type === Platform.Type)
.map((g) => g as Platform);
}
bind(g: Platform): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
}
unbind(g: Platform): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
}
}

View File

@ -1,86 +0,0 @@
import { Color, Graphics, IPointData, Point } from 'pixi.js';
import { GraphicData, JlGraphic, JlGraphicTemplate } from 'src/jlgraphic';
export interface IRectData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get lineWidth(): number; // 线宽
set lineWidth(v: number);
get lineColor(): string; // 线色
set lineColor(v: string);
get point(): IPointData; // 位置坐标
set point(point: IPointData);
get width(): number; // 宽度
set width(v: number);
get height(): number; // 高度
set height(v: number);
get points(): IPointData[]; // 线坐标点
set points(points: IPointData[]);
clone(): IRectData;
copyFrom(data: IRectData): void;
eq(other: IRectData): boolean;
}
const rectConsts = {
lineWidth: 2,
lineColor: '0xff0000',
width: 60,
height: 20,
};
export class Rect extends JlGraphic {
static Type = 'Rect';
rectGraphic: Graphics;
constructor() {
super(Rect.Type);
this.rectGraphic = new Graphics();
this.addChild(this.rectGraphic);
}
get datas(): IRectData {
return this.getDatas<IRectData>();
}
doRepaint(): void {
const width = this.datas.width;
const height = this.datas.height;
if (this.linePoints.length == 0) {
const r1 = new Point(this.datas.point.x, this.datas.point.y);
const r2 = new Point(r1.x + width, r1.y);
const r3 = new Point(r1.x + width, r1.y + height);
const r4 = new Point(r1.x, r1.y + height);
this.datas.points = [r1, r2, r3, r4, r1];
}
const rectGraphic = this.rectGraphic;
rectGraphic.clear();
rectGraphic.lineStyle(
this.datas.lineWidth,
new Color(this.datas.lineColor)
);
rectGraphic.drawPolygon(this.datas.points);
}
get linePoints(): IPointData[] {
return this.datas.points;
}
set linePoints(points: IPointData[]) {
const old = this.datas.clone();
old.points = points;
this.updateData(old);
}
}
export class RectTemplate extends JlGraphicTemplate<Rect> {
lineWidth: number;
lineColor: string;
width: number;
height: number;
constructor() {
super(Rect.Type);
this.lineWidth = rectConsts.lineWidth;
this.lineColor = rectConsts.lineColor;
this.width = rectConsts.width;
this.height = rectConsts.height;
}
new(): Rect {
return new Rect();
}
}

View File

@ -1,261 +0,0 @@
import {
FederatedPointerEvent,
Graphics,
Point,
IHitArea,
DisplayObject,
FederatedMouseEvent,
} from 'pixi.js';
import {
DraggablePoint,
GraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
JlDrawApp,
JlGraphic,
linePoint,
} from 'src/jlgraphic';
import AbsorbablePoint, {
AbsorbablePosition,
} from 'src/jlgraphic/graphic/AbsorbablePosition';
import {
ILineGraphic,
PolylineEditPlugin,
addWaySegmentingConfig,
addPolygonSegmentingPoint,
clearWayPoint,
clearWaypointsConfig,
getWayLineIndex,
} from 'src/jlgraphic/plugins/GraphicEditPlugin';
import { ContextMenu } from 'src/jlgraphic/ui/ContextMenu';
import { IRectData, Rect, RectTemplate } from './Rect';
import { Link } from '../link/Link';
export interface IRectDrawOptions {
newData: () => IRectData;
}
export class RectDraw extends GraphicDrawAssistant<RectTemplate, IRectData> {
point1: Point | null = null;
point2: Point | null = null;
rectGraphic: Graphics = new Graphics();
constructor(app: JlDrawApp, createData: () => IRectData) {
super(app, new RectTemplate(), createData, Rect.Type, '站台Rect');
this.container.addChild(this.rectGraphic);
RectPointsEditPlugin.init(app);
}
bind(): void {
super.bind();
}
unbind(): void {
super.unbind();
}
clearCache(): void {
this.rectGraphic.clear();
}
onLeftDown(e: FederatedPointerEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
if (this.point1 === null) {
this.point1 = p;
} else {
this.point2 = p;
this.createAndStore(true);
this.point1 = null;
this.point2 = null;
}
}
redraw(p: Point): void {
const template = this.graphicTemplate;
if (this.point1 === null) return;
const rectGraphic = this.rectGraphic;
rectGraphic.clear();
rectGraphic.lineStyle(template.lineWidth, template.lineColor);
rectGraphic.drawRect(...this.normalize(this.point1, p));
}
//根据画的两个点确定左上角的点的坐标和矩形宽高
private normalize(p1: Point, p2: Point): [number, number, number, number] {
const { abs } = Math;
const x = p1.x < p2.x ? p1.x : p2.x;
const y = p1.y < p2.y ? p1.y : p2.y;
const w = abs(p1.x - p2.x);
const h = abs(p1.y - p2.y);
return [x, y, w, h];
}
prepareData(data: IRectData): boolean {
if (this.point1 == null) {
console.log('Rect绘制因点不够取消绘制');
return false;
}
const p1 = this.point1 as Point;
const p2 = this.point2 as Point;
const [x, y, width, height] = this.normalize(p1, p2);
const template = this.graphicTemplate;
data.point = new Point(x, y);
data.lineWidth = template.lineWidth;
data.lineColor = template.lineColor;
data.width = width;
data.height = height;
return true;
}
}
//碰撞检测
export class RectGraphicHitArea implements IHitArea {
rect: Rect;
constructor(rect: Rect) {
this.rect = rect;
}
contains(x: number, y: number): boolean {
let contains = false;
const p = new Point(x, y);
const rectData = this.rect.datas;
//contains = pointPolygon(p, rectData.points, rectData.lineWidth);是否包含多边形内部
const tolerance = rectData.lineWidth;
for (let i = 0; i < rectData.points.length - 1; i++) {
const p1 = rectData.points[i];
const p2 = rectData.points[i + 1];
contains = contains || linePoint(p1, p2, p, tolerance);
if (contains) {
break;
}
}
return contains;
}
}
/**
*
* @param rect
* @returns
*/
function buildAbsorbablePositions(rect: Rect): AbsorbablePosition[] {
const aps: AbsorbablePosition[] = [];
const rects = rect.queryStore.queryByType<Rect>(Rect.Type);
const links = rect.queryStore.queryByType<Link>(Link.Type);
links.forEach((other) => {
const apa = new AbsorbablePoint(
other.localToCanvasPoint(other.getStartPoint())
);
const apb = new AbsorbablePoint(
other.localToCanvasPoint(other.getEndPoint())
);
aps.push(apa, apb);
});
rects.forEach((other) => {
if (other.id == rect.id) {
return;
}
other.linePoints.forEach((point) => {
const absorbablePoint = new AbsorbablePoint(
other.localToCanvasPoint(point)
);
aps.push(absorbablePoint);
});
});
return aps;
}
/**
*
* @param g
* @param dp
* @param index
*/
function onEditPointCreate(g: ILineGraphic, dp: DraggablePoint): void {
const rect = g as Rect;
// 端点
dp.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
rect.getGraphicApp().setOptions({
absorbablePositions: buildAbsorbablePositions(rect),
});
}
});
}
const RectEditMenu: ContextMenu = ContextMenu.init({
name: '矩形编辑菜单',
groups: [
{
items: [addWaySegmentingConfig, clearWaypointsConfig],
},
],
});
/**
* rect路径编辑
*/
export class RectPointsEditPlugin extends GraphicInteractionPlugin<Rect> {
static Name = 'RectPointsDrag';
constructor(app: GraphicApp) {
super(RectPointsEditPlugin.Name, app);
app.registerMenu(RectEditMenu);
}
static init(app: GraphicApp): RectPointsEditPlugin {
return new RectPointsEditPlugin(app);
}
filter(...grahpics: JlGraphic[]): Rect[] | undefined {
return grahpics.filter((g) => g.type == Rect.Type) as Rect[];
}
bind(g: Rect): void {
g.rectGraphic.eventMode = 'static';
g.rectGraphic.cursor = 'pointer';
g.rectGraphic.hitArea = new RectGraphicHitArea(g);
g.on('_rightclick', this.onContextMenu, this);
g.on('selected', this.onSelected, this);
g.on('unselected', this.onUnselected, this);
}
unbind(g: Rect): void {
g.off('_rightclick', this.onContextMenu, this);
g.off('selected', this.onSelected, this);
g.off('unselected', this.onUnselected, this);
}
onContextMenu(e: FederatedMouseEvent) {
const target = e.target as DisplayObject;
const rect = target.getGraphic() as Rect;
this.app.updateSelected(rect);
addWaySegmentingConfig.handler = () => {
const linePoints = rect.linePoints;
const p = rect.screenToLocalPoint(e.global);
const { start, end } = getWayLineIndex(linePoints, p);
addPolygonSegmentingPoint(rect, start, end);
};
clearWaypointsConfig.handler = () => {
clearWayPoint(rect, false);
};
RectEditMenu.open(e.global);
}
onSelected(g: DisplayObject): void {
const rect = g as Rect;
let lep = rect.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (!lep) {
lep = new PolylineEditPlugin(rect, { onEditPointCreate });
rect.addAssistantAppend(lep);
}
lep.showAll();
}
onUnselected(g: DisplayObject): void {
const rect = g as Rect;
const lep = rect.getAssistantAppend<PolylineEditPlugin>(
PolylineEditPlugin.Name
);
if (lep) {
lep.hideAll();
}
}
}

View File

@ -1,52 +0,0 @@
import { Container } from '@pixi/display';
import { Graphics } from 'pixi.js';
export enum LampEnum {
lampPostColor = '0xc0c0c0',
lampDefaultColor = '0xff0000',
logicModeColor = '0x000000',
}
const lampConsts = {
lampRadius: 10,
logicModeLineWidth: 2,
logicModeDistance: 7,
};
export class Lamp extends Container {
circleLamp: Graphics = new Graphics();
logicMode: Graphics = new Graphics();
constructor() {
super();
this.addChild(this.circleLamp);
this.addChild(this.logicMode);
}
paint(radiusX: number, radiusY: number) {
this.circleLamp.clear();
this.circleLamp
.beginFill(LampEnum.lampDefaultColor, 1)
.drawCircle(radiusX, radiusY, lampConsts.lampRadius)
.endFill();
this.logicMode
.clear()
.lineStyle(lampConsts.logicModeLineWidth, LampEnum.logicModeColor)
.moveTo(
radiusX - lampConsts.logicModeDistance,
radiusY + lampConsts.logicModeDistance
)
.lineTo(
radiusX + lampConsts.logicModeDistance,
radiusY - lampConsts.logicModeDistance
)
.moveTo(
radiusX - lampConsts.logicModeDistance,
radiusY - lampConsts.logicModeDistance
)
.lineTo(
radiusX + lampConsts.logicModeDistance,
radiusY + lampConsts.logicModeDistance
);
}
}

View File

@ -1,51 +0,0 @@
import { Container } from '@pixi/display';
import { Graphics } from 'pixi.js';
import { Lamp } from './Lamp';
export enum LampEnum {
lampPostColor = '0xc0c0c0',
}
const lampConsts = {
verticalLampPostLength: 20,
levelLampPostLength: 5,
postLineWidth: 3,
lampRadius: 10,
};
export class LampMainBody extends Container {
lampNum = 1;
lampPost: Graphics = new Graphics();
lamps: Lamp[] = [];
constructor() {
super();
}
paint(lampNum: number) {
if (lampNum < 1) {
throw new Error('信号机灯数量异常');
}
this.lampNum = lampNum;
this.removeChildren(0);
this.lampPost = new Graphics();
this.lampPost
.lineStyle(lampConsts.postLineWidth, LampEnum.lampPostColor)
.moveTo(0, -lampConsts.verticalLampPostLength / 2)
.lineTo(0, lampConsts.verticalLampPostLength / 2)
.moveTo(0, 0)
.lineTo(lampConsts.levelLampPostLength, 0);
this.addChild(this.lampPost);
this.lamps = [];
for (let i = 0; i < this.lampNum; i++) {
const lamp = new Lamp();
const radiusX =
(1 + i * 2) * lampConsts.lampRadius + lampConsts.levelLampPostLength;
lamp.paint(radiusX, 0);
this.addChild(lamp);
this.lamps.push(lamp);
}
}
// setState() {}
}

View File

@ -1,102 +0,0 @@
import { Graphics } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jlgraphic';
import { LampMainBody } from './LampMainBody';
import { drawArrow } from '../CommonGraphics';
export interface ISignalData extends GraphicData {
get code(): string; // 编号
set code(v: string);
clone(): ISignalData;
copyFrom(data: ISignalData): void;
eq(other: ISignalData): boolean;
}
export enum SignalColorEnum {
humanControlColor = '0xffff00',
fleetModeColor = '0x00ff00',
codeColor = '0X000000',
}
const signalConsts = {
lampNum: 1,
codeFontSize: 11,
nameOffsetY: 20,
fleetModeLength: 33,
fleetModeRadius: 10,
fleetModeLineWidth: 6,
};
export class Signal extends JlGraphic {
static Type = 'signal';
codeGraph: VectorText = new VectorText('');
humanControl: Graphics = new Graphics();
fleetMode: Graphics = new Graphics();
lampMainBody: LampMainBody = new LampMainBody();
constructor() {
super(Signal.Type);
this.codeGraph.name = 'signalCode';
this.addChild(this.codeGraph);
this.addChild(this.humanControl);
this.addChild(this.fleetMode);
this.addChild(this.lampMainBody);
}
get datas(): ISignalData {
return this.getDatas<ISignalData>();
}
paint(): void {
this.lampMainBody.paint(signalConsts.lampNum);
this.humanControl.beginFill(SignalColorEnum.humanControlColor, 1);
if (this.humanControl.drawRegularPolygon) {
this.humanControl.drawRegularPolygon(-10, 0, 10, 3, Math.PI / 2);
}
this.humanControl.endFill();
this.fleetMode.beginFill(SignalColorEnum.fleetModeColor, 1);
drawArrow(
this.fleetMode,
this.lampMainBody.width + signalConsts.fleetModeLength,
0,
signalConsts.fleetModeLength,
signalConsts.fleetModeRadius,
signalConsts.fleetModeLineWidth
);
this.fleetMode.endFill();
this.codeGraph.text = this.datas?.code || '信号机编号';
this.codeGraph.style.fill = SignalColorEnum.codeColor;
this.codeGraph.setVectorFontSize(signalConsts.codeFontSize);
this.codeGraph.anchor.set(0.5);
this.codeGraph.style.fill = SignalColorEnum.codeColor;
const codeTransform = this.datas?.childTransforms?.find(
(item) => item.name === 'signalCode'
);
if (codeTransform) {
const position = codeTransform?.transform.position;
const rotation = codeTransform?.transform?.rotation;
this.codeGraph.position.set(position?.x, position?.y);
this.codeGraph.rotation = rotation || 0;
} else {
this.codeGraph.position.set(0, signalConsts.nameOffsetY);
}
}
doRepaint(): void {
this.paint();
}
}
export class SignalTemplate extends JlGraphicTemplate<Signal> {
constructor(dataTemplate: ISignalData) {
super(Signal.Type, {
dataTemplate,
});
}
new(): Signal {
return new Signal();
}
}

View File

@ -1,133 +0,0 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
AbsorbableLine,
AbsorbablePosition,
GraphicApp,
GraphicDrawAssistant,
GraphicInteractionPlugin,
GraphicTransformEvent,
JlDrawApp,
JlGraphic,
} from 'src/jlgraphic';
import { ISignalData, Signal, SignalTemplate } from './Signal';
import { IscsFan } from '../iscs-fan/IscsFan';
export interface ISignalDrawOptions {
newData: () => ISignalData;
}
export class SignalDraw extends GraphicDrawAssistant<
SignalTemplate,
ISignalData
> {
_signal: Signal | null = null;
constructor(app: JlDrawApp, template: SignalTemplate) {
super(
app,
template,
'svguse: ../../drawIcon.svg#icon-signal',
'信号机Signal'
);
signalInteraction.init(app);
}
public get signal(): Signal {
if (!this._signal) {
this._signal = this.graphicTemplate.new();
this.signal.loadData(this.graphicTemplate.datas);
this.container.addChild(this.signal);
}
return this._signal;
}
clearCache(): void {
//this.codeGraph.clear();
}
onRightClick(): void {
this.createAndStore(true);
}
onLeftUp(e: FederatedPointerEvent): void {
this.container.position.copyFrom(this.toCanvasCoordinates(e.global));
this.createAndStore(true);
}
redraw(p: Point): void {
this.signal.paint();
this.container.position.set(p.x, p.y);
}
prepareData(data: ISignalData): boolean {
data.transform = this.container.saveTransform();
return true;
}
}
export class signalInteraction extends GraphicInteractionPlugin<Signal> {
static Name = 'signal_transform';
constructor(app: JlDrawApp) {
super(signalInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new signalInteraction(app);
}
filter(...grahpics: JlGraphic[]): Signal[] | undefined {
return grahpics
.filter((g) => g.type === Signal.Type)
.map((g) => g as Signal);
}
bind(g: Signal): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
g.codeGraph.draggable = true;
g.codeGraph.selectable = true;
g.codeGraph.rotatable = true;
g.codeGraph.scalable = true;
g.codeGraph.transformSave = true;
g.codeGraph.eventMode = 'static';
g.codeGraph.on('transformstart', (e: GraphicTransformEvent) => {
if (e.isShift()) {
console.log(
'信号机画布坐标',
e.target.position,
e.target.getPositionOnCanvas()
);
const app = g.getGraphicApp();
app.setOptions({
absorbablePositions: buildAbsorbablePositions(app),
});
}
});
}
// onScaleDragEnd() {
// console.log('-----------------');
// }
unbind(g: Signal): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
g.codeGraph.draggable = false;
g.codeGraph.selectable = false;
g.codeGraph.rotatable = false;
g.codeGraph.scalable = false;
g.codeGraph.transformSave = false;
g.codeGraph.eventMode = 'none';
}
}
function buildAbsorbablePositions(app: GraphicApp): AbsorbablePosition[] {
const canvas = app.canvas;
const store = app.queryStore;
const aps: AbsorbablePosition[] = [];
store.queryByType(IscsFan.Type).forEach((fan) => {
const p = fan.position;
aps.push(
new AbsorbableLine(new Point(0, p.y), new Point(canvas.width, p.y))
);
aps.push(
new AbsorbableLine(new Point(p.x, 0), new Point(p.x, canvas.height))
);
});
return aps;
}

View File

@ -1,101 +0,0 @@
import { Color, Graphics, IPointData, Point } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jlgraphic';
export interface IStationData extends GraphicData {
get code(): string; // 编号
set code(v: string);
get hasCircle(): boolean; // 是否有圆圈--线网图
set hasCircle(v: boolean);
get radius(): number; // 半径
set radius(v: number);
get borderWidth(): number; // 线宽
set borderWidth(v: number);
get borderColor(): string; // 圆边框线色
set borderColor(v: string);
get fillColor(): string; // 圆填充颜色
set fillColor(v: string);
get codeColor(): string; // 车站字体颜色
set codeColor(v: string);
get codeFontSize(): number; // 车站字体大小
set codeFontSize(v: number);
get point(): IPointData; // 位置坐标
set point(point: IPointData);
get circlePoint(): IPointData; // 位置坐标
set circlePoint(point: IPointData);
clone(): IStationData;
copyFrom(data: IStationData): void;
eq(other: IStationData): boolean;
}
export class Station extends JlGraphic {
static Type = 'station';
codeGraph: VectorText = new VectorText(''); //站台旁数字、字符
circleGraphic: Graphics;
constructor() {
super(Station.Type);
this.circleGraphic = new Graphics();
this.addChild(this.codeGraph);
this.addChild(this.circleGraphic);
}
get datas(): IStationData {
return this.getDatas<IStationData>();
}
doRepaint(): void {
this.circleGraphic.clear();
this.position.set(this.datas.point.x, this.datas.point.y);
const codeGraph = this.codeGraph;
if (this.datas.code == '') {
codeGraph.text = '车站Station';
} else {
codeGraph.text = this.datas.code;
}
codeGraph.style.fill = this.datas.codeColor;
codeGraph.setVectorFontSize(this.datas.codeFontSize);
codeGraph.anchor.set(0.5);
if (this.datas.hasCircle) {
const circleGraphic = this.circleGraphic;
circleGraphic.lineStyle(
this.datas.borderWidth,
new Color(this.datas.borderColor)
);
circleGraphic.beginFill(this.datas.fillColor, 1);
circleGraphic.drawCircle(0, 0, this.datas.radius);
circleGraphic.endFill;
circleGraphic.position.set(
this.datas.circlePoint.x,
this.datas.circlePoint.y
);
}
}
}
export class StationTemplate extends JlGraphicTemplate<Station> {
hasCircle: boolean;
radius: number;
borderWidth: number;
borderColor: string;
fillColor: string;
codeColor: string;
codeFontSize: number;
circlePoint: IPointData;
constructor() {
super(Station.Type);
this.hasCircle = false;
this.radius = 5;
this.borderWidth = 1;
this.borderColor = '0xff0000';
this.fillColor = '0xff0000';
this.codeColor = '0xF48815';
this.codeFontSize = 22;
this.circlePoint = new Point(0, -20);
}
new(): Station {
return new Station();
}
}

View File

@ -1,93 +0,0 @@
import { FederatedPointerEvent, Point } from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicInteractionPlugin,
JlDrawApp,
JlGraphic,
VectorText,
} from 'src/jlgraphic';
import { IStationData, Station, StationTemplate } from './Station';
export interface IStationDrawOptions {
newData: () => IStationData;
}
export class StationDraw extends GraphicDrawAssistant<
StationTemplate,
IStationData
> {
point: Point = new Point(0, 0);
codeGraph: VectorText = new VectorText('');
constructor(app: JlDrawApp, createData: () => IStationData) {
super(app, new StationTemplate(), createData, Station.Type, '车站Station');
this.container.addChild(this.codeGraph);
stationInteraction.init(app);
}
bind(): void {
super.bind();
}
unbind(): void {
super.unbind();
}
clearCache(): void {
//this.codeGraph.clear();
}
onLeftDown(e: FederatedPointerEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
this.point = p;
this.createAndStore(true);
}
redraw(p: Point): void {
const codeGraph = this.codeGraph;
codeGraph.text = '车站Station';
codeGraph.anchor.set(0.5);
codeGraph.style.fill = '0xf48815';
codeGraph.position.set(p.x, p.y);
codeGraph.setVectorFontSize(22);
}
prepareData(data: IStationData): boolean {
const template = this.graphicTemplate;
data.point = this.point;
data.hasCircle = template.hasCircle;
data.radius = template.radius;
data.borderWidth = template.borderWidth;
data.borderColor = template.borderColor;
data.fillColor = template.fillColor;
data.codeColor = template.codeColor;
data.codeFontSize = template.codeFontSize;
data.circlePoint = template.circlePoint;
return true;
}
}
export class stationInteraction extends GraphicInteractionPlugin<Station> {
static Name = 'station_transform';
constructor(app: JlDrawApp) {
super(stationInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new stationInteraction(app);
}
filter(...grahpics: JlGraphic[]): Station[] | undefined {
return grahpics
.filter((g) => g.type === Station.Type)
.map((g) => g as Station);
}
bind(g: Station): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
}
unbind(g: Station): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
}
}

View File

@ -1,185 +0,0 @@
import { Color, Graphics, IPointData } from 'pixi.js';
import {
GraphicData,
JlGraphic,
JlGraphicTemplate,
VectorText,
} from 'src/jlgraphic';
export interface ITrainData extends GraphicData {
get code(): string; // 车号
set code(v: string);
get codeColor(): string; // 车号颜色
set codeColor(v: string);
get codeFontSize(): number; // 车号字体大小
set codeFontSize(v: number);
get trainDirection(): string; // 行驶方向
set trainDirection(v: string);
get hasBorder(): boolean; // 是否有边框
set hasBorder(v: boolean);
get borderWidth(): number; // 边框线宽
set borderWidth(v: number);
get borderColor(): string; // 边框颜色
set borderColor(v: string);
get headColor(): string; // 箭头颜色
set headColor(v: string);
get bodyColor(): string; // 背景色
set bodyColor(v: string);
get point(): IPointData; // 位置坐标
set point(point: IPointData);
clone(): ITrainData;
copyFrom(data: ITrainData): void;
eq(other: ITrainData): boolean;
}
// 列车颜色
export enum TrainColorEnum {
headColor = '0x00FF00', // 箭头颜色
bodyColor = '0xA388B1', // 背景色
codeColor = '0xffffff', // 车号颜色
borderColor = '0xA3E198', // 边框的颜色
}
export const trainConsts = {
borderWidth: 1,
codeFontSize: 22,
marginX: 2, // 图形x轴边距
pauseW: 2, // 停止框宽度
};
export class Train extends JlGraphic {
static Type = 'Train';
arrowLeft: Graphics;
pauseLeft: Graphics;
arrowRight: Graphics;
pauseRight: Graphics;
codeRact: Graphics;
codeGraph: VectorText = new VectorText(''); //车号
constructor() {
super(Train.Type);
this.arrowLeft = new Graphics();
this.pauseLeft = new Graphics();
this.arrowRight = new Graphics();
this.pauseRight = new Graphics();
this.codeRact = new Graphics();
this.addChild(this.arrowLeft);
this.addChild(this.pauseLeft);
this.addChild(this.arrowRight);
this.addChild(this.pauseRight);
this.addChild(this.codeRact);
this.addChild(this.codeGraph);
this.codeGraph.setVectorFontSize(trainConsts.codeFontSize);
}
get datas(): ITrainData {
return this.getDatas<ITrainData>();
}
doRepaint(): void {
this.position.set(this.datas.point.x, this.datas.point.y);
const codeGraph = this.codeGraph;
const codeRact = this.codeRact;
if (this.datas.code == '') {
codeGraph.text = '01110111';
} else {
codeGraph.text = this.datas.code;
}
codeGraph.setVectorFontSize(this.datas.codeFontSize);
codeGraph.anchor.set(0.5);
const style = {
fill: this.datas.codeColor,
padding: 5,
};
codeGraph.style = style;
const {
x: codeX,
y: codeY,
width: codeWidth,
height: codeHeight,
} = codeGraph.getLocalBounds();
const marginX = trainConsts.marginX;
const pauseW = trainConsts.pauseW;
const arrowLeft = this.arrowLeft;
arrowLeft.beginFill(this.datas.headColor, 1);
arrowLeft.drawPolygon([
-codeHeight * 0.4 - marginX - pauseW - marginX - codeWidth / 2,
0,
-marginX - pauseW - marginX - codeWidth / 2,
codeHeight / 2,
-marginX - pauseW - marginX - codeWidth / 2,
-codeHeight / 2,
]);
arrowLeft.endFill();
this.pauseLeft.beginFill(this.datas.headColor, 1);
this.pauseLeft.drawRect(0, 0, pauseW, codeHeight);
this.pauseLeft.endFill();
this.pauseLeft.position.set(
-marginX - pauseW - codeWidth / 2,
-codeHeight / 2
);
this.pauseRight.beginFill(this.datas.headColor, 1);
this.pauseRight.drawRect(0, 0, pauseW, codeHeight);
this.pauseRight.endFill();
this.pauseRight.position.set(marginX + codeWidth / 2, -codeHeight / 2);
const arrowRight = this.arrowRight;
arrowRight.beginFill(this.datas.headColor, 1);
arrowRight.drawPolygon([
codeWidth / 2 + marginX + pauseW + marginX + codeHeight * 0.4,
0,
codeWidth / 2 + marginX + pauseW + marginX,
codeHeight / 2,
codeWidth / 2 + marginX + pauseW + marginX,
-codeHeight / 2,
]);
arrowRight.endFill();
if (this.datas.hasBorder) {
codeRact.visible = true;
codeRact.lineStyle(
this.datas.borderWidth,
new Color(this.datas.borderColor)
);
codeRact.beginFill(new Color(this.datas.bodyColor));
codeRact.drawRect(codeX, codeY, codeWidth, codeHeight);
codeRact.endFill();
} else {
codeRact.visible = false;
}
// 运行方向控制箭头停止显隐
if (this.datas.trainDirection == 'right') {
this.arrowLeft.visible = false;
this.arrowRight.visible = true;
this.pauseLeft.visible = false;
this.pauseRight.visible = true;
} else {
this.arrowLeft.visible = true;
this.arrowRight.visible = false;
this.pauseLeft.visible = true;
this.pauseRight.visible = false;
}
}
}
export class TrainTemplate extends JlGraphicTemplate<Train> {
trainDirection: string;
codeFontSize: number;
hasBorder: boolean;
borderWidth: number;
borderColor: string;
headColor: string;
codeColor: string;
bodyColor: string;
constructor() {
super(Train.Type);
this.trainDirection = 'left';
this.codeFontSize = trainConsts.codeFontSize;
this.hasBorder = true;
this.borderWidth = trainConsts.borderWidth;
this.borderColor = TrainColorEnum.borderColor;
this.headColor = TrainColorEnum.headColor;
this.codeColor = TrainColorEnum.codeColor;
this.bodyColor = TrainColorEnum.bodyColor;
}
new(): Train {
return new Train();
}
}

View File

@ -1,138 +0,0 @@
import { Color, FederatedPointerEvent, Graphics, Point } from 'pixi.js';
import {
GraphicDrawAssistant,
GraphicInteractionPlugin,
JlDrawApp,
JlGraphic,
VectorText,
} from 'src/jlgraphic';
import { ITrainData, Train, TrainTemplate, trainConsts } from './Train';
export interface ITrainDrawOptions {
newData: () => ITrainData;
}
export class TrainDraw extends GraphicDrawAssistant<TrainTemplate, ITrainData> {
point: Point = new Point(0, 0);
arrowLeft: Graphics = new Graphics();
pauseLeft: Graphics = new Graphics();
codeRact: Graphics = new Graphics();
constructor(app: JlDrawApp, createData: () => ITrainData) {
super(app, new TrainTemplate(), createData, Train.Type, '列车Train');
this.container.addChild(this.arrowLeft);
this.container.addChild(this.pauseLeft);
this.container.addChild(this.codeRact);
this.graphicTemplate.hasBorder = true;
trainInteraction.init(app);
}
bind(): void {
super.bind();
}
unbind(): void {
super.unbind();
}
clearCache(): void {
this.arrowLeft.clear();
this.pauseLeft.clear();
this.codeRact.clear();
}
onLeftDown(e: FederatedPointerEvent): void {
const { x, y } = this.toCanvasCoordinates(e.global);
const p = new Point(x, y);
this.point = p;
this.createAndStore(true);
}
redraw(p: Point): void {
const template = this.graphicTemplate;
const codeGraph = new VectorText(''); // 车号
codeGraph.setVectorFontSize(22);
codeGraph.anchor.set(0.5);
codeGraph.text = '01110111';
const style = { padding: 5 };
codeGraph.style = style;
const { width, height } = codeGraph.getLocalBounds();
codeGraph.destroy();
const marginX = trainConsts.marginX;
const pauseW = trainConsts.pauseW;
// 边框
if (template.hasBorder) {
const codeRact = this.codeRact;
codeRact.clear();
codeRact.lineStyle(template.borderWidth, new Color(template.borderColor));
codeRact.beginFill(new Color(template.bodyColor));
codeRact.drawRect(-width / 2, -height / 2, width, height);
codeRact.endFill();
codeRact.position.set(p.x, p.y);
}
// 箭头
const arrowLeft = this.arrowLeft;
arrowLeft.clear();
this.point.set(p.x, p.y);
arrowLeft.beginFill(template.headColor, 1);
arrowLeft.drawPolygon([
-height * 0.4 - marginX - pauseW - marginX - width / 2,
0,
-marginX - pauseW - marginX - width / 2,
height / 2,
-marginX - pauseW - marginX - width / 2,
-height / 2,
]);
arrowLeft.endFill();
arrowLeft.position.set(this.point.x, this.point.y);
// 停止框
const pauseLeft = this.pauseLeft;
pauseLeft.clear();
pauseLeft.beginFill(template.headColor, 1);
pauseLeft.drawRect(0, 0, pauseW, height);
pauseLeft.endFill();
pauseLeft.position.set(
this.point.x - marginX - pauseW - width / 2,
this.point.y - height / 2
);
}
prepareData(data: ITrainData): boolean {
const template = this.graphicTemplate;
data.code = '01110111';
data.codeColor = template.codeColor;
data.codeFontSize = template.codeFontSize;
data.hasBorder = template.hasBorder;
data.trainDirection = template.trainDirection;
data.point = this.point;
data.borderWidth = template.borderWidth;
data.borderColor = template.borderColor;
data.headColor = template.headColor;
data.bodyColor = template.bodyColor;
return true;
}
}
export class trainInteraction extends GraphicInteractionPlugin<Train> {
static Name = 'train_transform';
constructor(app: JlDrawApp) {
super(trainInteraction.Name, app);
}
static init(app: JlDrawApp) {
return new trainInteraction(app);
}
filter(...grahpics: JlGraphic[]): Train[] | undefined {
return grahpics.filter((g) => g.type === Train.Type).map((g) => g as Train);
}
bind(g: Train): void {
g.eventMode = 'static';
g.cursor = 'pointer';
g.scalable = true;
g.rotatable = true;
}
unbind(g: Train): void {
g.eventMode = 'none';
g.scalable = false;
g.rotatable = false;
}
}

View File

@ -1,9 +0,0 @@
import { GraphicData, JlGraphic } from 'src/jlgraphic';
export type ITrunoutData = GraphicData;
export class Turnout extends JlGraphic {
doRepaint(): void {
throw new Error('Method not implemented.');
}
}

7
src/index.ts Normal file
View File

@ -0,0 +1,7 @@
export * from './core';
export * from './graphic';
export * from './app';
export * from './operation';
export * from './utils';
export * from './plugins';
export * from './message';

1
src/message/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './MessageBroker';

View File

@ -70,7 +70,6 @@ export class OperationRecord {
if (this.undoStack.length >= this.maxLen) { if (this.undoStack.length >= this.maxLen) {
this.undoStack.shift(); this.undoStack.shift();
} }
// console.log('operation record', op)
this.undoStack.push(op); this.undoStack.push(op);
this.redoStack.splice(0, this.redoStack.length); this.redoStack.splice(0, this.redoStack.length);
} }
@ -79,7 +78,6 @@ export class OperationRecord {
*/ */
undo() { undo() {
const op = this.undoStack.pop(); const op = this.undoStack.pop();
// console.log('撤销', op);
if (op) { if (op) {
op.undo1(); op.undo1();
this.redoStack.push(op); this.redoStack.push(op);
@ -90,7 +88,6 @@ export class OperationRecord {
*/ */
redo() { redo() {
const op = this.redoStack.pop(); const op = this.redoStack.pop();
// console.log('重做', op);
if (op) { if (op) {
op.redo1(); op.redo1();
this.undoStack.push(op); this.undoStack.push(op);

1
src/operation/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './JlOperation';

View File

@ -153,10 +153,6 @@ export class CommonMouseTool extends AppInteractionPlugin {
} }
onDragStart(event: AppDragEvent) { onDragStart(event: AppDragEvent) {
// console.log(
// 'start',
// `pointerType:${event.original.pointerType},pointerId:${event.original.pointerId},button: ${event.original.button},buttons:${event.original.buttons}`
// );
if (this.boxSelect && event.target.isCanvas() && event.isLeftButton) { if (this.boxSelect && event.target.isCanvas() && event.isLeftButton) {
this.box.visible = true; this.box.visible = true;
this.app.interactionPlugin(ViewportMovePlugin.Name).resume(); this.app.interactionPlugin(ViewportMovePlugin.Name).resume();
@ -165,19 +161,11 @@ export class CommonMouseTool extends AppInteractionPlugin {
} }
onDragMove(event: AppDragEvent) { onDragMove(event: AppDragEvent) {
// console.log(
// 'moving',
// `pointerType:${event.original.pointerType},pointerId:${event.original.pointerId},button: ${event.original.button},buttons:${event.original.buttons}`
// );
if (this.boxSelect && event.target.isCanvas()) { if (this.boxSelect && event.target.isCanvas()) {
this.boxSelectDraw(event.start, event.end); this.boxSelectDraw(event.start, event.end);
} }
} }
onDragEnd(event: AppDragEvent) { onDragEnd(event: AppDragEvent) {
// console.log(
// 'end',
// `pointerType:${event.original.pointerType},pointerId:${event.original.pointerId},button: ${event.original.button},buttons:${event.original.buttons}`
// );
if (this.boxSelect && event.target.isCanvas() && event.isLeftButton) { if (this.boxSelect && event.target.isCanvas() && event.isLeftButton) {
this.boxSelectDraw(event.start, event.end); this.boxSelectDraw(event.start, event.end);
this.boxSelectGraphicCheck(); this.boxSelectGraphicCheck();
@ -232,7 +220,6 @@ export class CommonMouseTool extends AppInteractionPlugin {
const graphic = this.leftDownTarget.getGraphic(); const graphic = this.leftDownTarget.getGraphic();
if (graphic) { if (graphic) {
const app = this.app; const app = this.app;
// console.log(this.leftDownTarget.isGraphic());
// 图形选中 // 图形选中
if (!e.ctrlKey && !graphic.selected && graphic.selectable) { if (!e.ctrlKey && !graphic.selected && graphic.selectable) {
app.updateSelected(graphic); app.updateSelected(graphic);

View File

@ -403,7 +403,6 @@ export class BezierCurveEditPlugin extends LineEditPlugin {
} }
initEditPoints() { initEditPoints() {
// console.log('initEditPoints');
const cps = this.graphic.localToCanvasPoints(...this.linePoints); const cps = this.graphic.localToCanvasPoints(...this.linePoints);
for (let i = 0; i < cps.length; i++) { for (let i = 0; i < cps.length; i++) {
const p = cps[i]; const p = cps[i];

View File

@ -204,7 +204,6 @@ export class GraphicTransformPlugin extends InteractionPluginBase {
aps.push(ap); aps.push(ap);
} }
} }
// console.log(positions, aps);
return aps; return aps;
} }
@ -319,8 +318,6 @@ export class GraphicTransformPlugin extends InteractionPluginBase {
); );
} }
}); });
// const dt = new Date().getTime() - start;
// console.log('拖拽耗时', `${dt}ms`, targets);
} }
} }
} }
@ -539,7 +536,6 @@ export class TransformPoints extends Container {
KeyListener.create({ KeyListener.create({
value: '' + i, value: '' + i,
onPress: () => { onPress: () => {
// console.log('修改角度step');
this.angleStep = i; this.angleStep = i;
}, },
}) })
@ -707,7 +703,6 @@ export class TransformPoints extends Container {
// 计算缩放比例,并根据是否保持纵横比两种情况进行缩放处理 // 计算缩放比例,并根据是否保持纵横比两种情况进行缩放处理
const sx = originWidth == 0 ? this.originScale.x : width / originWidth; const sx = originWidth == 0 ? this.originScale.x : width / originWidth;
const sy = originHeight == 0 ? this.originScale.y : height / originHeight; const sy = originHeight == 0 ? this.originScale.y : height / originHeight;
// console.log(originWidth, originHeight, width, height, sx, sy);
if (this.obj.keepAspectRatio) { if (this.obj.keepAspectRatio) {
let max = Math.max(sx, sy); let max = Math.max(sx, sy);
if (originWidth == 0) { if (originWidth == 0) {

View File

@ -238,7 +238,6 @@ export class DragPlugin extends OtherInteractionPlugin {
// drag移动处理 // drag移动处理
if (this.target && this.drag && this.start) { if (this.target && this.drag && this.start) {
// console.log('drag move', e.movement);
this.app.emit( this.app.emit(
'drag_op_move', 'drag_op_move',
new AppDragEvent(this.app, 'move', this.target, e, this.start) new AppDragEvent(this.app, 'move', this.target, e, this.start)
@ -249,7 +248,6 @@ export class DragPlugin extends OtherInteractionPlugin {
onPointerUp(e: FederatedPointerEvent) { onPointerUp(e: FederatedPointerEvent) {
if (this.target && this.drag && this.start) { if (this.target && this.drag && this.start) {
// console.log('drag end');
this.app.emit( this.app.emit(
'drag_op_end', 'drag_op_end',
new AppDragEvent(this.app, 'end', this.target, e, this.start) new AppDragEvent(this.app, 'end', this.target, e, this.start)

View File

@ -18,7 +18,6 @@ export class GlobalKeyboardHelper {
if (e.ctrlKey) { if (e.ctrlKey) {
if (e.code == 'KeyS') { if (e.code == 'KeyS') {
// 屏蔽全局Ctrl+S保存操作 // 屏蔽全局Ctrl+S保存操作
// console.log('屏蔽全局Ctrl+S')
return false; return false;
} }
} }
@ -81,7 +80,6 @@ export class JlGraphicAppKeyboardPlugin {
const onMouseUpdateTarget = (e: MouseEvent) => { const onMouseUpdateTarget = (e: MouseEvent) => {
const node = e.target as Node; const node = e.target as Node;
target = node; target = node;
// console.log('Mousedown Event', node.nodeName, node.nodeType, node.nodeValue)
}; };
const keydownHandle = (e: KeyboardEvent) => { const keydownHandle = (e: KeyboardEvent) => {
// console.debug(e.key, e.code, e.keyCode); // console.debug(e.key, e.code, e.keyCode);
@ -147,7 +145,6 @@ export class JlGraphicAppKeyboardPlugin {
stack.push(old); stack.push(old);
} }
map.set(keyListener.identifier, keyListener); map.set(keyListener.identifier, keyListener);
// console.log(this.getAllListenedKeys());
} }
/** /**
* *
@ -172,7 +169,6 @@ export class JlGraphicAppKeyboardPlugin {
stack.splice(index, 1); stack.splice(index, 1);
} }
} }
// console.log(this);
} }
getKeyListenerBy(key: string | number): Map<string, KeyListener> | undefined { getKeyListenerBy(key: string | number): Map<string, KeyListener> | undefined {
@ -307,7 +303,6 @@ export class KeyListener {
return; return;
} }
if (this.pressTriggerEveryTime || !this.isPress) { if (this.pressTriggerEveryTime || !this.isPress) {
// console.log('Keydown: ', e, this.onPress);
this.isPress = true; this.isPress = true;
if (this.onPress) { if (this.onPress) {
this.onPress(e, app); this.onPress(e, app);
@ -338,7 +333,6 @@ export class KeyListener {
release(e: KeyboardEvent, app: IGraphicApp): void { release(e: KeyboardEvent, app: IGraphicApp): void {
if (this.isPress) { if (this.isPress) {
// console.log('Keyup : ', e.key, e);
this.isPress = false; this.isPress = false;
if (this.onRelease) { if (this.onRelease) {
this.onRelease(e, app); this.onRelease(e, app);

6
src/plugins/index.ts Normal file
View File

@ -0,0 +1,6 @@
export * from './InteractionPlugin';
export * from './CommonMousePlugin';
export * from './KeyboardPlugin';
export * from './CopyPlugin';
export * from './GraphicTransformPlugin';
export * from './AnimationManager';

Some files were not shown because too many files have changed in this diff Show More