• 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 }, //偏移事件位置
        offset: { x: 0, y: 0 },             //缩放偏移
        scale: 1,                           //缩放比例
        scaleStep: 0.1,                     //每次缩放产生的变化量
        maxScale: 2,                        //最大缩放倍数
        minScale: 0.5                       //最小缩放倍数
     }
    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();
    }
    // ctx.translate(100, 0);
    //视图层绘制
    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;
    })
    
    /*————————————————滚轮缩放———————————————————*/
    canvas.addEventListener('wheel', e => {
        e.preventDefault();
        const canvasPosition = getCanvasPosition(e);
        //计算出鼠标在画布的坐标位置
        const realCanvasPosition = {
            x: canvasPosition.x - canvasInfo.offset.x,
            y: canvasPosition.y - canvasInfo.offset.y
        }
        //变化偏移量
        const { scaleStep } = canvasInfo;
        const deltaX = realCanvasPosition.x / canvasInfo.scale * scaleStep;
        const deltaY = realCanvasPosition.y / canvasInfo.scale * scaleStep;
        //上下滚轮分别赋值
        if (e.wheelDelta > 0) {
            canvasInfo.offset.x -= deltaX;
            canvasInfo.offset.y -= deltaY;
            canvasInfo.scale += scaleStep;
        } else {
            canvasInfo.offset.x += deltaX;
            canvasInfo.offset.y += deltaY;
            canvasInfo.scale -= scaleStep;
        }
        //通过矩阵变换重置当前的坐标系
        ctx.setTransform(canvasInfo.scale, 0, 0, canvasInfo.scale, canvasInfo.offset.x, canvasInfo.offset.y);
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        cirlces.forEach(item => drawCircle(ctx, item.x, item.y, item.r));
    })
    

      

      

      

  • 相关阅读:
    ecplise maven springmvc工程搭建
    【转载】钩子函数与回调函数
    【转载】Vue项目中的文件/文件夹命名规范
    联想本win10 virtualbox 安装centos
    【vue】router-link 与 router-view
    【vue】import的使用
    【vue】父组件主动调用子组件 /// 非父子组件传值
    【vue】vue组件的自定义事件
    修改MongoDB密码
    用du查看文件详情
  • 原文地址:https://www.cnblogs.com/theblogs/p/15587038.html
Copyright © 2020-2023  润新知