vue封装组件---图片中显示轨迹,点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hsl_1990_08_15/article/details/88802685

感觉好几千年都没有写博客了,今天终于闲下来写写了,听说提笔如有神,我这提手已经词穷了。

年初,经过部门的大整合,搞的我们组的人已经精疲了,为了员工的精神幸福?呵呵了。

虽说公司强大了,但是使用员工夜以继日的汗水来浇灌的。

写到这里吧,同事在呢!!!!

废话就别说了,直接上代码,懂者自懂,不懂者我也无能为力。

<!--
*.vue:
    <template>
        <siteSvg :imgSrc="imgSrc" :parentElement="parentElement" :positionMove="positionMove" :circleInnerText="circleInnerText" :canClick="canClick" @clickResult="clickResult" :drawPolygonData="drawPolygonData" :positionSize="positionSize" :curvePathData="curvePathData" :positionDingData="positionDingData" @result="savePositionInfo"></siteSvg>
    </template>
    
    <script>
    import siteSvg from '@/components/custom/site-svg';
    export default {
        data(){
            return {
                //图片地址
                imgSrc:'',
                //区域列表数据
                drawPolygonData:[],
                //曲线(轨迹)列表数据
                curvePathData:[],
                //点(作业面)列表数据
                positionDingData:[],
                //点(作业面)大小,默认19
                positionSize:20,
                //点(作业面)是否可移动,默认不移动
                positionMove:true,
                //字体是否显示到圆内,如果显示到圆内,需要设置圆的大小positionSize
                circleInnerText:true,
                //点是否可以点击,如果能点击,我们最好设置回调函数
                canClick:true,
                parentElement:'parent-div'
            }
        },
        components: {
            siteSvg
        },
        methods:{
            savePositionInfo(data){
                console.log(data);
            },
            clickResult(data){
                console.log(data);
            }
        }
    }
    </script>
-->
<template>
    <div style="text-align: left;height: 100%;width: 100%;" class="real-time-look-position">
        <img class='imagemark-image position-myCanvasImg' :src="imgSrc" style='width:100%;height:100%;position: absolute;' @load="loadImg">
        <div class='imagemark-mark-div' style='width: 100%;height: 100%;' v-html="drawPolygon"></div>
        <div v-for="(data,index) in interPositionDataList" :key="index" :offsetX="data.xPos" :offsetY="data.yPos" :style="{left:data.left+'px',top:data.top+'px'}" style="position:absolute;width: 0;height: 0;line-height: 0px;z-index:0">
            <div v-if="!circleInnerText" class="help-tip">
                <div class="tip-content">
                    <div>{{data.workSurfaceName||'作业面名称'}}</div>
                </div>
            </div>
            <!-- circleInnerText?data.personCount>0?'rgba(0,0,255,0.5)':'rgba(225,102,92,0.5)':'rgb(0,0,255)' -->
            <div :id="'position-id-'+data.id" @click="canClick?positionClick(data):''" @mousedown="down(data.id)" @mousemove="move(data.id)" @mouseup="handleNodeClick()" :style="{width:positionSize+'px',height:positionSize+'px',backgroundColor:data.backGroundColor||'rgb(0,0,255)'}" style="border-radius: 999px;z-index:99999999;cursor: pointer;">
                <div v-if="circleInnerText" style="width: 100%;height: 100%;text-align: center;line-height: 25px;padding-top: 13px;">
                    <div style="color:#CCFF00;">{{data.personCount||'作业面工人数量'}}</div>
                    <div style="color:#FFFFFF;">{{data.workSurfaceName||'作业面名称'}}</div>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
