在Canvas中实现选中直线

先上图

代码
<!DOCTYPE html>
<html>
<head>
    <title>选中Canvas中的直线</title>
</head>
<body>
    <canvas id="myCanvas">Your browser does not support HTML5 Canvas. </canvas>
</body>
</html>
<script type="text/javascript">
    var myCanvas = document.getElementById("myCanvas");
    myCanvas.style.cssText = "position:absolute;left:0;top:0; border: 1px solid #ccc;"; // 画布样式
    myCanvas.width = 800;   // 画布的宽度
    myCanvas.height = 800;  // 画布的高度 
    var ctx = myCanvas.getContext('2d');

    var a = 300, b = 300;   // 原点        
    var lines = [
        { p1: { x: a, y: b }, p2: { x: a + 200, y: b }, flag: 0, },       // 原点右移200px;
        { p1: { x: a, y: b }, p2: { x: a, y: b - 200 }, flag: 0 },        // 原点上移200px;    
        { p1: { x: a, y: b }, p2: { x: a - 200, y: b }, flag: 0 },        // 原点左移200px;    
        { p1: { x: a, y: b }, p2: { x: a, y: b + 200 }, flag: 0 },        // 原点下移200px;    
        { p1: { x: a, y: b }, p2: { x: a + 100, y: b - 80 }, flag: 0 },   // 第1象限        
        { p1: { x: a, y: b }, p2: { x: a - 100, y: b - 100 }, flag: 0 },  // 第2象限
        { p1: { x: a, y: b }, p2: { x: a - 100, y: b + 100 }, flag: 0 },  // 第3象限
        { p1: { x: a, y: b }, p2: { x: a + 100, y: b + 80 }, flag: 0 },   // 第4象限
        { p1: { x: 100, y: 580 }, p2: { x: 200, y: 550 }, flag: 0 },
        { p1: { x: 200, y: 580 }, p2: { x: 300, y: 600 }, flag: 0 },
        { p1: { x: 80, y: 520 }, p2: { x: 10, y: 450 }, flag: 0 },
        { p1: { x: 10, y: 490 }, p2: { x: 60, y: 480 }, flag: 0 },
    ];

    // 画线
    drawAllLines();

    // Click 事件
    myCanvas.onclick = function (e) {
        // 鼠标点击的坐标
        var px = e.clientX,
            py = e.clientY;

        // 逐条线确定是否有点中
        var offset = 5;                         // 可接受(偏移)范围
        for (var i = 0; i < lines.length; i++) {
            var p1 = lines[i].p1;               // 直线起点
            var p2 = lines[i].p2;               // 直线终点 
            var flag = 0;                       // 1 - 点中
            var minX = Math.min(p1.x, p2.x);    // 较小的X轴坐标值
            var maxX = Math.max(p1.x, p2.x);    // 较大的X轴坐标值
            var minY = Math.min(p1.y, p2.y);    // 较小的Y轴坐标值
            var maxY = Math.max(p1.y, p2.y);    // 较大的Y轴坐标值

            if (p1.y === p2.y) {
                // 水平线
                if ((px >= minX && px <= maxX) && (py >= minY - offset && py <= maxY + offset)) {
                    flag = 1;
                    lines[i].crossPoint = { x: px, y: p1.y };         // 直线上交叉点  
                }

            }
            else if (p1.x === p2.x) {
                // 垂直线
                if ((py >= minY && py <= maxY) && (px >= minX - offset && px <= maxX + offset)) {
                    flag = 1;
                    lines[i].crossPoint = { x: p1.x, y: py };       // 直线上交叉点  
                }
            }
            else {
                // 斜线 (先判断点是否进入可接受大范围(矩形),然后再根据直线上的交叉点进行小范围比较)
                if ((px >= minX && px <= maxX) && (py >= minY - offset && py <= maxY + offset)) {
                    //求Y轴坐标
                    //方法1:根据tanθ= y/x = y1/x1, 即y = (y1/x1)*x  (该方法有局限性,垂直线(p2.x - p1.x)=0,不能用)
                    //var y = ((p2.y - p1.y) / (p2.x - p1.x)) * (px - p1.x);

                    //方法2:先求弧度hudu,根据cosθ=x/r, r=x/cosθ,求得r,再根据sinθ=y/r, y=sinθ*r, 求得y 
                    var hudu = Math.atan2(p2.y - p1.y, p2.x - p1.x);        // 直线的弧度(倾斜度)
                    // 用三角函数计出直线上的交叉点
                    var r = (px - p1.x) / Math.cos(hudu);                   // 直角三角形的斜边(或理解成圆的半径)
                    var y = Math.sin(hudu) * r;                             // Y轴坐标

                    var p = { x: px, y: p1.y + y };                         // 直线上的交叉点
                    if ((Math.abs(px - p.x) <= offset) && (Math.abs(py - p.y) <= offset)) {
                        flag = 1;                                           // 1 - 点中
                    }
                    lines[i].crossPoint = p;                                // 直线上的交叉点
                }
            }

            if (flag === 1) {
                lines[i].flag = ((lines[i].flag + 1) % 2);                  // 0、1切换
                break;
            }
        }
        // 重画线
        drawAllLines();
    };

    // 画所有线函数
    function drawAllLines() {
        // 清空画布
        ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);

        // 画出逐条线
        for (var i = 0; i < lines.length; i++) {
            var color = lines[i].flag === 1 ? "orange" : "blue";

            drawLine(ctx, lines[i].p1, lines[i].p2, color);

            // 画交叉点
            if (lines[i].crossPoint) {
                drawPoint(lines[i].crossPoint.x, lines[i].crossPoint.y);
            }
            lines[i].crossPoint = null;
        }
    }

    // 画单条线函数
    function drawLine(ctx, p1, p2, color) {
        color = color || 'blue';
        ctx.strokeStyle = color;
        ctx.beginPath();
        ctx.moveTo(p1.x, p1.y);
        ctx.lineTo(p2.x, p2.y);
        ctx.stroke();
        ctx.closePath();

        // 计算弧度
        var hudu = Math.atan2(p2.y - p1.y, p2.x - p1.x);
        var msg = "x:" + p2.x + " y:" + p2.y + " 弧度:" + hudu + " (rad)";
        // 线长 
        var l1 = Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
        msg = msg + " 线长: " + l1;

        ctx.fillText(msg, p2.x, p2.y);
    }

    // 画圆点
    function drawPoint(x, y, color) {
        color = color || 'red';
        ctx.strokeStyle = color;
        ctx.beginPath();
        ctx.arc(x, y, 2, 0, 2 * Math.PI);
        ctx.stroke();
        ctx.closePath();
    }
</script>






猜你喜欢

转载自blog.csdn.net/chelen_jak/article/details/80593166
今日推荐