<template>
    <div>
        <el-button @click="show">展示</el-button>
        <el-button @click="create">创建</el-button>
        <el-button @click="edit">编辑</el-button>
        <canvas id="editLine" width="740" height="400"  tabindex="0" />
    </div>
</template>
<script lang='ts'>
    import {SGraphItem, SGraphScene, SGraphView} from "@saga-web/graph/";
    import {SMouseEvent} from "@saga-web/base/";
    import {SColor, SLine, SPainter, SPoint, SRect} from "@saga-web/draw";
    import {SRelationState} from "@saga-web/big/lib/enums/SRelationState";
    import {SMathUtil} from "@saga-web/big/lib/utils/SMathUtil";

    /**
     * 直线item
     *
     * @author  张宇(taohuzy@163.com)
     * */

    class SLineItem extends SGraphItem {
        /** X坐标最小值  */
        private minX = Number.MAX_SAFE_INTEGER;
        /** X坐标最大值  */
        private maxX = Number.MIN_SAFE_INTEGER;
        /** Y坐标最小值  */
        private minY = Number.MAX_SAFE_INTEGER;
        /** Y坐标最大值  */
        private maxY = Number.MIN_SAFE_INTEGER;

        /** 线段   */
        _line: SPoint[] = [];
        get line(): SPoint[] {
            return this._line;
        }
        set line(arr: SPoint[]) {
            this._line = arr;
            this._xyzListToSPointList(arr);
            this.update();
        }

        /** 是否完成绘制  */
        _status: SRelationState = SRelationState.Create;
        get status(): SRelationState {
            return this._status;
        }
        set status(v: SRelationState) {
            this._status = v;
            this.update();
        }

        /** 线条颜色    */
        _strokeColor: string = "#000000";
        get strokeColor(): string {
            return this._strokeColor;
        }
        set strokeColor(v: string) {
            this._strokeColor = v;
            this.update();
        }

        /** 填充色 */
        _fillColor: string = "#2196f3";
        get fillColor(): string {
            return this._fillColor;
        }
        set fillColor(v: string) {
            this._fillColor = v;
            this.update();
        }

        /** 线条宽度    */
        _lineWidth: number = 1;
        get lineWidth(): number {
            return this._lineWidth;
        }
        set lineWidth(v: number) {
            this._lineWidth = v;
            this.update();
        }

        /** 拖动灵敏度   */
        dis: number = 10;

        /** 拖动灵敏度   */
        sceneDis: number = 10;

        /** 当前点索引   */
        curIndex: number = -1;

        /**
         * 构造函数
         *
         * @param   parent  父级
         * @param   line    坐标集合
         * */
        constructor(parent: SGraphItem | null, line: SPoint[]);

        /**
         * 构造函数
         *
         * @param   parent  父级
         * @param   point   第一个点坐标
         * */
        constructor(parent: SGraphItem | null, point: SPoint);

        /**
         * 构造函数
         *
         * @param   parent  父级
         * @param   l       坐标集合|第一个点坐标
         * */
        constructor(parent: SGraphItem | null, l: SPoint | SPoint[]) {
            super(parent);
            if (l instanceof SPoint) {
                this.line.push(l);
            } else {
                this.line = l;
            }
        }

        /**
         * 添加点至数组中
         *
         * @param   p       添加的点
         * @param   index   添加到的索引
         * */
        private addPoint(p: SPoint): void {
            if (this.line.length < 2) {
                this.line.push(p);
            } else {
                this.line[1] = p;
                this.status = SRelationState.Normal;
            }
            this._xyzListToSPointList(this.line);
            this.update();
        } // Function addPoint()

        /**
         * 鼠标双击事件
         *
         * @param	event         事件参数
         * @return	boolean
         */
        onDoubleClick(event: SMouseEvent): boolean {
            if (this.contains(event.x, event.y)) { // 判断是否点击到线上
                if (this.status == SRelationState.Normal) {
                    if (this.scene) {
                        this.scene.grabItem = this;
                    }
                    this.status = SRelationState.Edit;
                } else if (this.status = SRelationState.Edit) {
                    this.status = SRelationState.Normal;
                }
                this.update();
            }
            return true;
        } // Function onDoubleClick()

        /**
         * 鼠标按下事件
         *
         * @param   event   鼠标事件
         * @return  是否处理事件
         * */
        onMouseDown(event: SMouseEvent): boolean {
            if (this.status == SRelationState.Normal) {
                return super.onMouseDown(event);
            } else if (this.status == SRelationState.Edit) {
                // 判断是否点击到端点上(获取端点索引值)
                this.findNearestPoint(new SPoint(event.x, event.y));
            } else if (this.status == SRelationState.Create) {
                this.addPoint(new SPoint(event.x, event.y));
                return true;
            }
            this.$emit("mousedown");
            return true;
        } // Function onMouseDown()

        /**
         * 鼠标抬起事件
         *
         * @param	event         事件参数
         * @return	boolean
         */
        onMouseUp(event: SMouseEvent): boolean {
            if (this._status == SRelationState.Edit) {
                this.curIndex = -1;
            }
            return true;
        } // Function onMouseUp()

        /**
         * 鼠标移动事件
         *
         * @param   event   鼠标事件
         * @return  是否处理事件
         * */
        onMouseMove(event: SMouseEvent): boolean {
            if (this.status == SRelationState.Create) {
                if (this.line[0] instanceof SPoint) {
                    this.line[1] = new SPoint(event.x, event.y);
                }
            } else if (this.status == SRelationState.Edit) {
                if (-1 != this.curIndex) {
                    this.line[this.curIndex].x = event.x;
                    this.line[this.curIndex].y = event.y;
                }
            } else {
                return super.onMouseMove(event);
            }
            this._xyzListToSPointList(this.line);
            this.update();
            return true;
        } // Function onMouseMove()

        /**
         * 获取点击点与Point[]中的点距离最近点
         *
         * @param   p   鼠标点击点
         * */
        findNearestPoint(p: SPoint): void {
            let len = this.sceneDis;
            for (let i = 0; i < 2; i++) {
                let dis = SMathUtil.pointDistance(
                    p.x,
                    p.y,
                    this.line[i].x,
                    this.line[i].y
                );
                if (dis < len) {
                    len = dis;
                    this.curIndex = i;
                }
            }
        } // Function findNearestPoint()

        /**
         * xyz数据转换为SPoint格式函数；获取外接矩阵参数
         *
         * @param arr    外层传入的数据PointList
         */
        protected _xyzListToSPointList(arr: SPoint[]): void {
            if (arr.length) {
                this.minX = Number.MAX_SAFE_INTEGER;
                this.maxX = Number.MIN_SAFE_INTEGER;
                this.minY = Number.MAX_SAFE_INTEGER;
                this.maxY = Number.MIN_SAFE_INTEGER;
                arr.forEach(it => {
                    let x = it.x,
                        y = it.y;
                    if (x < this.minX) {
                        this.minX = x;
                    }
                    if (y < this.minY) {
                        this.minY = y;
                    }
                    if (x > this.maxX) {
                        this.maxX = x;
                    }
                    if (y > this.maxY) {
                        this.maxY = y;
                    }
                });
            }
        }

        /**
         * 判断点是否在区域内
         *
         * @param   x
         * @param   y
         * @return  true-是
         */
        contains(x: number, y: number): boolean {
            if (this.line.length == 2) {
                let p = new SPoint(x, y);
                if (
                    SMathUtil.pointToLine(p, new SLine(this.line[0], this.line[1])).MinDis <
                    this.dis
                ) {
                    return true;
                }
            }
            return false;
        } // Function contains()

        /**
         * 取消操作item事件
         *
         * */
        cancelOperate(): void {
            if (this.status == SRelationState.Create) {
                this.parent = null;
                this.releaseItem();
            } else if (this.status == SRelationState.Edit) {
                this.status = SRelationState.Normal;
                this.releaseItem();
            }
        } // Function cancelOperate()

        /**
         * Item对象边界区域
         *
         * @return	SRect
         */
        boundingRect(): SRect {
            return new SRect(
                this.minX,
                this.minY,
                this.maxX - this.minX,
                this.maxY - this.minY
            );
        } // Function boundingRect()

        /**
         * Item绘制操作
         *
         * @param   painter painter对象
         */
        onDraw(painter: SPainter): void {
            this.sceneDis = painter.toPx(this.dis);
            painter.pen.lineWidth = painter.toPx(this.lineWidth);
            painter.pen.color = new SColor(this.strokeColor);
            if (this.line.length == 2) {
                // 绘制外轮廓
                // painter.brush.color = SColor.Transparent;
                // painter.pen.color = new SColor("#128eee");
                // painter.drawRect(this.boundingRect());

                // 绘制直线
                painter.pen.color = new SColor(this.strokeColor);
                painter.drawLine(this.line[0], this.line[1]);

                if (this.status == SRelationState.Edit || this.status == SRelationState.Create) {
                    // 绘制端点
                    painter.brush.color = new SColor(this.fillColor);
                    painter.drawCircle(this.line[0].x, this.line[0].y, painter.toPx(5));
                    painter.drawCircle(this.line[1].x, this.line[1].y, painter.toPx(5));
                }
            } else if (this.line.length == 1) {
                if (this.status == SRelationState.Edit || this.status == SRelationState.Create) {
                    // 绘制端点
                    painter.brush.color = new SColor(this.fillColor);
                    painter.drawCircle(this.line[0].x, this.line[0].y, painter.toPx(5));
                }
            }
        } // Function onDraw()
    } // Class SLineItem

    export default {
        data() {
            return {
                scene: null,
                view: null
            };
        },
        mounted(): void {
            this.view = new SGraphView("editLine");
        },
        methods: {
            show() {
                const scene = new SGraphScene();
                this.view.scene = scene;
                const line: SPoint[] = [new SPoint(100, 100), new SPoint(300, 300)];
                const lineItem = new SLineItem(null, line);
                lineItem.status = SRelationState.Normal;
                scene.addItem(lineItem);
                this.view.fitSceneToView();
            },
            create() {
                const scene = new SGraphScene();
                this.view.scene = scene;
                const lineItem = new SLineItem(null, [] );
                lineItem.status = SRelationState.Create;
                scene.addItem(lineItem);
                scene.grabItem = lineItem;
                this.view.fitSceneToView();
            },
            edit() {
                const scene = new SGraphScene();
                this.view.scene = scene;
                const line: SPoint[] = [new SPoint(100, 100), new SPoint(300, 300)];
                const lineItem = new SLineItem(null, line);
                lineItem.status = SRelationState.Edit;
                scene.addItem(lineItem);
                scene.grabItem = lineItem;
                this.view.fitSceneToView();
            }
        }
    };
</script>