<template>
    <!-- 未做多语言 -->
    <div class="mark-stage">
        <vuescroll ref="canvasScroll">
            <!-- canvas部分 -->
            <div class="container-box">
                <div id="container" @mousemove="canvasMouseMove" @mousedown="canvasMouseDown" @mouseup="canvasMouseUp"></div>
            </div>
        </vuescroll>
    </div>
</template>

<script>
import Konva from 'konva'
export default {
    name: 'MarkCanvas',
    props: {
        // 当前鼠标操作类型
        mouseStatus: {
            type: String,
            default: 'move',
            required: true
        },
        //canvas主图（eg：学生作答数据）
        bgImg: {
            type: [String, Object],
            default: ''
        },
        //canvas绘制图片的数据（eg:添加表情包）
        drawImgData: {
            type: [String, Object],
            default: ''
        }
    },
    data() {
        return {
            stage: undefined,
            orgLayer: undefined,
            markLayer: undefined,
            tr: undefined,
            scaleDefault: 1,
            maxScale: 5,
            minScale: 0.2,
            scaleStep: 0.2,
            imgWidth: 0,
            imgHeight: 0,
            isMouseDown: false,
            clickPoint: {
                x: 0,
                y: 0
            },
            // mouseStatus: 'move', //move：移动  rect:画矩形 resize:调整图形
            resizeBefore: '',
            rect: undefined,
            oval: undefined,
            arrow: undefined,
            text: undefined,
            line: undefined,
            img: undefined,
            isDltText: false,
        }
    },
    methods: {
        uuid() {
            function S4() {
                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
            }
            return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4())
        },
        move(index) {
            this.activeIcon = index
            this.mouseStatus = 'move'
        },
        drawImg(imgIndex) {
            // this.activeIcon = imgIndex
            // this.curImg = new Image()
            // this.curImg.src = this.imgs[imgIndex]
            // this.curImg.onload = () => {
            //     this.mouseStatus = 'img'
            //     this.startImg({ x: 100, y: 100 })
            // }
        },
        startImg(current) {
            let _this = this
            this.img = new Konva.Image({
                id: this.uuid(),
                draggable: false,
                strokeScaleEnabled: false,
                image: _this.curImg,
                width: 80,
                height: 80,
                x: current.x,
                y: current.y
            })
            // 监听点击事件设置选中状态
            this.img.on('click', (evt) => {
                _this.resizeBefore = _this.mouseStatus == 'resize' ? _this.resizeBefore : _this.mouseStatus//记录resize之前的状态
                _this.mouseStatus = 'resize'
                evt.target.draggable(true)
                evt.cancelBubble = true //阻止事件冒泡 
                _this.tr.nodes([evt.target])
                _this.markLayer.add(_this.tr)
            })
            // 优化一些绘制逻辑
            this.img.on('mouseout', (evt) => {
                evt.cancelBubble = true //阻止事件冒泡
                evt.target.draggable(false)
                let nodes = _this.tr.nodes()
                if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore
            })
            // this.img.zIndex(1)
            this.markLayer.add(this.img)
            this.stage.add(this.markLayer)
            this.img = null
        },
        drawText(index) {
            this.activeIcon = index
            this.mouseStatus = 'text'
        },
        startText(current) {
            let _this = this
            let nodes = this.tr.nodes()
            if (nodes.length > 0) return
            if (!this.text) {
                this.text = new Konva.Text({
                    id: this.uuid(),
                    fontSize: 16,
                    text: '',
                    fill: 'red',
                    lineHeight: 1.5,
                    width: 180,
                    height: 30,
                    x: _this.clickPoint.x / _this.scaleDefault,
                    y: _this.clickPoint.y / _this.scaleDefault,
                    draggable: false
                })
                // 监听点击事件设置选中状态
                this.text.on('click', (evt) => {
                    _this.resizeBefore = _this.mouseStatus == 'resize' ? _this.resizeBefore : _this.mouseStatus//记录resize之前的状态
                    _this.mouseStatus = 'resize'
                    evt.target.draggable(true)
                    evt.cancelBubble = true //阻止事件冒泡 
                    _this.tr.nodes([evt.target])
                    _this.markLayer.add(_this.tr)
                })
                this.text.on('mouseout', (evt) => {
                    evt.cancelBubble = true //阻止事件冒泡
                    evt.target.draggable(false)
                    let nodes = _this.tr.nodes()
                    if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore
                })
                this.text.on('dblclick dbltap', (evt) => {
                    let nodes = _this.tr.nodes()
                    if (nodes && nodes.length > 0) {
                        let text = nodes[0]
                        let textPosition = text.getAbsolutePosition()
                        let stageBox = _this.stage.container().getBoundingClientRect()
                        let areaPosition = {
                            x: stageBox.left + textPosition.x,
                            y: stageBox.top + textPosition.y,
                        }
                        let textarea = document.createElement('textarea');
                        document.body.appendChild(textarea)

                        textarea.value = text.text()
                        textarea.style.position = 'absolute'
                        textarea.style.top = areaPosition.y + 'px'
                        textarea.style.left = areaPosition.x + 'px'
                        textarea.style.background = 'transparent'
                        textarea.style.color = 'red'
                        textarea.style.fontSize = '16px'
                        textarea.style.borderColor = 'red'
                        textarea.style.boxShadow = 'none'
                        textarea.style.height = text.height() + 'px'
                        textarea.className = 'textarea'
                        textarea.style.width = text.width()

                        textarea.focus()
                        _this.isDltText = true //设置删除按键的状态，文本框状态应该是删除文字不能删除图形
                        text.hide()
                        _this.tr.hide()
                        textarea.addEventListener('input', () => {
                            textarea.style.height = 'auto'
                            textarea.style.height = textarea.scrollHeight + 'px'
                            _this.isDltText = true
                        })
                        textarea.addEventListener('blur', function (e) {
                            if (textarea.value) {
                                text.text(textarea.value)
                                text.width(textarea.clientWidth)
                                text.height(textarea.scrollHeight)
                                text.show()

                                _this.markLayer.draw()
                            } else {
                                text.remove()
                            }
                            _this.tr.nodes([])
                            _this.tr.show()
                            document.body.removeChild(textarea)
                            _this.isDltText = false
                        })
                    }
                })
            } else {
                this.text.x(current.x)
                this.text.y(current.y)
            }
            // this.text.zIndex(100)
            this.tr.nodes([this.text])
            this.markLayer.add(this.tr)
            this.markLayer.add(this.text)
            this.stage.add(this.markLayer)
        },
        drawLine(index) {
            this.activeIcon = index
            this.mouseStatus = 'line'
        },
        startLine(current) {
            let _this = this
            if (!this.line) {
                this.line = new Konva.Line({
                    id: this.uuid(),
                    stroke: 'red',
                    strokeWidth: 3,
                    draggable: false,
                    tension: 1,
                    points: [_this.clickPoint.x / _this.scaleDefault, _this.clickPoint.y / _this.scaleDefault]
                })
                // 监听点击事件设置选中状态
                this.line.on('click', (evt) => {
                    _this.resizeBefore = _this.mouseStatus == 'resize' ? _this.resizeBefore : _this.mouseStatus//记录resize之前的状态
                    _this.mouseStatus = 'resize'
                    evt.target.draggable(true)
                    evt.cancelBubble = true //阻止事件冒泡 
                    _this.tr.nodes([evt.target])
                    _this.markLayer.add(_this.tr)
                })
                // 优化一些绘制逻辑
                this.line.on('mouseout', (evt) => {
                    evt.cancelBubble = true //阻止事件冒泡
                    evt.target.draggable(false)
                    let nodes = _this.tr.nodes()
                    if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore
                })
            } else {
                this.line.points(this.line.points().concat([current.x / _this.scaleDefault, current.y / _this.scaleDefault]))
            }
            // this.line.zIndex(1)
            this.markLayer.add(this.line)
            this.stage.add(this.markLayer)
        },
        drawArrow(index) {
            this.activeIcon = index
            this.mouseStatus = 'arrow'
        },
        // 绘制箭头
        startArrow(current) {
            let _this = this
            if (!this.arrow) {
                this.arrow = new Konva.Arrow({
                    id: this.uuid(),
                    fill: 'transparent',
                    stroke: 'red',
                    strokeWidth: 4,
                    pointerLength: 10,
                    pointerWidth: 8,
                    draggable: false,
                    fill: 'red',
                    lineCap: 'round',
                    strokeScaleEnabled: false,
                    points: [_this.clickPoint.x / _this.scaleDefault, _this.clickPoint.y / _this.scaleDefault, (current.x) / _this.scaleDefault, (current.y) / _this.scaleDefault]
                })
                // 监听点击事件设置选中状态
                this.arrow.on('click', (evt) => {
                    _this.resizeBefore = _this.mouseStatus == 'resize' ? _this.resizeBefore : _this.mouseStatus//记录resize之前的状态
                    _this.mouseStatus = 'resize'
                    evt.target.draggable(true)
                    evt.cancelBubble = true //阻止事件冒泡 
                    _this.tr.nodes([evt.target])
                    _this.markLayer.add(_this.tr)
                })
                // 优化一些绘制逻辑
                this.arrow.on('mouseout', (evt) => {
                    evt.cancelBubble = true //阻止事件冒泡
                    evt.target.draggable(false)
                    let nodes = _this.tr.nodes()
                    if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore
                })
            } else {
                this.arrow.points([_this.clickPoint.x / _this.scaleDefault, _this.clickPoint.y / _this.scaleDefault, (current.x) / _this.scaleDefault, (current.y) / _this.scaleDefault])
            }
            // this.arrow.zIndex(1)
            this.markLayer.add(this.arrow)
            this.stage.add(this.markLayer)
        },
        drawOval(index) {
            this.activeIcon = index
            this.mouseStatus = 'oval'
        },
        startOval(current) {
            let _this = this
            //判断rect是否初始化
            let rx = (current.x - _this.clickPoint.x) / _this.scaleDefault * 0.5
            let ry = (_this.clickPoint.y - current.y) / _this.scaleDefault * 0.5
            if (!this.oval) {
                this.oval = new Konva.Ellipse({
                    id: this.uuid(),
                    // x: _this.clickPoint.x / _this.scaleDefault,
                    // y: _this.clickPoint.y / _this.scaleDefault,
                    x: _this.clickPoint.x,
                    y: _this.clickPoint.y,
                    radiusX: rx > 0 ? rx : -rx,
                    radiusY: ry,
                    fill: 'transparent',
                    stroke: 'red',
                    strokeWidth: 2,
                    draggable: false,
                    rotation: rx > 0 ? 0 : 180,
                    strokeScaleEnabled: false
                })
                // 监听点击事件设置选中状态
                this.oval.on('click', (evt) => {
                    _this.resizeBefore = _this.mouseStatus == 'resize' ? _this.resizeBefore : _this.mouseStatus//记录resize之前的状态
                    _this.mouseStatus = 'resize'
                    evt.target.draggable(true)
                    evt.cancelBubble = true //阻止事件冒泡 
                    _this.tr.nodes([evt.target])
                    _this.markLayer.add(_this.tr)
                })
                // 优化一些绘制逻辑
                this.oval.on('mouseout', (evt) => {
                    evt.cancelBubble = true //阻止事件冒泡
                    evt.target.draggable(false)
                    let nodes = _this.tr.nodes()
                    if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore
                })
            } else {
                this.oval.x(_this.clickPoint.x / _this.scaleDefault + rx)
                this.oval.y(_this.clickPoint.y / _this.scaleDefault - ry)
                this.oval.radiusX(rx > 0 ? rx : -rx)
                this.oval.radiusY(ry)
                this.oval.rotation(rx > 0 ? 0 : 180)
            }
            this.oval.zIndex(1)
            this.markLayer.add(this.oval)
            this.stage.add(this.markLayer)
        },
        drawIcon(index) {
            this.activeIcon = index
        },
        review(index) {
            this.activeIcon = index
        },
        cancelFull(index) {
            this.activeIcon = index
        },
        //绘制矩形
        drawRect(index) {
            this.activeIcon = index
            this.mouseStatus = 'rect'
        },
        startRect(current) {
            let _this = this
            //判断rect是否初始化
            if (!this.rect) {
                this.rect = new Konva.Rect({
                    id: this.uuid(),
                    x: _this.clickPoint.x / _this.scaleDefault,
                    y: _this.clickPoint.y / _this.scaleDefault,
                    width: (current.x - _this.clickPoint.x) / _this.scaleDefault,
                    height: (current.y - _this.clickPoint.y) / _this.scaleDefault,
                    fill: 'transparent',
                    stroke: 'red',
                    strokeWidth: 2,
                    draggable: false,
                    strokeScaleEnabled: false
                })
                // 监听点击事件设置选中状态
                this.rect.on('click', (evt) => {
                    _this.resizeBefore = _this.mouseStatus == 'resize' ? _this.resizeBefore : _this.mouseStatus//记录resize之前的状态
                    _this.mouseStatus = 'resize'
                    evt.target.draggable(true)
                    evt.cancelBubble = true //阻止事件冒泡
                    //Transformer   
                    _this.tr.nodes([evt.target])
                    _this.markLayer.add(_this.tr)
                })
                // 优化一些绘制逻辑
                this.rect.on('mouseout', (evt) => {
                    evt.cancelBubble = true //阻止事件冒泡
                    evt.target.draggable(false)
                    let nodes = _this.tr.nodes()
                    if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore
                })
            } else {
                this.rect.x(_this.clickPoint.x / _this.scaleDefault)
                this.rect.y(_this.clickPoint.y / _this.scaleDefault)
                this.rect.width((current.x - _this.clickPoint.x) / _this.scaleDefault)
                this.rect.height((current.y - _this.clickPoint.y) / _this.scaleDefault)
            }
            this.rect.zIndex(1)
            this.markLayer.add(this.rect)
            this.stage.add(this.markLayer)
        },
        //防抖函数
        debounce(func, delay) {
            return function () {
                window.clearTimeout(window.timeout)
                window.timeout = setTimeout(() => {
                    clearTimeout(window.timeout)
                    func.apply(this, arguments)
                }, delay)
            }
        },
        //还原比例
        restore() {
            this.scaleDefault = 1
            this.myScale()
        },
        // 缩小
        smaller() {
            this.scaleDefault -= this.scaleStep
            if (this.scaleDefault < this.minScale) {
                this.scaleDefault += this.scaleStep
                //函数防抖，优化重复提示
                this.debounce(() => {
                    this.$Message.warning('已经缩小到最小比例')
                }, 400)()
            } else {
                this.myScale()
            }
        },
        //放大
        larger() {
            this.scaleDefault += this.scaleStep
            if (this.scaleDefault > this.maxScale) {
                this.scaleDefault -= this.scaleStep
                //函数防抖，优化重复提示
                this.debounce(() => {
                    this.$Message.warning('已经放大到最大比例')
                }, 400)()
            } else {
                this.myScale()
            }
        },
        //还原比例
        restore() {
            this.scaleDefault = 1
            this.myScale()
        },
        myScale() {
            this.stage.children.forEach(item => {
                item.scale({
                    x: this.scaleDefault,
                    y: this.scaleDefault
                })
            })
            this.stage.width(this.imgWidth * this.scaleDefault)
            this.stage.height(this.imgHeight * this.scaleDefault)
        },
        //绑定鼠标滚轮事件，操作缩放功能
        bundleScoll() {
            let stage = document.getElementById('container')
            let _this = this
            stage.addEventListener('mousewheel', function (e) {
                if (e.preventDefault) {
                    e.preventDefault()
                } else {
                    window.event.returnValue == false
                }
                _this.scrollFunc(e)
            }, false) || stage.addEventListener('DOMMouseScroll', function (e) {
                if (e.preventDefault) {
                    e.preventDefault()
                } else {
                    window.event.returnValue == false
                }
                _this.scrollFunc(e)
            }, false)
        },
        //判断鼠标放大还是缩小
        scrollFunc(e) {
            e = e || window.event
            if (e.wheelDelta) { // 判断浏览器IE，谷歌滑轮事件
                if (e.wheelDelta > 0) { // 当滑轮向上滚动时
                    this.larger()
                }
                if (e.wheelDelta < 0) { // 当滑轮向下滚动时
                    this.smaller()
                }
            } else if (e.detail) { // Firefox滑轮事件
                if (e.detail > 0) { // 当滑轮向上滚动时
                    this.larger()
                }
                if (e.detail < 0) { // 当滑轮向下滚动时
                    this.smaller()
                }
            }
        },
        //获取在canvas上的坐标
        getCanvasPoint(x, y) {
            // let canvas = document.getElementById('container')
            let canvas = document.getElementsByClassName('konvajs-content')
            let cs = canvas.length ? canvas[0] : null
            if (cs) {
                let canvasRect = cs.getBoundingClientRect()
                return {
                    x: x - canvasRect.left,
                    y: y - canvasRect.top
                }
            } else {
                return {
                    x, y
                }
            }

        },
        //按下鼠标事件
        canvasMouseDown(e) {
            this.isMouseDown = true
            this.clickPoint = this.getCanvasPoint(e.clientX, e.clientY)
        },
        //鼠标弹起事件
        canvasMouseUp() {
            this.isMouseDown = false
            switch (this.mouseStatus) {
                case 'move':
                    break
                case 'rect':
                    this.rect = null
                    break
                case 'oval':
                    this.oval = null
                    break
                case 'arrow':
                    this.arrow = null
                    break
                case 'text':
                    this.text = null
                    break
                case 'line':
                    this.line = null
                    break
                // case 'img':
                //     this.img = null
                //     break
                default:
                    break
            }
        },
        //鼠标移动事件
        canvasMouseMove(e) {
            if (this.isMouseDown) {
                let current = this.getCanvasPoint(e.clientX, e.clientY)
                switch (this.mouseStatus) {
                    case 'move':
                        this.$refs["canvasScroll"].scrollBy({
                            dx: this.clickPoint.x - current.x,
                            dy: this.clickPoint.y - current.y
                        }, 0)
                        break
                    case 'rect':
                        this.startRect(current)
                        break
                    case 'oval':
                        this.startOval(current)
                        break
                    case 'arrow':
                        this.startArrow(current)
                        break
                    case 'text':
                        this.startText(current)
                        break
                    case 'line':
                        this.startLine(current)
                        break
                    default:
                        break
                }
            }
        },

        //清除所有批注
        clear(index) {
            this.activeIcon = index
            this.markLayer.removeChildren()
            this.stage.add(this.markLayer)
        }
    },
    mounted() {
        let _this = this

        //创建画布
        _this.stage = new Konva.Stage({
            container: 'container',
            id: 'canvas',
            width: 600,
            height: 240
        })
        _this.orgLayer = new Konva.Layer()
        _this.markLayer = new Konva.Layer()
        _this.stage.add(_this.orgLayer)
        _this.stage.add(_this.markLayer)
        _this.orgLayer.batchDraw()
        _this.bundleScoll()
        _this.stage.on('click', (evt) => {
            _this.tr.nodes([])
        })
        _this.stage.on('mouseover', (evt) => {
            let nodes = _this.tr.nodes()
            if (_this.mouseStatus == 'resize' && nodes.length == 0) _this.mouseStatus = _this.resizeBefore

        })

        this.tr = new Konva.Transformer({
            rotateEnabled: false,
            anchorStroke: 'red',
            enabledAnchors: ['top-center', 'top-left', 'top-right', 'middle-left', 'middle-right', 'bottom-left', 'bottom-center', 'bottom-right'],
            anchorSize: 8,
            borderStroke: 'red'
        })
        this.tr.borderEnabled(true)
        this.tr.anchorCornerRadius(10)

    },
    created() {
        //监听删除按键，删除图形
        document.onkeydown = e => {
            if (e.keyCode == 8 && !this.isDltText) {
                let shape = this.tr ? this.tr.nodes() : []
                if (shape.length) {
                    shape[0].remove()
                    this.tr.nodes([])
                }
            }
        }
    },
    watch: {
        bgImg: {
            handler(n, o) {
                this.$nextTick(() => {
                    // this.restore()
                    this.orgLayer.removeChildren()
                    this.markLayer.removeChildren()
                    let imageObj = new Image()
                    let _this = this
                    imageObj.onload = function () {
                        //创建画布
                        _this.imgWidth = imageObj.width
                        _this.imgHeight = imageObj.height
                        _this.stage.width(imageObj.width)
                        _this.stage.height(imageObj.height)
                        let img = new Konva.Image({
                            x: 0,
                            y: 0,
                            image: imageObj,
                            width: imageObj.width,
                            height: imageObj.height
                        })
                        _this.orgLayer.add(img)
                        _this.orgLayer.batchDraw()
                    }
                    imageObj.src = this.bgImg
                    this.stage.add(this.orgLayer)
                })
            },
            immediate: true,
            deep: true
        }
    }
}
</script>
<style scoped lang="less">
.mark-stage {
    flex: 1;
    overflow: hidden;
    background: white;
    text-align: center;
    position: relative;
    height: 100%;
}
.container-box {
    display: flex;
    justify-content: center;
    width: 100%;
    padding: 10px;
}
#container {
    max-width: 100%;
}
</style>
<style>
.textarea:focus {
    box-shadow: none;
    overflow: hidden;
    outline: none !important;
    line-height: 1.5;
}
</style>