图片上画热区/canvas上绘图,相互不覆盖

 思路:

1.canvas保存路径,显示页面用图片热区<map>显示

2.不相互覆盖:这个问题想了好久,一直找操作canvas的方法。今天忽然开窍,还是利用图片热区。

        本来是在canvas的点击事件上获取点的位置,然后画路径。后来想到可以把原图和已有的热区加载到页面上并且设置为透明。点击原图的时候获取点的位置,然后画路径。如果点到已有热区上就提示一下。结果真的可以,好激动哦。可能是我比较菜,所以能想出办法来,就容易激动☺。

3.图片缩放:这个利用mousewheel就好了。还有个图片拖拽,我这里没有用。在显示页面用到了,下篇记录

4.关联图片:根据名称模糊查找出想要关联的数据,复选框选择就好了。

领导追的比较紧,现在干活都是实现为止,所以代码还有很多问题和不足,若是有幸被谁发现问题,请留言告诉我。谢谢!

<template>
    <div id="hotSpot" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-body" >
                    <div id="hotAddBlock" @mousewheel="bigimg($event)" style="text-align:left;">
                        
                        <img ref="hideCad" style="position:absolute;top:0;left:0;opacity:0;z-index:8;" :src="cadImg.picurl" usemap="#MapHostEdit"/>
                        <map name="MapHostEdit" id="MapHostEdit" style="z-index:10;">
                            <area shape="poly" :coords="line.nickArea.points|filterLine" v-for="line in hotSpots" @click.stop="stopDraw" :key="line.nickArea.id">
                        </map>
                        <canvas id="hotSpotCanvas" width="980px" height="620px" style="z-index:9;">
                            <p>您的系统不支持此程序!</p>
                        </canvas>
                    </div>
                </div>
                <div class="modal-footer">
                    <button class="btn btn-info" @click.prevent="drawLine">绘制热点</button>
                    <button v-show="currentArr.length>1" class="btn btn-info" @click.prevent="drawLineOver">完成绘制</button>
                    <button class="btn" data-dismiss="modal" aria-hidden="true">关闭</button>                            
                </div>
            </div>            
        </div>
        <div class="upload-div" ref="formDiv">
            <form class="form-horizontal" role="form" @submit="addLine">
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="热点名称" v-model="requestData.nickArea.nickAreaName" maxlength="50"/>
                </div>
                <div class="form-group">
                    <textarea class="form-control" rows=3 placeholder="热点描述信息" v-model="requestData.nickArea.remark" maxlength="100"></textarea>
                </div>
                <div class="input-group">
                    <input type="text" class="form-control" v-model="requestImg.picName" placeholder="搜索平面图"/>
                    <span class="input-group-btn">
                        <button class="btn btn-default" @click.prevent="getImgs">
                            <i class="fa fa-search"></i>
                        </button>
                    </span>
                </div>
                <div class="form-group pics-selected">
                    <div class="check-Box-div" v-for="item in cadImgArr">
                        <input type="checkbox" :id="item.id" :value="item" v-model="picArr">
                        <label :for="item.id">{{item.picName}}</label>
                    </div>
                </div>
                <div class="form-group text-left pics-selected">
                   <div>已选平面图:</div>
                   <div class="check-Box-div" v-for="(item,index) in picArr" :key="'pic'+index">
                       {{item.picName}} 
                        <span @click="removeItem(index)" class="badge">X</span>
                       <!-- <span @click="removeItem(index)">X</span> -->
                   </div>
                </div>
                <div class="form-group">
                    <button class="btn btn-info btn-sm" @click.prevent="addLine">确定</button>&nbsp;&nbsp;
                    <button class="btn btn-info btn-sm" @click.prevent="hideForm">关闭</button>
                </div> 
            </form> 
        </div>
    </div>
</template>

