思路:
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>
<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>