123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748 |
- /*
- * *********************************************************************************************************************
- *
- * !!
- * .F88X
- * X8888Y
- * .}888888N;
- * i888888N; .:! .I$WI:
- * R888888I .'N88~ i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
- * .R888888I .;N8888~ .X8' "8I.!,/8" !%NY8`"8I8~~8>,88I
- * +888888N; .8888888Y "&&8Y.}8,
- * ./888888N; .R888888Y .'}~ .>}'.`+> i}! "i' +/' .'i~ !11,.:">, .~]! .i}i
- * ~888888%: .I888888l .]88~`1/iY88Ii+1'.R$8$8]"888888888> Y8$ W8E X8E W8888'188Il}Y88$*
- * 18888888 E8888881 .]W%8$`R8X'&8%++N8i,8N%N8+l8%` .}8N:.R$RE%N88N%N$K$R 188,FE$8%~Y88I
- * .E888888I .i8888888' .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
- * 8888888I .,N888888~ ~88i"8W,!N8*.I88.}888%F,i$88"F88" 888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
- * i888888N' I888Y ]88;/EX*IFKFK88X K8R .l8W 88Y ~88}'88E&%8W.X8N``]88!.$8K .:W8I
- * .i888888N; I8Y .&8$ .X88! i881.:%888>I88 ;88] +88+.';;;;:.Y88X 18N.,88l .+88/
- * .:R888888I
- * .&888888I Copyright (c) 2016-2020. 博锐尚格科技股份有限公司
- * ~8888'
- * .!88~ All rights reserved.
- *
- * *********************************************************************************************************************
- */
- import {
- SMouseButton,
- SMouseEvent,
- SObject,
- SMatrix
- } from "@persagy-web/base/lib";
- import { SPainter, SPoint, SRect } from "@persagy-web/draw/lib";
- import { SGraphScene } from "./SGraphScene";
- /**
- * Graph图形引擎Item类
- *
- * @author 庞利祥(sybotan@126.com)
- */
- export class SGraphItem extends SObject {
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 属性
- /** 场景对象 */
- private _scene: SGraphScene | null = null;
- get scene(): SGraphScene | null {
- if (null != this._parent) {
- return this._parent.scene;
- } else {
- return this._scene;
- }
- } // Get scene
- set scene(v: SGraphScene | null) {
- this._scene = v;
- this.update();
- } // Set scene
- /** parent属性存值函数 */
- private _parent: SGraphItem | null = null;
- get parent(): SGraphItem | null {
- return this._parent;
- } // Get parent
- set parent(v: SGraphItem | null) {
- // 如果parent未变更
- if (this.parent == v) {
- return;
- }
- // 如果原parent不为空
- if (this._parent != null) {
- // 将节点从原parent节点中摘除
- let i = this._parent.children.indexOf(this);
- this._parent.children.splice(i, 1);
- }
- this._parent = v;
- this.update();
- // 如果新parent不为空
- if (this._parent != null) {
- // 将节点加入到新parent节点中
- this._parent.children.push(this);
- this._parent.children.sort(SGraphItem.sortItemZOrder);
- }
- } // Set parent()
- /** 子节点 */
- children: SGraphItem[] = [];
- /** Z轴顺序 */
- private _zOrder: number = 0;
- get zOrder(): number {
- return this._zOrder;
- } // Get zOrder
- set zOrder(v: number) {
- this._zOrder = v;
- if (this._parent != null) {
- this._parent.children.sort(SGraphItem.sortItemZOrder);
- }
- this.update();
- } // Set zOrder
- /** 位置 */
- pos: SPoint = new SPoint(0, 0);
- /** X轴坐标 */
- get x(): number {
- return this.pos.x;
- } // Get x
- set x(v: number) {
- if (this.pos.x == v) {
- return;
- }
- let old = this.pos.x;
- this.pos.x = v;
- this.update();
- } // Set x
- /** Y轴坐标 */
- get y(): number {
- return this.pos.y;
- } // Get y
- set y(v: number) {
- if (this.pos.y == v) {
- return;
- }
- let old = this.pos.y;
- this.pos.y = v;
- this.update();
- } // Set y
- /** 缩放比例 */
- scale: number = 1;
- /** 放缩反比例 */
- private _inverseScale: number = 1;
- get inverseScale(): number {
- return this._inverseScale;
- } // Get inverseScale
- /** 旋转角度 */
- _rotate: number = 0;
- get rotate(): number {
- return this._rotate;
- } // Get rotate
- set rotate(v: number) {
- this._rotate = v;
- this.update();
- } // Set rotate
- /** 是否可见 */
- private _visible: boolean = true;
- get visible(): boolean {
- return this._visible;
- } // Get visible
- set visible(v: boolean) {
- this._visible = v;
- this.update();
- } // Set visible
- /** 是否可以移动 */
- moveable: boolean = false;
- /** 是否正在移动 */
- private _isMoving = false;
- /** 是否可用 */
- enabled: boolean = true;
- /** 是否可被选中 */
- selectable = false;
- /** 是否被选中 */
- protected _selected = false;
- get selected(): boolean {
- return this._selected && this.selectable && this.enabled;
- } // Get selected
- set selected(value: boolean) {
- // 如果选择状态未变更
- if (this.selected == value) {
- return;
- }
- this._selected = value;
- this.update();
- } // Set selected
- /** 是否进行变形 */
- isTransform = true;
- /** 鼠标按下时位置 */
- private _mouseDownPos = new SPoint();
- /** 鼠标样式 */
- cursor: string = "default";
- /** 保存上一次的grabitem */
- private _lastGrab: SGraphItem | null = null;
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 函数
- /**
- * 构造函数
- *
- * @param parent 指向父对象
- */
- constructor(parent: SGraphItem | null = null) {
- super();
- if (parent) {
- this.parent = parent;
- }
- } // Function constructor()
- /**
- * Item绘制框架
- *
- * @param painter painter对象
- * @param rect 绘制区域
- */
- onPaint(painter: SPainter, rect: SRect): void {
- this.onDraw(painter);
- for (let item of this.children) {
- // 如果item不可见
- if (!item.visible) {
- continue;
- }
- // item所占矩阵与要刷新的矩阵相交则刷新,否则不刷
- // if (item.boundingRect()--rect){
- //
- // }
- // 保存画布状态
- painter.save();
- try {
- // item位移到指定位置绘制
- painter.translate(item.x, item.y);
- painter.scale(item.scale, item.scale);
- painter.rotate(item.rotate);
- // 如果不进行变形处理,则取消painter的变型操作
- if (!item.isTransform) {
- let matrix = painter.worldTransform;
- item._inverseScale = 1.0 / matrix.a;
- painter.scale(item._inverseScale, item._inverseScale);
- }
- // 设置绘制区域
- // canvas.clip(item.boundingRect())
- // rect 调整 宽度高度取最小值 根据pos位移
- // 绘制item
- item.onPaint(painter, rect);
- } catch (e) {
- console.log(e);
- }
- // 恢复画布状态
- painter.restore();
- }
- } // Function onPaint()
- /**
- * Item绘制操作
- *
- * @param painter painter对象
- */
- onDraw(painter: SPainter): void {} // Function onDraw()
- /**
- * 隐藏对象
- */
- hide(): void {
- this.visible = false;
- } // Function hide()
- /**
- * 显示对象
- */
- show(): void {
- this.visible = true;
- } // Function show()
- /**
- * 更新Item
- */
- update(): void {
- if (null != this.scene) {
- const view = this.scene.view;
- if (null != view) {
- view.update();
- }
- }
- } // Function update()
- /**
- * Item对象边界区域
- *
- * @return 对象边界区域
- */
- boundingRect(): SRect {
- return new SRect(0, 0, 10, 10);
- } // Function boundingRect()
- /**
- * 移动item到指定位置
- *
- * @param x 新位置的x坐标
- * @param y 新位置的y坐标
- */
- moveTo(x: number, y: number): void {
- this.x = x;
- this.y = y;
- } // moveTo()
- /**
- * 判断item是否包含点x,y
- *
- * @param x 横坐标(当前item)
- * @param y 纵坐标(当前item)
- *
- * @return boolean
- */
- contains(x: number, y: number): boolean {
- return this.boundingRect().contains(x, y);
- } // Function contains()
- /**
- * 获得item的路径节点列表。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
- *
- * @return *[]
- */
- itemPath(): SGraphItem[] {
- if (this.parent != null) {
- let list = this.parent.itemPath();
- list.push(this);
- return list;
- }
- return [this];
- } // Function itemPath()
- /**
- * 将场景中的xy坐标转换成item坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
- *
- * @param x 场景中的横坐标
- * @param y 场景中的纵坐标
- *
- * @return 在item中的坐标
- */
- mapFromScene(x: number, y: number): SPoint {
- const m = this.scene2itemMattrix();
- return new SPoint(x, y).matrixTransform(m.inversed());
- } // Function mapFromScene()
- /**
- * 将item中的xy坐标转换成场景坐标。(该节点被加载到场景中,如果未被加载到场景中,计算会出错)
- *
- * @param x item中的横坐标
- * @param y item中的纵坐标
- *
- * @return 在场景中的坐标
- */
- mapToScene(x: number, y: number): SPoint {
- if (this.parent == null) {
- return new SPoint(x, y);
- }
- const m = this.scene2itemMattrix();
- return new SPoint(x, y).matrixTransform(m);
- } // Function mapToScene()
- /**
- * 场景对象到item对象的转换矩阵
- *
- * @return 转换矩阵
- */
- scene2itemMattrix(): SMatrix {
- let m = new SMatrix();
- let list = this.itemPath();
- for (let item of list) {
- m.translate(item.x, item.y);
- m.scale(item.scale, item.scale);
- m.rotate(item.rotate);
- // 如果不进行变形处理,则取消painter的变型操作
- if (!item.isTransform) {
- m.scale(item._inverseScale, item._inverseScale);
- }
- }
- return m;
- }
- // =================================================================================================================
- // 事件
- /**
- * 鼠标单击事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onClick(event: SMouseEvent): boolean {
- for (let i = this.children.length - 1; i >= 0; i--) {
- let item = this.children[i];
- if (!this.acceptEvent() || !item.visible) {
- continue;
- }
- let ce = SGraphItem.toChildMouseEvent(item, event);
- if (item.contains(ce.x, ce.y) && item.onClick(ce)) {
- // 如果点在子项目上且子项目处理了事件
- return true;
- }
- }
- return false;
- } // Function onClick()
- /**
- * 鼠标双击事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onDoubleClick(event: SMouseEvent): boolean {
- for (let i = this.children.length - 1; i >= 0; i--) {
- let item = this.children[i];
- if (!this.acceptEvent() || !item.visible) {
- continue;
- }
- let ce = SGraphItem.toChildMouseEvent(item, event);
- if (item.contains(ce.x, ce.y) && item.onDoubleClick(ce)) {
- // 如果点在子项目上且子项目处理了事件
- return true;
- }
- }
- return false;
- } // Function onDoubleClick()
- /**
- * 鼠标按下事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onMouseDown(event: SMouseEvent): boolean {
- for (let i = this.children.length - 1; i >= 0; i--) {
- try {
- let item = this.children[i];
- if (!this.acceptEvent() || !item.visible) {
- continue;
- }
- let ce = SGraphItem.toChildMouseEvent(item, event);
- if (item.contains(ce.x, ce.y) && item.onMouseDown(ce)) {
- // 如果点在子项目上且子项目处理了事件
- return true;
- }
- } catch (e) {
- console.log(e);
- }
- }
- // 选择
- let select = false;
- if (this.selectable) {
- select = this.clickSelect(event);
- }
- // 移动
- if (this.moveable) {
- this._mouseDownPos = new SPoint(event.x, event.y);
- this._isMoving = true;
- if (this.scene) {
- this._lastGrab = this.scene.grabItem;
- }
- this.grabItem(this);
- return true;
- }
- return select;
- } // Function onMouseDown()
- /**
- * 鼠标移动事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onMouseMove(event: SMouseEvent): boolean {
- for (let i = this.children.length - 1; i >= 0; i--) {
- let item = this.children[i];
- if (!this.acceptEvent() || !item.visible) {
- continue;
- }
- let ce = SGraphItem.toChildMouseEvent(item, event);
- if (item.contains(ce.x, ce.y) && item.onMouseMove(ce)) {
- // 如果点在子项目上且子项目处理了事件
- return true;
- }
- }
- if (this.scene && this.scene.view) {
- this.scene.view.cursor = this.cursor;
- }
- if (
- event.buttons & SMouseButton.LeftButton &&
- this.moveable &&
- this._isMoving
- ) {
- let old = new SPoint(this.pos.x, this.pos.y);
- const mp = this.toParentChange(
- event.x - this._mouseDownPos.x,
- event.y - this._mouseDownPos.y
- );
- this.moveTo(this.pos.x + mp.x, this.pos.y + mp.y);
- this.$emit("onMove", old, this.pos);
- }
- // 处理hover
- const scene = this.scene;
- if (null != scene) {
- if (scene.hoverItem == null || scene.hoverItem !== this) {
- if (scene.hoverItem != null) {
- scene.hoverItem.onMouseLeave(event);
- }
- this.onMouseEnter(event);
- scene.hoverItem = this;
- }
- }
- return true;
- } // Function onMouseMove()
- /**
- * 释放鼠标事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onMouseUp(event: SMouseEvent): boolean {
- for (let i = this.children.length - 1; i >= 0; i--) {
- let item = this.children[i];
- if (!this.acceptEvent() || !item.visible) {
- continue;
- }
- let ce = SGraphItem.toChildMouseEvent(item, event);
- if (item.contains(ce.x, ce.y) && item.onMouseUp(ce)) {
- // 如果点在子项目上且子项目处理了事件
- return true;
- }
- }
- this._isMoving = false;
- this.releaseItem();
- if (this.scene) {
- this.scene.grabItem = this._lastGrab;
- }
- return false;
- } // Function onMouseUp()
- /**
- * 鼠标进入事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onMouseEnter(event: SMouseEvent): boolean {
- return false;
- } // Function onMouseEnter()
- /**
- * 鼠标离开事件
- *
- * @param event 保存事件参数
- * @return boolean
- */
- onMouseLeave(event: SMouseEvent): boolean {
- return false;
- } // Function onMouseLeave()
- /**
- * 上下文菜单事件
- *
- * @param event 事件参数
- */
- onContextMenu(event: SMouseEvent): boolean {
- for (let i = this.children.length - 1; i >= 0; i--) {
- let item = this.children[i];
- if (!this.acceptEvent() || !item.visible) {
- continue;
- }
- let ce = SGraphItem.toChildMouseEvent(item, event);
- if (item.contains(ce.x, ce.y) && item.onContextMenu(ce)) {
- // 如果点在子项目上且子项目处理了事件
- return true;
- }
- }
- return false;
- } // Function onContextMenu()
- /**
- * 按键按下事件
- *
- * @param event 事件参数
- */
- onKeyDown(event: KeyboardEvent): void {} // Function onKeyDown()
- /**
- * 按键press事件
- *
- * @param event 事件参数
- */
- onKeyPress(event: KeyboardEvent): void {} // Function onKeyPress()
- /**
- * 按键松开事件
- *
- * @param event 事件参数
- */
- onKeyUp(event: KeyboardEvent): void {} // Function onKeyUp()
- /**
- * 取消操作item事件
- *
- * */
- cancelOperate(): void {} // Function cancelOperate()
- /**
- * 返回item对应的数据对象
- *
- * */
- toData(): any | null {
- return null;
- } // Function toData()
- /**
- * 移动item后的处理,计算其他信息,将原点置为场景原点
- *
- * @param x x坐标
- * @param y y坐标
- * */
- moveToOrigin(x: number, y: number): void {
- if (this.children && this.children.length) {
- this.children.forEach(it => {
- it.moveToOrigin(x, y);
- });
- }
- } // Function moveToOrigin()
- // =================================================================================================================
- // 私有方法
- /**
- * 按ZOrder排序
- *
- * @param a 比较元素1
- * @param b 比较元素2
- * @return {number}
- */
- private static sortItemZOrder(a: SGraphItem, b: SGraphItem): number {
- return a.zOrder - b.zOrder;
- } // Function sortItemZOrder()
- /**
- * 鼠标事件转子对象鼠标事件
- *
- * @param child 子对象
- * @param event 事件参数
- * @return 子对象鼠标事件
- */
- private static toChildMouseEvent(
- child: SGraphItem,
- event: SMouseEvent
- ): SMouseEvent {
- let ce = new SMouseEvent(event);
- ce.matrix.translate(child.x, child.y);
- ce.matrix.scale(child.scale, child.scale);
- ce.matrix.rotate(0, 0, child.rotate);
- if (!child.isTransform) {
- ce.matrix.scale(child._inverseScale, child._inverseScale);
- }
- const mp = new SPoint(event.offsetX, event.offsetY).matrixTransform(
- ce.matrix.inversed()
- );
- ce.x = mp.x;
- ce.y = mp.y;
- return ce;
- } // Function toChildMouseEvent()
- /**
- * 锁定item
- *
- * @param item 被锁定的item
- */
- protected grabItem(item: SGraphItem): void {
- if (this.scene != null) {
- this.scene.grabItem = item;
- }
- } // Function grabItem
- /**
- * 释放被锁定的item
- */
- protected releaseItem(): void {
- if (this.scene != null) {
- this.scene.grabItem = null;
- }
- } // Function grabItem
- /**
- * 计算点在父节点的位置
- *
- * @param x X轴
- * @param y Y轴
- * @return 在父节点的位置
- */
- private toParentChange(x: number, y: number): SPoint {
- const m = new SMatrix();
- m.scale(this.scale, this.scale);
- if (!this.isTransform) {
- m.scale(this._inverseScale, this._inverseScale);
- }
- m.rotate(this.rotate);
- const mp = new SPoint(x, y).matrixTransform(m);
- return new SPoint(mp.x, mp.y);
- }
- /**
- * 判断是否处理事件
- *
- * @return true: 处理事件,否则不处理
- */
- private acceptEvent(): boolean {
- return this.visible && this.enabled;
- } // Function acceptEvent()
- /**
- * 点选item对象
- *
- * @param event 事件参数
- */
- private clickSelect(event: SMouseEvent): boolean {
- // 如果Item不可被选中,或没有按下鼠标左键,则直接返回
- if (!this.selectable || event.buttons != SMouseButton.LeftButton) {
- return false;
- }
- const scene = this.scene;
- if (scene == null) {
- return false;
- }
- // 如果按下Ctrl键,只改变当前item的选择标志
- if (event.ctrlKey) {
- scene.selectContainer.toggleItem(this);
- } else {
- scene.selectContainer.setItem(this);
- }
- return true;
- } // Function clickSelect()
- } // Class SGraphItem
|