canvas绘制拖拽箭头

canvas绘制拖拽箭头

完整代码

复制代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>跟随鼠标移动的拖拽箭头</title>
<style>
    body { margin: 0; background: #f0f0f0; }
    canvas { background: #fff; border: 1px solid #ccc; }
</style>
</head>
<body>
<canvas id="canvas"></canvas>

<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

let startPoint = null;
let currentMouse = null;
let arrow = null;
let clickCount = 0;

// 箭头头部参数
const headLength = 15; // 箭头头部长度
const headWidth = 25;  // 箭头头部宽度

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // 第一次点击后,鼠标移动时就显示箭头
    if (startPoint && currentMouse && clickCount === 1) {
        const angle = angleBetweenPoints(startPoint.x, startPoint.y, currentMouse.x, currentMouse.y);

        // 箭身终点往回退 headLength
        const bodyEnd = shortenLine(currentMouse.x, currentMouse.y, angle, headLength);

        // 1. 绘制箭身(渐变线)
        drawGradientLine(startPoint.x, startPoint.y, bodyEnd.x, bodyEnd.y, 2, 10);

        // 2. 绘制箭头头部(三角形)
        drawArrowHead(currentMouse.x, currentMouse.y, angle, headWidth, headLength);
    }

    // 绘制最终箭头
    if (arrow) {
        const { x1, y1, x2, y2 } = arrow;
        const angle = angleBetweenPoints(x1, y1, x2, y2);

        // 箭身终点往回退 headLength
        const bodyEnd = shortenLine(x2, y2, angle, headLength);

        // 1. 绘制箭身(渐变线)
        drawGradientLine(x1, y1, bodyEnd.x, bodyEnd.y, 2, 10);

        // 2. 绘制箭头头部(三角形)
        drawArrowHead(x2, y2, angle, headWidth, headLength);
    }
}

// 绘制渐变线
function drawGradientLine(x1, y1, x2, y2, startWidth, endWidth) {
    const dx = x2 - x1;
    const dy = y2 - y1;
    const len = Math.sqrt(dx*dx + dy*dy);
    const steps = 50;
    const widthStep = (endWidth - startWidth) / steps;

    for (let i = 0; i < steps; i++) {
        const t = i / steps;
        const x = x1 + dx * t;
        const y = y1 + dy * t;
        const nextX = x1 + dx * (t + 1/steps);
        const nextY = y1 + dy * (t + 1/steps);

        ctx.beginPath();
        ctx.moveTo(x, y);
        ctx.lineTo(nextX, nextY);
        ctx.lineWidth = startWidth + widthStep * i;
        ctx.strokeStyle = '#333';
        ctx.stroke();
    }
}

// 绘制箭头头部
function drawArrowHead(x, y, angle, headWidth, headLength) {
    ctx.save();
    ctx.translate(x, y);
    ctx.rotate(angle);
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(-headLength, -headWidth/2);
    ctx.lineTo(-headLength, headWidth/2);
    ctx.closePath();
    ctx.fillStyle = '#333';
    ctx.fill();
    ctx.restore();
}

// 计算两点之间的角度
function angleBetweenPoints(x1, y1, x2, y2) {
    return Math.atan2(y2 - y1, x2 - x1);
}

// 计算缩短后的终点
function shortenLine(x, y, angle, length) {
    return {
        x: x - Math.cos(angle) * length,
        y: y - Math.sin(angle) * length
    };
}

canvas.addEventListener('mousedown', e => {
    const rect = canvas.getBoundingClientRect();
    const mx = e.clientX - rect.left;
    const my = e.clientY - rect.top;

    if (clickCount === 0) {
        startPoint = { x: mx, y: my };
        clickCount = 1;
    } else if (clickCount === 1) {
        arrow = { x1: startPoint.x, y1: startPoint.y, x2: mx, y2: my };
        startPoint = null;
        clickCount = 0;
    }
});

canvas.addEventListener('mousemove', e => {
    const rect = canvas.getBoundingClientRect();
    currentMouse = { x: e.clientX - rect.left, y: e.clientY - rect.top };
    draw();
});

draw();
</script>
</body>
</html>
相关推荐
weixin199701080162 小时前
《跨境二手ERP的3种对接模式:自研API / SaaS中间件 / 平台认证服务商,怎么选?》(附Python源码)
开发语言·python·中间件
传奇开心果编程4 小时前
【Rust入门知识点学与练】第24课:Trait 基础
开发语言·学习·rust
言乐610 小时前
Python加速器4跨境网络加速器
运维·服务器·开发语言·网络·python
金金计较.10 小时前
Go语言-3
java·开发语言·golang
张小凡vip11 小时前
python--爬虫--经验积累的遇到的坑
开发语言·爬虫·python
Wang's Blog11 小时前
Java框架快速入门: Spring Security+OAuth2之云服务集成与多因子认证设计
java·开发语言·spring
门思科技12 小时前
LoRaWAN 网络容量估算:一个 SX1302 网关到底能带多少设备
开发语言·网络·php
大草原的小灰灰12 小时前
Python基础语法
开发语言·python
雪芽蓝域zzs12 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
泡泡鱼(敲代码中)14 小时前
MySQL基础学习笔记:从数据模型到DDL全掌握
开发语言·数据库·笔记·学习·mysql