- 紧跟上一节单个选中以后,图形的平移需要几个参数,鼠标移动位置与图形中心点位置的差值,是否按住鼠标左键,计算获得图形的中心点,正式开始:
- 在data中定义参数:
mouseMovePos: [0, 0], //鼠标移动位置与图形中心点位置的差值
isMouseClick: false, //是否按住鼠标左键
- 当鼠标按下和抬起的时候修改参数
this.isMouseClick = true; //鼠标左键已按下,可以进行平移操作
//鼠标抬起
mapMouseUp(e) {
this.isMouseClick = false; //禁止移动
this.mouseStartPos = []; //抬起后开始点击位置清空
this.mouseMovePos = [0,0]; //清空两次点位的差值,按下后重新计算
},
- mathUtils.js中封装获取中心点方法
// 获取多边形的中心点
getPolygonCenter(arr) {
var polygon = turf.polygon([arr]);
var center = turf.centerOfMass(polygon);
return center.geometry.coordinates
},
- 在鼠标移动过程中判断状态是否是move,activeData当前选中是否有数据,isMouseClick当前是否可以移动,符合条件就获取中心位置并且计算移动的差值
//鼠标移动
mapMousemove(e) {
let x = e.offsetX
let y = e.offsetY
//鼠标移动中判断当前是否状态是move,activeData当前选中是否有数据,isMouseClick当前是否可以移动
if(this.type === 'move' && this.activeData.length > 0 && this.isMouseClick) {
//获取图形中心位置
const center = mathUtils.getPolygonCenter(this.activeData);
//计算点击位置与图形中心位置的差值,如果差值大于0或小于0代表移动了
this.mouseMovePos = [x - center[0],y - center[1]]
//移动图形
this.movePoint(this.mouseMovePos, this.activeData)
}
this.redrawMap({
x,
y
})
},
- 调用移动图形的方法,中心点的差值得出来了,其余点到中心点的距离也是一样的,只需要通过其余点的坐标加上差值就得出来新的坐标,然后使用新的坐标重绘就ok了
//图形平移,通过差值计算点位坐标
movePoint(movePos, data) {
this.activeData = data.map(item => {
return [item[0] + movePos[0],item[1] + movePos[1]]
})
},
效果图如下:
整体代码如下,复制可用:
首页:
<template>
<div id="app">
<div class="nav-top">
<div :class="{'nav-sel':type==='move'}" @click="setType('move')">选择</div>
<div :class="{'nav-sel':type==='rectangle'}" @click="setType('rectangle')">矩形</div>
<div :class="{'nav-sel':type==='circle'}" @click="setType('circle')">圆形</div>
</div>
<div class="draw-box" ref="drawBox">
<canvas class="canvas-style" ref="canvasMap" @click="mapClick" @mousedown="mapMousedown"
@mousemove="mapMousemove" @mouseup="mapMouseUp" @dblclick="mapDbclick"
@mousewheel.prevent="mapMouseWheel" @contextmenu.prevent="rightMenu"></canvas>
</div>
</div>
</template>
<script>
import drawMap from '@/utils/drawMap.js';
import mathUtils from '@/utils/mathUtils.js';
export default {
name: 'app',
data() {
return {
type: 'rectangle', //当前可编辑图形的状态
mouseStartPos: [], //鼠标点击的位置
mouseMovePos: [0, 0], //鼠标移动位置与图形中心点位置的差值
mouseClickArr: [], //当前已点击的坐标记录
drawAllData: [], //当前所有保存的数据
activeData: [], //当前选中的图形坐标数据
isMouseClick: false, //是否按住鼠标左键
}
},
mounted() {
//初始化画板
const initData = {
id: this.$refs.canvasMap,
w: this.$refs.drawBox.clientWidth,
h: this.$refs.drawBox.clientHeight
}
drawMap.initMap(initData);
this.redrawMap();
},
methods: {
//单击地图
mapClick(e) {
let x = e.offsetX
let y = e.offsetY
//点击地图加入点位
switch (this.type) {
case 'rectangle':
this.mouseClickArr.push([x, y])
if (this.mouseClickArr.length === 3) {
this.drawRectangle(this.mouseClickArr)
this.redrawMap()
this.mouseClickArr = []
}
break;
}
},
//鼠标按下
mapMousedown(e) {
let x = e.offsetX
let y = e.offsetY
this.mouseStartPos = [e.offsetX, e.offsetY]
this.isMouseClick = true; //鼠标左键已按下,可以进行平移操作
if (this.type === 'move') {
let activePoint = []
if (this.drawAllData.length > 0) {
for (const [i, item] of this.drawAllData.entries()) {
mathUtils.pointInPolygonORLine(this.mouseStartPos, item) === true ? activePoint = item : []
}
}
if (this.activeData.length === 0) {
this.activeData = activePoint;
} else if (this.activeData.length > 0) {
this.drawAllData = this.drawAllData.concat([this.activeData])
this.activeData = activePoint;
}
this.drawAllData = this.drawAllData.filter(item => {
return item !== this.activeData
})
this.redrawMap();
}
},
//鼠标移动
mapMousemove(e) {
let x = e.offsetX
let y = e.offsetY
//鼠标移动中判断当前是否状态是move,activeData当前选中是否有数据,isMouseClick当前是否可以移动
if(this.type === 'move' && this.activeData.length > 0 && this.isMouseClick) {
//获取图形中心位置
const center = mathUtils.getPolygonCenter(this.activeData);
//计算点击位置与图形中心位置的差值,如果差值大于0或小于0代表移动了
this.mouseMovePos = [x - center[0],y - center[1]]
//移动图形
this.movePoint(this.mouseMovePos, this.activeData)
}
this.redrawMap({
x,
y
})
},
//鼠标抬起
mapMouseUp(e) {
this.isMouseClick = false; //禁止移动
this.mouseStartPos = []; //抬起后开始点击位置清空
this.mouseMovePos = [0,0]; //清空两次点位的差值,按下后重新计算
},
//鼠标双击
mapDbclick(e) {
console.log('鼠标双击', e);
},
//鼠标滚轮
mapMouseWheel(e) {
console.log('鼠标滚轮', e);
},
//鼠标右击
rightMenu(e) {
console.log('鼠标右击', e);
},
async redrawMap(point) {
//canvas重绘
drawMap.redrawMap();
//实时画鼠标点位
point && point.x && drawMap.drawCircle({
x: point.x,
y: point.y,
r: 4,
fillStyle: '#fff'
})
//绘制已经保存的房间数据
if (this.drawAllData.length > 0) {
for (const [i, item] of this.drawAllData.entries()) {
drawMap.drawRectangle(item);
}
}
//绘制正在编辑的数据
if (this.activeData.length > 0) {
drawMap.drawRectangle(this.activeData, true);
}
//实时的画各类图形
point && point.x && this.drawNowDrawing(point.x, point.y);
},
//实时画图形
drawNowDrawing(x, y) {
switch (this.type) {
case 'rectangle':
if (this.mouseClickArr.length >= 1) {
const mouseClick = this.mouseClickArr.length === 1 ? [
[x, y],
[x, y]
] : [
[x, y]
]
const newArr = this.mouseClickArr.concat(mouseClick)
this.drawRectangle(newArr)
}
break;
}
},
//画矩形
drawRectangle(arr) {
// 画矩形,点选三个点完成一个矩形
const vPoint = mathUtils.calculateVerticalPoint(arr);
// 根据第一点算的为第四点 根据第二点算的为第三点
const point4 = mathUtils.calculatePoint(vPoint, arr[0], arr[2]);
const point3 = mathUtils.calculatePoint(vPoint, arr[1], arr[2]);
const rectangleData = [arr[0], arr[1], point3, point4, arr[0]];
if (this.mouseClickArr.length === 3) {
this.drawAllData = this.drawAllData.concat([rectangleData])
}
drawMap.drawRectangle(rectangleData);
},
//图形平移,通过差值计算点位坐标
movePoint(movePos, data) {
this.activeData = data.map(item => {
return [item[0] + movePos[0],item[1] + movePos[1]]
})
},
//设置可编辑类型
setType(e) {
this.type = e
},
}
}
</script>
<style>
html,
body {
margin: 0;
padding: 0;
}
.nav-top {
display: flex;
align-items: center;
}
.nav-top>div {
padding: 10px;
border: 1px solid;
border-radius: 8px;
margin-right: 20px;
cursor: pointer;
}
.nav-top .nav-sel {
border: 2px solid #18c1f6;
}
.draw-box {
width: 100vw;
height: calc(100vh - 64px);
background: #F1F2F6;
position: fixed;
bottom: 0;
}
.hidden-icon {
position: absolute;
top: 0;
z-index: -100;
left: 0;
visibility: hidden;
}
.del-icon {
width: 16px;
transform: translate(-8px, -8px);
user-select: none;
}
</style>
mathUtils.js
import * as turf from "@/utils/turf.es";
let adsorptionDistance = 6
const mathUtils = {
// 计算点到线垂点的方法
calculateVerticalPoint(arr) {
const point = arr[2]
var x1 = arr[0][0];
var y1 = arr[0][1];
var x2 = arr[1][0];
var y2 = arr[1][1]
if (x1 == x2 && y1 == y2) {
return [point[0], point[1]];
}
var m = point[0];
var n = point[1];
var a = y2 - y1;
var b = x1 - x2;
var c = x2 * y1 - x1 * y2;
var x3 = (b * b * m - a * b * n - a * c) / (a * a + b * b);
var y3 = (a * a * n - a * b * m - b * c) / (a * a + b * b);
return [Math.round(x3 * 100) / 100, Math.round(y3 * 100) / 100];
},
// 根据垂点计算平行点
calculatePoint(vPoint, point, point2) {
const x = point[0] - vPoint[0] + point2[0]
const y = point[1] - vPoint[1] + point2[1]
return [x, y]
},
// 判断点是否在多边形内部或者线上
pointInPolygonORLine(point, polygon) {
var pt = turf.point(point);
var poly = turf.polygon([polygon]);
return turf.booleanPointInPolygon(pt, poly)
},
// 获取多边形的中心点
getPolygonCenter(arr) {
var polygon = turf.polygon([arr]);
var center = turf.centerOfMass(polygon);
return center.geometry.coordinates
},
}
export default mathUtils;