canvas根据坐标点位画图形-canvas选中单个进行平移操作

  1. 紧跟上一节单个选中以后,图形的平移需要几个参数,鼠标移动位置与图形中心点位置的差值,是否按住鼠标左键,计算获得图形的中心点,正式开始:
  2. 在data中定义参数:
mouseMovePos: [0, 0], //鼠标移动位置与图形中心点位置的差值
isMouseClick: false, //是否按住鼠标左键
  1. 当鼠标按下和抬起的时候修改参数
this.isMouseClick = true; //鼠标左键已按下,可以进行平移操作

//鼠标抬起
mapMouseUp(e) {
	this.isMouseClick = false; //禁止移动
	this.mouseStartPos = []; //抬起后开始点击位置清空
	this.mouseMovePos = [0,0]; //清空两次点位的差值,按下后重新计算
},
  1. mathUtils.js中封装获取中心点方法
// 获取多边形的中心点
getPolygonCenter(arr) {
	var polygon = turf.polygon([arr]);
	var center = turf.centerOfMass(polygon);
	return center.geometry.coordinates
},
  1. 在鼠标移动过程中判断状态是否是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
	})
},
  1. 调用移动图形的方法,中心点的差值得出来了,其余点到中心点的距离也是一样的,只需要通过其余点的坐标加上差值就得出来新的坐标,然后使用新的坐标重绘就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;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值