• H5 Canvas 越线绘制页面


    效果

    ⚠ 因为使用的是斜率来处理的垂直逻辑 tan,当为被除数为0时做了特殊处理,两点自由变换时到达零界点会有卡顿。

    image

    推导

    开始复习初中二年级数学知识

    斜率k的公式: k = ( y 1 − y 2 ) ( x 1 − x 2 ) k = \dfrac{(y_1 -y_2)}{(x_1 - x_2)} k=(x1x2)(y1y2)

    两条垂直相交直线的斜率相乘积为-1: k 1 × k 2 = − 1 k_1 \times k_2 = -1 k1×k2=1

    如图已知 P 1 P_1 P1 P 2 P_2 P2的坐标,以及d的值,求点 P 4 P_4 P4的坐标。 😂怀念初中算题的生活
    image
    ⚠ 仅个人观点非正确答案

    k 1 × k 2 = − 1 k_1 \times k_2 = -1 k1×k2=1

    设:

    P 1 P 2 P_1P_2 P1P2的斜率为 k 1 k_1 k1
    P 3 P 4 P_3P_4 P3P4的斜率为 k 2 k_2 k2

    k 1 = ( y 2 − y 1 ) ( x 2 − x 1 ) k_1 = \dfrac{(y_2 -y_1)}{(x_2 - x_1)} k1=(x2x1)(y2y1)
    k 2 = ( y 4 − y 3 ) ( x 4 − x 3 ) k_2 = \dfrac{(y_4 -y_3)}{(x_4 - x_3)} k2=(x4x3)(y4y3)

    k 1 × ( y 4 − y 3 ) ( x 4 − x 3 ) = − 1 k_1 \times \dfrac{(y_4 -y_3)}{(x_4 - x_3)}=-1 k1×(x4x3)(y4y3)=1

    根据勾股定理可知

    d = ( y 4 − y 3 ) 2 + ( x 4 − x 3 ) 2 d = \sqrt{(y_4 -y_3)^2 + (x_4 - x_3)^2} d=(y4y3)2+(x4x3)2

    可知下列俩公式

    ( y 4 − y 3 ) = d 2 − ( x 4 − x 3 ) 2 (y_4 -y_3)=\sqrt{d^2 - (x_4 - x_3)^2} (y4y3)=d2(x4x3)2

    ( y 4 − y 3 ) = − ( x 4 − x 3 ) k 1 (y_4 -y_3)=-\dfrac{ (x_4 - x_3)}{k_1} (y4y3)=k1(x4x3)

    合并继续推

    d 2 − ( x 4 − x 3 ) 2 = − ( x 4 − x 3 ) k 1 \sqrt{d^2 - (x_4 - x_3)^2}=-\dfrac{ (x_4 - x_3)}{k_1} d2(x4x3)2 =k1(x4x3)

    d 2 − ( x 4 − x 3 ) 2 = ( x 4 − x 3 ) 2 k 1 2 d^2 - (x_4 - x_3)^2=\dfrac{ (x_4 - x_3)^2}{k_1^2} d2(x4x3)2=k12(x4x3)2

    ( x 4 − x 3 ) 2 k 1 2 + ( x 4 − x 3 ) 2 = d 2 \dfrac{ (x_4 - x_3)^2}{k_1^2}+(x_4 - x_3)^2=d^2 k12(x4x3)2+(x4x3)2=d2

    ( x 4 − x 3 ) 2 × ( 1 k 1 2 + 1 ) = d 2 (x_4 - x_3)^2 \times (\dfrac{1}{k_1^2} + 1)=d^2 (x4x3)2×(k121+1)=d2

    ( x 4 − x 3 ) 2 = d 2 1 k 1 2 + 1 (x_4 - x_3)^2 =\dfrac{d^2}{\dfrac{1}{k_1^2} + 1} (x4x3)2=k121+1d2

    可知

    ( x 4 − x 3 ) = d 2 1 k 1 2 + 1 (x_4 - x_3)=\sqrt{\dfrac{d^2}{\dfrac{1}{k_1^2} + 1}} (x4x3)=k121+1d2
    ( y 4 − y 3 ) = − ( x 4 − x 3 ) k 1 (y_4 - y_3)=-\dfrac{ (x_4 - x_3)}{k_1} (y4y3)=k1(x4x3)

    代码

    获取坐标点

    x 4 x_4 x4 y 4 y_4 y4套入公式中的 ( x 4 − x 3 ) (x_4 - x_3) (x4x3) ( y 4 − y 3 ) (y_4 - y_3) (y4y3)

    // 已知 A⊥B 则 斜率 k1 * k2 = -1
    // 因 k1 = (y2 - y1)/(x2 - x1) 
    // 所以 (y4 - y3)/(x4 - x3) = - (y2 - y1)/(x2 - x1) 
    let x1 = startX
    let y1 = startY
    let x2 = endX
    let y2 = endY
    
    let k = (y2 - y1) / (x2 - x1)
    
    
    let y3 = (y1 + y2) / 2
    let x3 = (x1 + x2) / 2
    
    // 设 d 为箭头末端距离线的距离
    let d = 20;
    
    let x4 = 0
    let y4 = 0
    if (x1 == x2) x4 = Math.sign(redirect) * d;
    else if (y1 == y2) y4 = Math.sign(redirect) * d;
    else {
        x4 = Math.sign(redirect) * Math.sqrt(Math.pow(d, 2) / (1 + Math.pow(1 / k, 2)))
        y4 = - 1 / k * x4;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    其中redirect是指对应方向

    绘制箭头
    // 获得角度
    let a = Math.atan2(y4, x4) * 180 / Math.PI
    // 角度偏移值
    a += 90
    // 角度转弧度
    let rd = a * Math.PI / 180
    // 保存画布
    ctx.save()
    // 移动画布
    ctx.translate(x4 + x3, y4 + y3)
    // 旋转画布
    ctx.rotate(rd)
    // 绘制箭头
    ctx.drawImage(arrowImage, -10, -20, 20, 22)
    // 画布还原
    ctx.rotate(-rd)
    ctx.translate(-x4 - x3, -y4 - y3)
    ctx.restore()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    源码

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title> 画垂直线</title>
    
        <style>
            body {
                text-align: center;
            }
    
            #line {
                width: 600px;
                height: 600px;
                border: 1px solid #ddd;
                margin: 20px auto;
            }
        </style>
    
    
    </head>
    
    <body>
        <canvas id="line"></canvas>
    
        <button id="changeRedirect">切换方向</button>
    
        <script>
    
            var arrow = `data:image/png;base64,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`
    
            var arrowImage = new Image()
    
            arrowImage.src = arrow;
    
            var c = document.getElementById("line");
    
            var b = document.getElementById('changeRedirect')
    
            /** @type {CanvasRenderingContext2D} */
            var ctx = c.getContext("2d");
            c.width = c.clientWidth
            c.height = c.clientHeight
    
            var isDown = false;
            var startX = 0;
            var startY = 0;
            var endX = 0;
            var endY = 0
    
            var lasttime = +new Date()
            var timeoutId = null
            var interval = 20
            var redirect = 1;
    
            function rendering() {
                // 节流 
                // 不怎么会 仅供参考
                if (+new Date() - lasttime < interval) {
                    if (!timeoutId)
                        timeoutId = setTimeout(() => {
                            rendering()
                            clearTimeout(timeoutId)
                            timeoutId = null
                        }, 100)
                    return;
                }
                lasttime = +new Date()
                clearTimeout(timeoutId)
                // 清理画布
                ctx.clearRect(0, 0, c.clientWidth, c.clientHeight);
    
                ctx.strokeStyle = "rgb(18,150,219)"
                // 开始路径
                ctx.beginPath();
                // 移动点到开始位置
                ctx.moveTo(startX, startY);
                // 连接到结束点
                ctx.lineTo(endX, endY);
                // 结束
                ctx.stroke();
    
                // 已知 A⊥B 则 斜率 k1 * k2 = -1
                // 因 k1 = (y2 - y1)/(x2 - x1) 
                // 所以 (y4 - y3)/(x4 - x3) = - (y2 - y1)/(x2 - x1) 
                let x1 = startX
                let y1 = startY
                let x2 = endX
                let y2 = endY
    
                let k = (y2 - y1) / (x2 - x1)
    
    
                let y3 = (y1 + y2) / 2
                let x3 = (x1 + x2) / 2
    
                // 设 d 为箭头末端距离线的距离
                let d = 20;
    
                let x4 = 0
                let y4 = 0
                if (x1 == x2) x4 = Math.sign(redirect) * d;
                else if (y1 == y2) y4 = Math.sign(redirect) * d;
                else {
                    x4 = Math.sign(redirect) * Math.sqrt(Math.pow(d, 2) / (1 + Math.pow(1 / k, 2)))
                    y4 = - 1 / k * x4;
                }
    
                // 获得角度
                let a = Math.atan2(y4, x4) * 180 / Math.PI
                // 角度偏移值
                a += 90
                // 角度转弧度
                let rd = a * Math.PI / 180
                // 保存画布
                ctx.save()
                // 移动画布
                ctx.translate(x4 + x3, y4 + y3)
                // 旋转画布
                ctx.rotate(rd)
                // 绘制箭头
                ctx.drawImage(arrowImage, -10, -20, 20, 22)
                // 画布还原
                ctx.rotate(-rd)
                ctx.translate(-x4 - x3, -y4 - y3)
                ctx.restore()
    
                // 辅助线
                // 开始路径
                // ctx.beginPath();
                // 移动点到开始位置
                // ctx.moveTo(x3, y3);
                // 连接到结束点
                // ctx.lineTo(x4 + x3, y4 + y3);
                // 结束
                // ctx.stroke();
            }
            c.addEventListener('mousedown', (ev) => {
                // console.log(ev);
                isDown = true;
                ctx.clearRect(0, 0, c.clientWidth, c.clientHeight);
    
                startX = ev.offsetX;
                startY = ev.offsetY;
                endX = ev.offsetX;
                endY = ev.offsetY
            })
            c.addEventListener('mousemove', (ev) => {
                // console.log(ev);
                if (!isDown) return;
                endX = ev.offsetX;
                endY = ev.offsetY;
                rendering();
            })
            document.addEventListener('mouseup', (ev) => {
                // console.log(ev);
                isDown = false
            })
            b.addEventListener('click', (ev) => {
                redirect *= -1;
                rendering()
            })
        </script>
    </body>
    
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
  • 相关阅读:
    从零开始在window10系统下mysql5.7安装审计插件(亲测绝对可用)
    SpringBoot整合Docker实现一次构建到处运行
    CE修改器入门:运用代码注入
    @Profile注解多环境
    MySQL之CRUD
    LuatOS-SOC接口文档(air780E)-- gmssl - 国密算法
    JS严格模式(精简分析,快速掌握)
    鸿蒙App基础
    基于pycharm对每个工程配置python环境
    npm run dev和npm run serve两个命令的区别
  • 原文地址:https://blog.csdn.net/linyisonger/article/details/128164307