<script type="text/javascript">
import bus from '@/js/eventBus'
export default{
    props:['id'],
	name:'',
    data () {
        return {
            canvas:'',
            ctx:'',
            bili:1,//页面显示比例
            cadImgArr:[],//热区可关联的图片列表
            hotSpots:[],//已有热区列表
            cadImg:{},//当前要画热区的图片
            currentArr:[],//保存路径
            picArr:[],//保存选中的关联图片
            requestImg:{picName:"",projectId:this.id},
            requestHotSpot:{gridType:5,tuuid:this.id,picPid:""},
            requestData:{nickArea:{gridType:5,tuuid:this.id,nickAreaName:"",remark:"",points:"",addUserId:sessionStorage.userID,picPid:""},pics:[]},
        }
    },
    filters:{
        filterLine(value){
            return value.replace(/;/g,',');
        },
    },
    mounted() {
        bus.$on("cadForHot",this.busDeal);
        this.canvas=this.getid("hotSpotCanvas");
        this.ctx=this.canvas.getContext("2d");
    },
    watch:{
        id:function(newValue){
            this.requestImg.projectId=newValue;
            this.requestHotSpot.tuuid=newValue;
            this.requestData.nickArea.tuuid=newValue;
        },
        cadImg:{
            handler:function(newvalue){                
                if(newvalue.picwidth){
                    this.bili=998/newvalue.picwidth;
                    $("#hotAddBlock").css("zoom",this.bili);
                }
                this.requestHotSpot.picPid=newvalue.id;
            },deep:true
        }
    },
    methods:{
        //查找项目上的平面图
        getImgs(){
          var _this=this;
          _this.common.doAction(_this.common.findCADByName,_this.requestImg,function(result){
                  if(result.status==1){
                      _this.cadImgArr=result.data;
                  }else{
                      _this.cadImgArr=[];
                  }
              },2);
         },
        initMethod(){
            this.canvas.width=this.cadImg.picwidth;
            this.canvas.height =this.cadImg.pichigh;
            var imgCAD=new Image();
            imgCAD.src=this.cadImg.picurl;
            var _this=this;
            imgCAD.onload = function(){
                _this.ctx.drawImage(imgCAD,0,0);
                _this.getHotSpots();
            }
        },
        //获取平面图上的热区
        getHotSpots(){
            var _this=this;
            _this.common.doAction(_this.common.searchNick,_this.requestHotSpot,function(result){
                if(result.status==1){
                    _this.hotSpots=result.data;
                    _this.drawHotSpot();
                }else{
                    _this.hotSpots=[];
                }
            },2);
        },
        //画热点区域
        drawHotSpot(){
            for(var i=0;i<this.hotSpots.length;i++){
                this.drawHotLine(this.hotSpots[i].nickArea.points,this.hotSpots[i].nickArea.nickAreaName);
            }
        },
        drawHotLine(points,name){
            var lists=points.split(";");
            this.ctx.beginPath();
            this.ctx.moveTo(lists[0].split(',')[0], lists[0].split(',')[1]); 
            for(var i=1;i<lists.length;i++){
                this.ctx.lineTo(lists[i].split(',')[0], lists[i].split(',')[1]);
            }
            this.ctx.fillStyle="#f40d0d5e";
            this.ctx.fill();
            this.ctx.font="14px Arial";
            this.ctx.fillStyle="#ffffff";
            this.ctx.fillText(name,lists[0].split(',')[0], lists[0].split(',')[1]);
            this.ctx.restore();
        },
        stopDraw(){
            alert("进入了别的热区!");return;
        },
        drawLine(){
            if(this.currentArr.length>0){
                this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
                var imgCAD=new Image();
                imgCAD.src=this.cadImg.picurl;
                this.ctx.drawImage(imgCAD,0,0);  
                this.drawHotSpot();                 
                this.currentArr=[];
            }
            var _this=this;
            _this.$refs.hideCad.onclick = function(ev){               
                var ev = ev || event;
                _this.disX =ev.offsetX/_this.bili;
                _this.disY =ev.offsetY/_this.bili;
                _this.ctx.beginPath();
                _this.ctx.arc(_this.disX,_this.disY,4,0,2*Math.PI);
                _this.ctx.fillStyle="green";
                _this.ctx.closePath();
                _this.ctx.fill();
                var i=_this.currentArr.length-1;
                if(i>=0){
                    _this.ctx.beginPath();
                    _this.ctx.lineWidth = 3;//圆边框宽度
                    _this.ctx.strokeStyle="green";
                    _this.ctx.moveTo(_this.currentArr[i].picxaxis,_this.currentArr[i].picyaxis);
                    _this.ctx.lineTo(_this.disX,_this.disY);
                    _this.ctx.closePath();
                    _this.ctx.stroke();
                    _this.ctx.save();
                }
                _this.currentArr.push({picxaxis:_this.disX,picyaxis:_this.disY});
            }
        },
       //绘制完成
        drawLineOver(){
             if(this.isContainPoint()){
                alert("覆盖了其他热区!");
                this.currentArr=[];
                this.initMethod();
                return;
            }     
            this.$refs.hideCad.onclick=null;
            this.$refs.formDiv.style.display="block";
        },
        hideForm(){
            this.$refs.formDiv.style.display="none";
        },
        addLine(){
            this.$refs.formDiv.style.display="none";            
            var _this=this;
            for(var i=0;i<_this.currentArr.length;i++){
                _this.requestData.nickArea.points+=_this.currentArr[i].picxaxis+","+_this.currentArr[i].picyaxis+";"
            }
            for(var i=0;i<_this.picArr.length;i++){
                _this.requestData.pics.push({picId:_this.picArr[i].id,picName:_this.picArr[i].picName});
            }
//提交数据
            _this.common.doAction(_this.common.addNick,_this.requestData,function(result){
                  if(result.status==1){
                      $("#hotSpot").modal('hide');
                      bus.$emit('hotAddOk',true);
                  }else{
                      _this.common.showAlert(result.message);
                  }
            },2);
        },
        getid(id) { //封装函数,通过id获取该id的html标签对象
            return document.getElementById(id);
        },
        //接收数据,有了数据才可以执行操作呀
        busDeal(data){
            if(data){
                this.currentArr=[];
                this.cadImgArr=[];
                this.picArr=[];
                this.cadImg=data;
                this.requestData.nickArea.nickAreaName="";
                this.requestData.nickArea.remark="";
                this.requestData.nickArea.points="";
                this.requestData.nickArea.picPid=data.id;
                this.requestData.pics=[];
                this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
                this.initMethod();
            }
        },
        removeItem(index){
            this.picArr.splice(index,1);
        },
        //作用:判断某个点是否在某范围内
        //已有每个热区的每个点跟当前画的路径对比,看是否包含中其中。若有一个点包含其中,则为覆盖了其他热区。
        //原理:每个点跟路径的所有的线对比,看是否交点为奇数,奇数则为包含。
        //转载自:http://www.360doc.com/content/12/1105/14/7662927_245870913.shtml
        isContainPoint(){
            var result=false;
            for(var j=0;j<this.hotSpots.length;j++){
                var hotSpoint=this.hotSpots[j].nickArea.points.split(';');                
                for(var k=0;k<hotSpoint.length-1;k++){
                    var p=hotSpoint[k].split(',');
                    for(var i=0;i<this.currentArr.length-1;i++){
                        var p1={x:this.currentArr[i].picxaxis,y:this.currentArr[i].picyaxis},
                        p2={x:this.currentArr[i+1].picxaxis,y:this.currentArr[i+1].picyaxis},
                        p3={x:p[0],y:p[1]},p4={x:hotSpoint[k+1].split(',')[0],y:hotSpoint[k+1].split(',')[1]};
                        if(this.checkCross(p1,p2,p3,p4)){
                            return true;
                        }
                        if( ( ( ( this.currentArr[ i + 1 ].picyaxis <= p[1] ) && ( p[1] < this.currentArr[ i ].picyaxis ) ) || ( ( this.currentArr[ i ].picyaxis <= p[1] ) && ( p[1]< this.currentArr[ i + 1 ].picyaxis ) ) ) && ( p[0] < ( this.currentArr[ i ].picxaxis - this.currentArr[ i + 1 ].picxaxis ) * ( p[1] - this.currentArr[ i + 1 ].picyaxis ) / ( this.currentArr[ i ].picyaxis - this.currentArr[ i + 1 ].picyaxis) + this.currentArr[ i + 1 ].picxaxis ) )
                        {
                            result = !result;
                        }
                    }
                    if(result){
                        return true;
                    }
                }
            }
            return result;
        },
        //作用:判断两条线是否相交
        checkCross(p1,p2,p3,p4){
            var v1={x:p1.x-p3.x,y:p1.y-p3.y},
            v2={x:p2.x-p3.x,y:p2.y-p3.y},
            v3={x:p4.x-p3.x,y:p4.y-p3.y},
            v=this.crossMul(v1,v3)*this.crossMul(v2,v3)
            v1={x:p3.x-p1.x,y:p3.y-p1.y}
            v2={x:p4.x-p1.x,y:p4.y-p1.y}
            v3={x:p2.x-p1.x,y:p2.y-p1.y}
            return (v<=0&&this.crossMul(v1,v3)*this.crossMul(v2,v3)<=0)?true:false
        },
        crossMul(v1,v2){
            return v1.x*v2.y-v1.y*v2.x;
        },
        //缩放图片
        bigimg(event){
             var obj = event.currentTarget;
             var zoom = parseInt(obj.style.zoom,10)||100;
            zoom += event.wheelDelta / 12;
            if(zoom > 0 )
            obj.style.zoom=zoom+'%';
            this.bili=zoom/100;
            return false;
         },
    },
    beforeDestroy() {
        bus.$off("cadForLine",this.busDeal);
    },
}
</script>
<style scoped>
 .modal-dialog{width:1000px;height:665px;}
 .modal-body{width: auto;top:5px;left:5px;right:5px;padding:0px;}
 .upload-div{
        width:500px;height:450px;
        padding:20px;
        position:absolute;
        top:160px;left:550px;
        background-color:#fff;
        border:1px solid #ddd;
        border-radius: 8px;
        box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
        display: none;
    }
    .pics-selected{height:100px;overflow-y:auto;}
    .check-Box-div{float:left;margin-top:10px;margin-right:5px;}
 [type="checkbox"] + label{padding:5px 5px 5px 25px;}
</style>

 

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