Painter.vue 10.6 KB
<template>
    <div class="painter" ref="painter"></div>
</template>
<script>
import _ from 'underscore';
import zrender from 'zrender';
export default {
    props: {
        isEdit:Boolean,
        cdata: {
            type: Object,
            default: {}
        },
        list:Array,
        desk:Object
    },
    watch: {
        cdata: {
            immediate: true,
            handler(nval) {
                if(JSON.stringify(nval) == '{}'){
                    return false
                }
                setTimeout(()=>{
                    if(!_.isEmpty(nval))this.initZrender();
                },500);
            },
            deep: true
        }
    },
    data() {
        return {
            pointList: [],//当前绘制的图形点位列表
            groupList: [], //图形数组
            zr: {}, //绘图实例对象
            baseColor: '#ff000075',
            strokeColor: '#f00',
            /*********************************/
            fillColor: '#f00',
            scaleVal: 10, //缩放
            rotateVal: 0, //旋转角度
            tempData: {},
            /*********************************/
            groupObj: {}
        }
    },
    methods: {
        initZrender() {
            this.$nextTick(() => {
                let client = document.querySelector('.painter').getBoundingClientRect();
                this.zr = zrender.init(this.$refs.painter, {
                    renderer: 'canvas',
                    devicePixelRatio: 2,
                    width: client.width,
                    height: client.height
                });
                this.bindingEvt();
                this.initialGroup();
            })
        },
        initialGroup(){
           let list = this.list
           _.each(list,item=>{
               let gdata = zrender.util.clone(item);
               if(gdata.coordinate){
                    gdata.points = _.map(JSON.parse(gdata.coordinate),point=>{
                        let x = point.x*this.zr.getWidth()/1920;
                        let y = point.y*this.zr.getHeight()/1080;
                        return [x,y];
                    });
                    gdata.desk = item;
                    this.createGroup(gdata,true);
               } 
           })
        },
        bindingEvt() {
            let that = this;
            let group;
            this.zr.on('click', evt => {
                if(!this.desk||_.isEmpty(this.desk)){
                    return this.$message({
                        showClose: true,
                        type: "warning",
                        message: '请先点击选择通道'
                    })
                }
                this.$emit('start',this.desk);
                let point = [evt.event.zrX, evt.event.zrY];
                this.pointList.push(point);
                if (this.pointList.length == 1) { //第一次点击,创建Group
                    let points = zrender.util.clone(this.pointList);
                    group = this.createGroup({ points, fill: that.baseColor,desk:this.desk});
                }
                this.drawPolyline(group, this.pointList);
            })
            this.zr.on('mousemove', evt => {
                if (this.pointList.length == 0) return false;
                let point = [evt.event.zrX, evt.event.zrY];
                this.drawPolyline(group, this.pointList.concat([point]));
            });
        },
        drawPolyline(group, points) {
            group.polyline.setShape({
                points: points
            });
            group.points = zrender.util.clone(points);
        },
        createGroup(gdata,isFull=false) {
            let that = this;
            let points = gdata.points;
            
            let fill = gdata.fill;
            let position = gdata.position;
            /*******************************/
            let group = new zrender.Group({
                complete: false,
                position: position || [0, 0]
            });
            if(isFull){
                group.points = points;
            }
            group.desk = gdata.desk;
            group.cdata = this.cdata;
            group.zr = this.zr;
            
            let polyline = this.createPolyline({
                stroke: that.strokeColor,
                fill: fill,
                points: points
            })
            group.id = gdata.id || Date.now().toString(36);
            group.add(polyline);
            group.polyline = polyline;
            group.fill = gdata.fill;
            group.data = gdata;
            if (this.isEdit && points.length == 1) {
                let circle = that.createCircle(group, points[0]);
                group.add(circle)
            } else if(isFull){
                this.drawText(group, false);
            }
            group.on('click', function (evt) {
                if (!that.isEdit) {
                    evt.cancelBubble = true;
                    return false;
                }
                if(group.complete){
                   that.$emit('gclick',group);
                   evt.cancelBubble = true;
                    return false;
                }
                
                if (that.pointList.length == 1) {
                    //evt.cancelBubble = true;
                }
            });
            let action = this.$refs.action;
            /*action.onmouseleave = ()=>{
                action.style.display = 'none'
            }*/
            group.on('contextmenu', function (evt) {
                if (!that.isEdit) {
                    evt.stop();
                    return false
                }
                if (that.pointList.length > 0) {
                    evt.stop();
                    return false;
                }
                action.style.display = 'block';
                action.style.left = (evt.offsetX - 5) + 'px'
                action.style.top = (evt.offsetY - 5) + 'px'
                evt.stop();
                that.setCurrentGroup(this);
                return false;
            })
            this.zr.add(group);
            this.groupList.push(group);
            return group;
        },
        createCircle(group, point) {
            let that = this;
            let circle = new zrender.Circle({
                style: {
                    fill: 'transparent',
                    stroke: '#f00',
                    lineWidth: 2
                },
                shape: {
                    cx: point[0],
                    cy: point[1],
                    r: 10
                }
            });
            circle.on('click', evt => {
                evt.cancelBubble = true;
                that.pointList.push(that.pointList[0]);
                group.remove(circle);
                if (that.pointList.length > 3) {
                    this.drawPolyline(group, that.pointList);
                    this.drawText(group,true);
                } else {
                    this.zr.remove(group)
                }
                that.pointList = [];
            });
            return circle;
        },
        createPolyline(params) {
            let that = this;
            return new zrender.Polyline({
                x: 0,
                y: 0,
                origin: [0, 0],
                //cursor:'move',
                draggable: false,
                style: {
                    stroke: params.stroke,
                    fill: params.fill || that.baseColor,
                    lineWidth: 3
                },
                shape: {
                    points: params.points,
                    smooth: 0.01
                }
            });

        },
        drawText(group,finish) {
            let that = this,xPoints=[],yPoints=[];
            _.each(group.points,item=>{
               xPoints.push(item[0]);
               yPoints.push(item[1]);
            })
            let [x, y] = [_.max(xPoints) - _.min(xPoints), _.max(yPoints) - _.min(yPoints)];
            let client = group.getBoundingRect();
            let content = `{name|${group.desk.name || ''}}`;

            let text = new zrender.Text({
                position: [client.x, client.y],
                style: {
                    x: client.width / 2,
                    y: client.height / 2,
                    width: client.width,
                    height: client.height,
                    textAlign: 'center',
                    textVerticalAlign: 'middle',
                    //textShadowBlur: 3,
                    textShadowColor: '#893e95',
                    //textShadowOffsetX: 3,
                    //textShadowOffsetY: 3,
                    text: content,
                    fill: '#fff',
                    fontSize: 14,
                    fontWeight:600,
                    rich: {
                        name: {
                            textLineHeight: 16,
                            textFill: '#fff'
                        }
                    }
                }
            });
            //text.setClipPath(curGroup.polyline)
            //this.setDragaAble(text)
            group.add(text);
            group.text = text;
            group.complete = true;//图像已经绘制完毕
            group.polyline.attr({
                origin: [client.x + client.width / 2, client.y + client.height / 2]
            });
            if (that.isEdit) {
                that.setDragaAble(group);
            }
            this.$emit('finish',group);
        },
        setCurrentGroup(group) {
            this.groupObj = _.find(this.groupList, item => {
                return item.id == group.id;
            });
            this.fillColor = this.groupObj.polyline.style.fill;
        },
        setDragaAble(el, popup) {
            let isDown = false,
                downPoint = [],
                initPoint = [];
            el.on('mousedown', evt => {
                isDown = true;
                evt.cancelBubble = true;
                downPoint = [evt.event.zrX, evt.event.zrY];
                initPoint = zrender.util.clone(el.position);
                evt.cancelBubble = true;
            });
            el.on('mousemove', evt => {
                if (isDown) {
                    evt.cancelBubble = true;
                    let pos = [evt.event.zrX - downPoint[0], evt.event.zrY - downPoint[1]];
                    el.attr('position', [initPoint[0] + pos[0], initPoint[1] + pos[1]]);
                }
            });
            el.on('mouseup', evt => {
                evt.cancelBubble = true;
                isDown = false;
            });
            this.zr.on('mouseup', function () {
                isDown = false;
            })
        },

    }
}
</script>
<style scoped lang="less">
.painter {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}
</style>