1 构造箭头类
2 计算鼠标在canvas上的坐标
3 计算鼠标位置与箭头中心位置连线的角度
4 计算在x,y方向上的移动量
5重新渲染箭头
<!--箭头跟随鼠标转动案例--> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> *{ margin: 0; padding: 0; } </style> </head> <body> <canvas id="canvas"></canvas> </body> <script src="arrow.js"></script> <script src="utils.js"></script> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let W = canvas.width = 800; let H = canvas.height = 600; const arrow = new Arrow({ x: W/2, y: H/2, w: 140, h: 60, rotation:30 }).render(ctx); let mouse = utils.getOffset(canvas); let speed=0.2 //获取鼠标在canvas上的坐标,连线即可计算角度 function move() { /** * 计算图形中心点与鼠标的连线 * @type {number} */ let dx = mouse.x - arrow.x; let dy = mouse.y - arrow.y; let angle = Math.atan2(dy, dx); //设置箭头的角度 arrow.rotation = angle //计算向鼠标所在位置移动时,在x和y方向上的移动量, //speed为移动的系数, let vx = speed * Math.cos(angle); let vy = speed * Math.sin(angle); arrow.x += vx; arrow.y += vy; ctx.clearRect(0, 0, W, H); arrow.render(ctx); requestAnimationFrame(move); } move() </script> </html>
util.js
var utils={} utils.getOffset=function (ele){ let mouse = {x: 0, y: 0}; ele.addEventListener('mousemove', function (e){ let {x, y} = utils.eventWrapper(e); mouse.x = x; mouse.y = y; }); return mouse; }; // 坐标系转换 utils.eventWrapper = function (ev){ /*** * pageX 事件发生点当前文档横坐标 * pageY 事件发生点当前文档纵坐标 * target 事件发生的目标元素---最先触发的那一层 * getBoundingClientRect * 事件发生节点元素的DOMRect对象,除去宽高外,都是相对于左上角的值 * 简单可理解为文档流的pageX,pageY减去canvas相对于文档流向下,向 * 右的偏移量,即可得到鼠标事件在canvas元素中的坐标 */ let {pageX, pageY, target} = ev; let {left, top} = target.getBoundingClientRect(); return {x: pageX - left, y: pageY - top}; }; arrow.js
class Arrow { constructor(props){ this.x=0//绘制箭头的初始坐标点x,y this.y=0 this.w=0 this.h=0 Object.assign(this,props) return this } //创建图形 createPath(ctx){ let {w,h}=this ctx.beginPath(); ctx.moveTo(-w/2, -h/2); ctx.lineTo(w/10, -h/2); ctx.lineTo(w/10, -h); ctx.lineTo(w/2, 0); ctx.lineTo(w/10, h); ctx.lineTo(w/10, h/2); ctx.lineTo(-w/2, h/2); ctx.closePath(); return this; } //绘制图形 render(ctx){ let {fillStyle, strokeStyle, rotation, x, y,lineWidth} = this; ctx.save(); ctx.fillStyle = fillStyle ? fillStyle:'rgba(255,0,0,1)'; ctx.lineWidth=lineWidth?lineWidth:20 ctx.strokeStyle = strokeStyle ? fillStyle:'rgba(255,0,0,1)'; ctx.translate(x, y); ctx.rotate(rotation); this.createPath(ctx); ctx.fill(); ctx.stroke(); ctx.restore(); return this; } }