import windowUtils from '@/utils/windowUtils';
export default {
  name: 'siteSvg',
  props:{
    imgSrc:{
        type:String,
        default:''
    },
    drawPolygonData:{
        type:Array,
        default:()=>[]
    },
    curvePathData:{
        type:Array,
        default:()=>[]
    },
    positionMove:{
        type:Boolean,
        default:false
    },
    positionDingData:{
        type:Array,
        default:()=>[]
    },
    positionSize:{
        type:Number,
        default:19
    },
    circleInnerText:{
        type:Boolean,
        default:false
    },
    canClick:{
        type:Boolean,
        default:false
    },
    parentElement:{
        type:String,
        default:''
    }
  },
  data () {
    return {
        width:0,
        height:0,
        pageWidth:0,
        pageHeight:0,
        interPositionDataList:[],
        imageScale:0,
        imageOffsetX:0,
        imageOffsetY:0,
        currentClick:'',
        existedColors:['rgba(255,225,179,0.3)', 'rgba(179,255,255,0.3)', 'rgba(255,179,179,0.3)', 'rgba(179,255,179,0.3)', 'rgba(225,179,179,0.3)', 'rgba(255,209,225,0.3)'],
        nameColors:['rgba(255,225,179,1)', 'rgba(179,255,255,1)', 'rgba(255,179,179,1)', 'rgba(179,255,179,0.3)', 'rgba(225,179,179,1)', 'rgba(255,209,225,1)'],
        drawPolygon:'',
        elementObj:'',
        flag:false,
        nx:0,
        ny:0,
        dx:0,
        dy:0,
        cur:{x:0,y:0}
    }
  },
  watch:{
      positionDingData:{
          handler(val,oldVal){
              this.positionDingData=val;
              this.addPositionDing();
          }
      }
  },
  components: {
    
  },
  computed:{
  },
  methods:{
    loadImg:function(event){
        this.width = event.target.naturalWidth;
        this.height = event.target.naturalHeight;
        this.drawExistedRegions();
    },
    drawExistedRegions:function(){
        this.imageScale = Math.min(
            this.pageWidth / this.width,
            this.pageHeight / this.height
        );
        this.imageOffsetX = -this.width * this.imageScale / 2;
        this.imageOffsetY = -this.height * this.imageScale / 2;
        let positionArr=document.getElementsByClassName('real-time-look-position');
        //如果一个页面多次引用这个组件,需要判断到底是某一个,在传入参数中设置parentElement
        if(positionArr&&positionArr.length>0&&this.parentElement){
            for(let i=0;i<positionArr.length;i++){
                if(positionArr[i].parentElement.className.indexOf(this.parentElement)>=0){
                    this.elementObj=positionArr[i];
                    break;
                }
            }
        }else{
            this.elementObj=positionArr[0];
        }
        this.elementObj.style.transform="scale(1)";
        this.changeScale(this.imageScale);
        this.forDrawExistedPolygon();
        this.addPositionDing();
    },
      //改变图片大小
    changeScale: function(scale, save) {
        if (scale > 1) {
            scale = 1;
        }
        var minScale = Math.min(this.pageWidth / this.width, this.pageHeight / this.height);
        if (scale < minScale) {
            scale = minScale;
        }
        var imageWidth = this.width * scale;
        var imageHeight = this.height * scale;

        var offsetX = this.imageOffsetX / this.imageScale * scale;
        var offsetY = this.imageOffsetY / this.imageScale * scale;

        // 边界不能脱离中心点
        if (offsetX + imageWidth < this.pageWidth) {
            offsetX = this.pageWidth - imageWidth;
        }
        if (offsetY < this.pageHeight) {
            offsetY = this.pageHeight - imageHeight;
        }

        this.elementObj.style.transformOrigin="0 0";//设置图片的中心点为左上角

        this.elementObj.style.width = imageWidth + "px";
        this.elementObj.style.height = imageHeight + "px";
        this.elementObj.style.top = offsetY + "px";
        this.elementObj.style.left = offsetX + "px";

        if (save) {
            this.imageScale = scale;
            this.imageOffsetX = offsetX;
            this.imageOffsetY = offsetY;
        }
    },
    forDrawExistedPolygon:function(){
        var avgHtml="<svg class='imagemark-mark position-myCanvas' style='position: absolute;top: 0;left: 0;width: 100%;height: 100%;' viewBox='0 0 "+this.width+" "+this.height+"'>";
        //如果有区域信息,开始画区域
        if(this.drawPolygonData&&this.drawPolygonData.length>0){
            for (var i = 0; i < this.drawPolygonData.length; i++) {
                var points = [];
                var r = this.drawPolygonData[i];
                if (!r.points) continue;
                for (var j = 0; j < r.points.length; j++) {
                    points.push({x: r.points[j].offsetX, y: r.points[j].offsetY});
                }
                if (!points.length) return;
                var p = "";
                var maxX = 0, minX = Number.MAX_VALUE, maxY = 0, minY = Number.MAX_VALUE;
                for (var j = 0; j < points.length; j++) {
                    var point = points[j];
                    p += point.x + "," + point.y + " ";
                    maxX = Math.max(maxX, point.x);
                    minX = Math.min(minX, point.x);
                    maxY = Math.max(maxY, point.y);
                    minY = Math.min(minY, point.y);
                }
                var color = this.existedColors[i % this.existedColors.length];
                var textColor = this.nameColors[i % this.existedColors.length];
                var count=r.deviceCount?r.deviceCount:0;
                var text = r.name + "(" + count + ")";
                var textSize = 25;
                var textX = Math.max(minX, minX + (maxX - minX) / 2 - text.length * textSize / 2);
                var textY = minY + (maxY - minY) / 2;
                avgHtml+="<text x='" + textX + "' y='" + textY + "' style='fill:" + textColor + ";font-size:" + textSize + "px;'>" + text + "</text>" +
                "<polygon points='" + p + "' style='fill:" + color + ";stroke: " + color + ";stroke-width:1;'/>";
            }
        }
        //如果有轨迹数据,划曲线,或者折线,看需求定义
        if(this.curvePathData&&this.curvePathData.length>0){
            var path="";
            let existQ=false;
            //方式1 这里的绘制二次贝塞尔曲线使用M X1,Y1 Q X2,Y2 X3,Y3 T X4,Y4    M:定义起点  Q:定义控制点  T:T 命令是二次被赛尔曲线的平滑延伸命令
            //方式2 M x0,y0 C x1,y1 x2,y2 x3,y3       C方法定义的是三次贝塞尔曲线,这里只是多了一个控制点
            //方式3 M X0,Y1 CX1,Y1 X2,Y2 S X3,Y3
            for(var i=0;i<this.curvePathData.length;i++){
                //方式1
                // if(i===0){
                //     path+="M "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                // }else if((this.curvePathData.length-1)===i){
                //     path+="T "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                // }else{
                //     if(existQ){
                //         path+=this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                //     }else{
                //         existQ=true;
                //         path+="Q "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                //     }
                // }
                //方式2  比1和3好点
                if(i===0){
                    path+="M "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                }else{
                    if(existQ){
                        path+=this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                    }else{
                        existQ=true;
                        path+="C "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                    }
                }
                //方式3
                // if(i===0){
                //     path+="M "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                // }else if((this.curvePathData.length-1)===i){
                //     path+="S "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                // }else{
                //     if(existQ){
                //         path+=this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                //     }else{
                //         existQ=true;
                //         path+="C "+this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
                //     }
                // }
                //画折现
                // path+=this.curvePathData[i].xPos+","+this.curvePathData[i].yPos+" ";
            }
            //折现
            // avgHtml+="<polyline points='"+path+"' style='fill:none;stroke:#0000FF;stroke-width:5px;cursor: default;'></polyline>";
            //曲线
            avgHtml+="<path d='"+path+"' stroke='#0000FF' stroke-width='5px' stroke-opacity='0.6' stroke-linejoin='round' stroke-linecap='round' style='cursor: pointer;' fill='none'></path>"
        }
        avgHtml += "</svg>";
        this.drawPolygon += avgHtml;
    },
    //鼠标按下点,准备开始移动
    down:function(id){
        this.setPositionZIndex(id);
        if(this.positionMove){
            this.flag = true;
            this.dx = this.elementObj.offsetLeft;
            this.dy = this.elementObj.offsetTop;
        }
    },
    //移动点的位置
    move:function(id){
        if(this.positionMove&&this.flag){
            var touch ;
            if(event.touches){
                touch = event.touches[0];
            }else {
                touch = event;
            }
            let x = touch.clientX-this.dx;
            let y = touch.clientY-this.dy;
            if(x<=0){
                x=0;
            }
            if(this.y<=0){
                this.y=0;
            }
            if(x>=this.width*this.imageScale){
                x=this.width*this.imageScale;
            }
            if(y>=this.height*this.imageScale){
                y=this.height*this.imageScale;
            }
            for(let i=0;i<this.interPositionDataList.length;i++){
                if(this.interPositionDataList[i].id===id){
                    this.interPositionDataList[i].xPos = (x/this.imageScale).toFixed(4);
                    this.interPositionDataList[i].yPos = (y/this.imageScale).toFixed(4);
                    this.interPositionDataList.splice(i, 1, this.interPositionDataList[i]);
                    break;
                }
            }
            
            //阻止页面的滑动默认事件
            document.addEventListener("touchmove",function(){
                event.preventDefault();
            },false);
        }
    },
    //添加点信息
    addPositionDing:function(){
        let that=this;
        //如果有点的数据,则添加点信息
        if(that.positionDingData&&that.positionDingData.length>0){
            for(let i=0;i<that.positionDingData.length;i++){
                that.positionDingData[i].left=(that.positionDingData[i].xPos*that.imageScale-that.positionSize/2).toFixed(4);
                that.positionDingData[i].top=(that.positionDingData[i].yPos*that.imageScale-that.positionSize/2).toFixed(4);
            }
            this.interPositionDataList=that.positionDingData;
            //如果允许点移动,则添加移动事件
            if(this.positionMove){
                //如果移动端也用这个来设置点的移动,放开
                // this.$nextTick(this.addMoveEventToPoint());
                document.body.addEventListener("mouseup",function(){
                    that.flag = false;
                },false);
            }
        }
    },
    //设置点的层级
    setPositionZIndex:function(elementId){
        if(this.currentClick&&this.currentClick!==elementId){
            document.getElementById("position-id-"+this.currentClick).parentElement.style.zIndex=0;
        }
        document.getElementById("position-id-"+elementId).parentElement.style.zIndex=1000;
        this.currentClick=elementId;
    },
    //给生成的点添加移动事件
    addMoveEventToPoint:function(){
        if(this.interPositionDataList&&this.interPositionDataList.length>0){
            let that=this;
            let interval=setInterval(function(){
                let positionId=document.getElementById("position-id-"+that.interPositionDataList[0].id);
                if(positionId!==null){
                    clearInterval(interval);
                    for(let i=0;i<that.interPositionDataList.length;i++){
                        positionId=document.getElementById("position-id-"+that.interPositionDataList[i].id);
                        if(positionId!==null){
                            positionId.addEventListener("touchstart",function(){
                                that.down(that.interPositionDataList[i].id);
                            },false)
                            positionId.addEventListener("touchmove",function(){
                                that.move(that.interPositionDataList[i].id);
                            },false)
                            positionId.addEventListener("touchend",function(){
                                that.flag = false;
                            },false)
                        }
                    }
                }
            },100)
        }
    },
    //移动完点后,进行保存处理
    handleNodeClick:function(){
        this.flag = false;
        this.$emit('result',this.interPositionDataList);
    },
    //点击后回调
    positionClick:function(id){
        this.$emit('clickResult',id);
    },
    initData:function(){
        //获取场布图所在外层div的宽高
        this.pageWidth=windowUtils.getWidgthByClassNameparentElement("real-time-look-position",this.parentElement);
        this.pageHeight=windowUtils.getHeightByClassNameparentElement("real-time-look-position",this.parentElement);
    }
  },
  mounted:function(){
    // 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
    this.$nextTick(this.initData());
  }
}
</script>

