【问题标题】:How do you draw a line from the last position of the mouse to the present position of the mouse?如何从鼠标的最后一个位置到鼠标的当前位置画一条线?
【发布时间】:2020-12-26 20:48:31
【问题描述】:

所以,我正在创建一些绘图工具,但是当我移动鼠标时,它不会在一条线上画圆。我不知道怎么说好,但我想让它从A点(鼠标的最后位置)到B点(鼠标的当前位置)画一条线。

从这里开始画,你就会明白:

const c = document.getElementById('c')
const ctx = c.getContext('2d')

c.height = window.innerHeight
c.width = window.innerWidth

function pen(e, colorHEX) {
    let mouseX = e.clientX
    let mouseY = e.clientY
    
    ctx.fillStyle = colorHEX
    ctx.beginPath()
    ctx.arc(mouseX, mouseY, 2, 0, Math.PI * 2)
    ctx.fill()
    ctx.closePath()
}

$('body').mousedown(function(eObj){
    $('body').mousemove(function(e) {
        pen(e, '#000000')
    })
})

$('body').mouseup(function(eObj) {
    $('body').unbind('mousemove')
})
body {
    margin: 0;
    overflow: hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
    <canvas id="c"></canvas>
    
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

【问题讨论】:

  • 鼠标按下获取坐标。移动鼠标并在鼠标上获取坐标。现在计算线 y=mx + b 的公式。然后循环点创建线
  • 嗯...你能解释一下慢一点吗?我不明白。如果可以的话,在代码中。

标签: javascript html5-canvas


【解决方案1】:

我认为您正在尝试绘制一条连续的线(您不需要通过画圆圈来做到这一点)。您需要存储最后一个鼠标位置,然后从那里画一条线到当前鼠标位置。

const c = document.getElementById('c')
const ctx = c.getContext('2d')

c.height = window.innerHeight
c.width = window.innerWidth

let lastPos // state variable

function pen(e, colorHEX) {
     
    const pos = {x:e.clientX, y: e.clientY}
    lastPos = (lastPos || pos) // Default to current pos
    
    ctx.beginPath()
    ctx.strokeStyle = colorHEX
    ctx.lineWidth = 1
    ctx.moveTo(lastPos.x, lastPos.y)
    ctx.lineTo(pos.x, pos.y)
    ctx.stroke()
    ctx.closePath()

    // Update the state variable
    lastPos = pos
}

$('body').mousedown(function(eObj){
    $('body').mousemove(function(e) {
        pen(e, '#000000')
    })
})

$('body').mouseup(function(eObj) {
    $('body').unbind('mousemove')
    lastPos = undefined
})
body {
    margin: 0;
    overflow: hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
    <canvas id="c"></canvas>
    
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

【讨论】:

  • 这很好用,但是当我添加圈子时,它会中断。因为,如果您只想要屏幕上的一个点,它看起来就像一条线,但用户想要一个点。
【解决方案2】:

你可以使用 lineTo 方法

要在拖动线条时让它移动,需要一个包含角度和数学的额外脚本。

const c = document.getElementById('c')
const ctx = c.getContext('2d')

c.height = window.innerHeight
c.width = window.innerWidth

let startX;
let startY;





function pen(e, colorHEX) {
    let endX = e.clientX
    let endY = e.clientY
    
    ctx.fillStyle = colorHEX
    ctx.beginPath()
    ctx.moveTo(startX, startY)
    ctx.lineTo(endX, endY)
    ctx.fill()
    ctx.closePath()
    ctx.stroke()
}

$('body').mousedown(function(e){
    startX = e.clientX;
    startY = e.clientY;
})

$('body').mouseup(function(e) {
    pen(e, "#000000");
})
body {
    margin: 0;
    overflow: hidden;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
    <canvas id="c"></canvas>
    
    <script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

【讨论】:

  • 我不希望它画一条线,但我希望它画一条由组成的线,但不一定是直线. A - - - - - - - - - - B
【解决方案3】:

用鼠标绘图

你有两个选择。

  1. 从 A 到 B 绘制一条线段,设置线宽以匹配圆的直径并将线帽设置为圆形。

  2. 插入从 A 到 B 的点,在相距 1px 的点处绘制一个圆(或任何形状)。

  3. 我说了两个,但有无数种方法可以做这类事情,但这会将这个答案归入 TLDR 类别。

您使用哪种方法将取决于您的需求的更详细的细节。下面的两个例子使用最基本的实线绘制看起来是一样的。

我认为您可能遇到的问题是因为您正在打开和关闭事件侦听器,您的最后一个鼠标位置是最后一个鼠标。

我添加了两个示例。每个绘图选项一个,最上面的一个使用始终打开的鼠标侦听器,第二个根据需要打开和打开鼠标侦听器。

示例

鼠标将其状态放入名为mouse 的对象中。

每次鼠标改变位置时,最后一个位置被放入mouse.lastXmouse.lastY

如果鼠标event.typemousedown,则mouse.button 设置为true,如果mouseup 则设置为false

鼠标上下也用于打开和关闭光标等操作,添加和删除事件(第二个示例)

在侦听器的底部,它检查鼠标是否已按下(mouse.buttontrue)并从最后一个位置到当前位置绘制一条线。

使用线段

  • 使用 2D API 的笔画函数进行绘制。
  • 始终在鼠标侦听器上使用。

const ctx = c.getContext('2d');
const BORDER = 1;  // I added a 1px border to canvas.
c.height = innerHeight - BORDER * 2;
c.width = innerWidth - BORDER * 2;
const mouse = {x: 0, y: 0, lastX: 0, lastY: 0, button: false};
function drawLine(xA, yA, xB, yB, col, width) {
    ctx.strokeStyle = col;
    ctx.lineCap = "round";
    ctx.lineWidth = width;

    ctx.beginPath()
    ctx.lineTo(xA, yA);
    ctx.lineTo(xB, yB);
    ctx.stroke();
}

function mouseEvent(e) {
    if (e.type === "mousedown") { 
        mouse.button = true; 
        c.classList.add("hideMouse");
    } else if (e.type === "mouseup") { 
        mouse.button = false;
        c.classList.remove("hideMouse");
    }

    mouse.lastX = mouse.x;
    mouse.lastY = mouse.y;
    mouse.x = e.clientX - BORDER;
    mouse.y = e.clientY - BORDER;

    if (mouse.button) {        
        drawLine(mouse.lastX, mouse.lastY, mouse.x, mouse.y, "#000", 4);
    }
}
addEventListener("mousedown", mouseEvent);
addEventListener("mouseup",   mouseEvent); 
addEventListener("mousemove", mouseEvent);
body {
    margin: 0;
    overflow: hidden;
    font-family: arial;
}
canvas {
    border: 1px solid black;
    cursor: crosshair;
}
.hideMouse {
    cursor: none;
}
div {
    background: #FFF8;
    position: absolute;
    top: 4px;
    left: 4px;    
}
<canvas id="c"></canvas>
<div>Click and drag mouse to draw</div>

插值线

  • 用插值算法替换drawLine函数体。

  • mousedown 上添加鼠标侦听器mousemovemouseup。请注意,up 监听器在添加时具有选项{once:true},因此不需要手动删除。

const ctx = c.getContext('2d');
const BORDER = 1;  // I added a 1px border to canvas.
c.height = innerHeight - BORDER * 2;
c.width = innerWidth - BORDER * 2;
const mouse = {x: 0, y: 0, lastX: 0, lastY: 0, button: false};

function drawLine(xA, yA, xB, yB, col, width) {
    var i = 0;
    const dx = xB - xA;
    const dy = yB - yA;
    const length = Math.hypot(dx, dy);
    const stepX = length > 0 ? dx / length : 0;
    const stepY = length > 0 ? dy / length : 0;
    ctx.beginPath();
    ctx.fillStyle = col;
    while (i <= length) {
        ctx.moveTo(xA + width / 2, yA);
        ctx.arc(xA, yA, width / 2, 0, Math.PI * 2);
        xA += stepX;
        yA += stepY;
        i ++;            
    }
    ctx.fill();
}

function mouseEvent(e) {
    if (e.type === "mousedown") { 
        mouse.button = true; 
        c.classList.add("hideMouse");
        addEventListener("mouseup",   mouseEvent, {once: true});
        addEventListener("mousemove", mouseEvent);

        // Set mouse pos so last pos is not where the last mouse up was
        mouse.x = e.clientX - BORDER;
        mouse.y = e.clientY - BORDER;
    } else if (e.type === "mouseup") { 
        mouse.button = false;
        c.classList.remove("hideMouse");
        removeEventListener("mousemove", mouseEvent);
    }

    mouse.lastX = mouse.x;
    mouse.lastY = mouse.y;
    mouse.x = e.clientX - BORDER;
    mouse.y = e.clientY - BORDER;

    if (mouse.button) {        
        drawLine(mouse.lastX, mouse.lastY, mouse.x, mouse.y, "#000", 4);          
    }
}
addEventListener("mousedown", mouseEvent);
body {
    margin: 0;
    overflow: hidden;
    font-family: arial;
}
canvas {
    border: 1px solid black;
    cursor: crosshair;
}
.hideMouse {
    cursor: none;
}
div {
    background: #FFF8;
    position: absolute;
    top: 4px;
    left: 4px;    
}
 <canvas id="c"></canvas>
 <div>Click and drag mouse to draw</div>

旁注...

jQuery 已死

BTW jQuery 是不需要的,它在 5 年前就变得无关紧要了。

使用它会让您落后于现代前端开发很多年。

在过去的 5 年中,对 jQuery 体验编码器的需求大幅下降。这种趋势将继续,因为 jQuery 将自己描绘成一个角落,唯一的出路是通过重新塑造品牌和重新定位其目的。

每次使用 jQuery,您都在投入您最宝贵的资产,即时间。时间花在学习和获得经验上。那时要明智而直接地了解什么是适用的和在未来发展的,而不是了解十多年前开始消亡的东西。

更多详情Should you use or learn jQuery in 2020?

【讨论】:

    猜你喜欢
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多