1. 程式人生 > 其它 >canvas 視覺化操作-拖拽&縮放&移動

canvas 視覺化操作-拖拽&縮放&移動

canvas拖拽的實現

/*
canvas 視覺化操作-拖拽&縮放&移動
*/
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

const stautsConfig = {
	//拖拽開始
	IDLE: 0, 
	//拖拽中
	DRAG_START: 1,
	//拖拽結束
	DRAGGING: 2

}
//畫布資訊
const canvasInfo = {
	status: stautsConfig.IDLE,			//拖拽狀態
	dragTarget: null, 					//拖拽物件
	lastEvtPos: { x: null, y: null },	//計算偏移量座標
	offsetEvtPos: { x: null, y: null }  //偏移事件位置
}

const cirlces = [];//畫布圓的資訊

//畫圓
const drawCircle = (ctx, cx, cy, r) => {
	ctx.save();

	ctx.beginPath();
	ctx.strokeStyle = 'blue';
	ctx.arc(cx, cy, r, 0, Math.PI*2);
	ctx.stroke();

	ctx.closePath();
	ctx.restore();
}
//檢視層繪製
drawCircle(ctx, 100, 100, 20);
//資料層記錄
cirlces.push({
	x: 100, 
	y: 100,
	r: 20
})
drawCircle(ctx, 200, 200, 30);
cirlces.push({
	x: 200, 
	y: 200,
	r: 30
})

/*————————————————拖拽———————————————————*/

//畫布位置
const getCanvasPosition = e => {
	return {
		x: e.offsetX,
		y: e.offsetY
	}
}

//獲取距離
const getDistance = (p1, p2) => {
	return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
}

//判斷是否在圓內
const ifInCirlce = (pos) => {
	for (let i = 0; i < cirlces.length; i++) {
		//如果兩個距離小於半徑就返回
		if (getDistance(cirlces[i], pos) < cirlces[i].r) {
			return cirlces[i]
		}
	}
	return false;

}

//滑鼠按下
canvas.addEventListener('mousedown', e => {
	const canvasPosition = getCanvasPosition(e);
	const cirlceRef = ifInCirlce(canvasPosition);
	//如果拖拽物件條件成立,系統進入拖拽狀態
	if (cirlceRef) {
		//記錄拖拽目標、狀態、偏移量位置、偏移事件位置
		canvasInfo.dragTarget = cirlceRef;
		canvasInfo.status = stautsConfig.DRAG_START;
		canvasInfo.lastEvtPos = canvasPosition; 
		canvasInfo.offsetEvtPos = canvasPosition;
	}
})

//滑鼠移動
canvas.addEventListener('mousemove', e => {
	const canvasPosition = getCanvasPosition(e);
	//如果在某個圓內,修改拖動中的滑鼠樣式
	if (ifInCirlce(canvasPosition)) {
		canvas.style.cursor = 'all-scroll';
	} else {
		canvas.style.cursor = ''
	}
	//如果第一次距離和第二次之間大於5,代表真正的拖動(防止抖動,一按下就移動的問題)
	if (canvasInfo.status === stautsConfig.DRAG_START && getDistance(canvasPosition, canvasInfo.lastEvtPos) > 5) {
		console.log('try');
		canvasInfo.status = stautsConfig.DRAGGING;
		//更新偏移事件位置
		canvasInfo.offsetEvtPos = canvasPosition;
	} else if (canvasInfo.status === stautsConfig.DRAGGING){
		console.log('拖拽中');
		const { dragTarget } = canvasInfo;
		dragTarget.x += (canvasPosition.x - canvasInfo.offsetEvtPos.x);
		dragTarget.y += (canvasPosition.y - canvasInfo.offsetEvtPos.y);
		//拖拽時候清空並重繪圓圈
		ctx.clearRect(0, 0, canvas.width, canvas.height);
		cirlces.forEach(item => drawCircle(ctx, item.x, item.y, item.r));
		canvasInfo.offsetEvtPos = canvasPosition;
	}
})

//滑鼠抬起
canvas.addEventListener('mouseup', e => {
	if (canvasInfo.status === stautsConfig.DRAGGING) canvasInfo.status = stautsConfig.IDLE;
})