<style scoped>
 .help-tip{
	position: absolute;
    text-align: center;
    border-radius: 50%;
    font-size: 14px;
    line-height: 18px;
    cursor: default;
    z-index: 999;
}

.help-tip:hover .tip-content{
	/* display:block; */
	transform-origin: 100% 0%;

	-webkit-animation: fadeIn 0.3s ease-in-out;
	animation: fadeIn 0.3s ease-in-out;

}

.help-tip .tip-content{
	background-color: #fff;
    padding: 0;
    width: 94px;
    position: absolute;
    border-radius: 3px;
    -webkit-box-shadow: 0 0px 67px rgba(0,0,0,.2);
    box-shadow: 0 0px 67px rgba(0,0,0,.2);
    color: #FF5500;
    font-size: 13px;
    line-height: 37px;
    top: -44px;
    left: -33px;
    height: 35px;
    border: 1px solid rgb(230,230,230);
}

.help-tip .tip-content:before{
	position: absolute;
    content: '';
    width: 0;
    height: 0;
    right: 42px;
    top: 35px;
    border-left: 11px solid transparent;
    border-right: 11px solid transparent;
    border-top: 8px solid #fff;
}

.help-tip .tip-content:after{
	width:100%;
	height:40px;
	content:'';
	position: absolute;
	top:0px;
	left:0px;
}
</style>

复制整个文件到你的vue工程中,然后引用,根据文件中给出的说明来使用,以此来慰藉我无处施展的内功心法

展开阅读全文

没有更多推荐了,返回首页