【问题标题】:Trying to SKETCH a rectangle on canvas, preferably in Javascript?试图在画布上绘制一个矩形,最好是在 Javascript 中?
【发布时间】:2020-04-03 21:57:16
【问题描述】:

我正在尝试绘制一个矩形,就像您在 Paint 中所做的那样。 But currently when I try to sketch a rectangle, this is what my canvas looks like--double drawings, messy rectangles.

这就是我的整个代码的样子:

(已删除的代码)

如何绘制一个如下所示的矩形:like one rectangle?

【问题讨论】:

  • 问题需要独立且具体。
  • 您可能需要在每次重绘之前使用clearRect(或其他)清除脏区。
  • 我建议在您的问题中发布您的代码。如果你想让它显示得很好,你可以使用降价。这将帮助您更好地回答您的问题
  • @rayhatfield:我不想清除所有的画布,只是为了张贴它被拖动以形成最终矩形的形状,如果这有意义吗?
  • @intuitiveprogramming 请发布完整代码以查看您需要更改的内容

标签: javascript canvas shapes sketching


【解决方案1】:

首先,我认为将坐标存储在单独的变量中而不是数组(startX、startY、lastX、lastY)中会更清楚。

此外,您应该从鼠标位置中减去画布位置以获得画布内的坐标,现在它有点工作,因为画布位于页面顶部。

我看到你想保留旧内容,我使用了一个画布来存储之前绘制的内容,然后在绘制当前矩形之前你必须重新绘制旧内容(使用 ctx.drawImage)。

您应该在坐标上添加 0.5,这样线条才不会变得模糊,这仅在您绘制奇数宽度(1、3、5)的线条时才会发生。这是因为如果您尝试在坐标 x=1 上绘制 1px 线,则必须在两侧(0.5 到 1.5)绘制半个像素,因此看起来很模糊。

但如果你在 x=0.5 处绘制它,你会绘制从 0 到 1 的线,这正好是一个像素。

var isDown = false;
var startX, startY;
var lastX, lastY;

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var canvasRect = canvas.getBoundingClientRect();

var backBuffer = canvas.cloneNode(true);
var backBufferCtx = backBuffer.getContext('2d');

canvas.addEventListener('mousedown', function down() {
    startX = event.clientX - canvasRect.left;
    startY = event.clientY - canvasRect.top;
    isDown = true;
});

canvas.addEventListener('mouseup', function up() {
    isDown = false;

    // Draw Current Canvas Content
    updateCanvas();

    // Save current content
    backBufferCtx.clearRect(0, 0, backBuffer.width, backBuffer.height);
    backBufferCtx.drawImage(canvas, 0, 0);
});

canvas.addEventListener('mousemove', function move() {
    if (! isDown) return;

    lastX = event.clientX - canvasRect.left;
    lastY = event.clientY - canvasRect.top;
    updateCanvas();
});

function updateCanvas() {
    // Clear the canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Draw Current Canvas Content
    ctx.drawImage(backBuffer, 0, 0);

    // Draw New Rectangle
    ctx.beginPath();
    // add 0.5 so the line do not get blurry
    ctx.rect(startX + 0.5, startY + 0.5, lastX - startX, lastY - startY);
    ctx.stroke();
}
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000; margin-top: 100px"></canvas>

【讨论】:

  • 酷,这行得通!有没有更简单的方法,比如使用 .todataURL 并将旧版本放在笔画之前?因为在丢失该代码之前,我在原始版本中做了类似的事情。
  • @intuitiveprogramming 我认为这是更简单的方法,因为您可以使用其他画布(后缓冲区)作为图像,但是使用 toDataURL 您需要创建图像并将 image.src 设置为之前的 dataurl你可以把它画在画布上。
  • 知道了!感谢您的帮助!
【解决方案2】:

您发布的代码有数组:
ctx.rect(x[x1],y[y1]
但我猜你画的不仅仅是矩形......

这是一个示例:

ctx = document.getElementById('c').getContext('2d');
ctx.lineWidth = 2;
x = [5, 30, 90]
y = [5, 50, 30]

for (i = 0; i < x.length; i++) {
  ctx.rect(x[i], y[i], 50, 20)
}
ctx.stroke();
&lt;canvas height="100" width="300" id="c"&gt;

只是矩形而已,没有重复绘图或混乱,您提供的代码不应导致任何问题,例如您在图片中显示的内容。


这是基于您的新代码的更新...

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
ctx.lineWidth = 2;

var x = 0;
var y = 0;
draw = false;

function down() {
  x = event.clientX;
  y = event.clientY;
  draw = true;
}

function move() {
  if (draw) {
    var a = event.clientX;
    var b = event.clientY;

    ctx.clearRect(0, 0, canvas.width, canvas.height)
    addCircles()
    ctx.beginPath()
    ctx.rect(x, y, a - x, b - y);
    ctx.stroke();
  }
}

function up() {
  draw = false
}


function addCircles() {
  ctx.beginPath()
  ctx.fillStyle = '#F00';
  ctx.arc(50, 50, 30, 0, Math.PI * 2)
  ctx.fill();
  ctx.beginPath()
  ctx.fillStyle = '#0F0';
  ctx.arc(100, 100, 30, 0, Math.PI * 2)
  ctx.fill();
  ctx.beginPath()
  ctx.fillStyle = '#00F';
  ctx.arc(200, 80, 30, 0, Math.PI * 2)
  ctx.fill();
}


addCircles()
&lt;canvas id="myCanvas" width="300" height="160" style="border:1px solid #000000;" onmousedown="down()" onmousemove="move()" onmouseup="up()"&gt; &lt;/canvas&gt;

你有一堆变量,我删除了绘制矩形不是绝对需要的所有东西,你以后可能会复杂化,无论如何你想绘制多个对象,但我建议你经常测试你的代码,小的增量更改确保它做你想做的事。

【讨论】:

  • 不,我的代码有 mousedown 坐标 (x[x1],y[y1]) 和 mousemove 坐标 (x[x2],y[y2])。我不想对矩形进行编程以显示在画布上。想要创建一个矩形,就像在 Paint 中一样。
  • @intuitiveprogramming 根据你的完整代码查看我的更新
  • 有没有 clearrect 的替代品?喜欢 canvas.todataURL 吗?因为我想保留画布上可能存在的其他东西。所以我不想每次画一个矩形时都清除画布。
  • 很遗憾,您每次都必须清除画布,但您可以重新绘制您需要的所有内容,让我做一个小样本给您看
  • @intuitiveprogramming 我添加了一个绘制多个对象的示例,每次都清除画布,剩下的就看你了
【解决方案3】:

画布的上下文是一个非常强大的东西,我建议你在https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D上查看它的所有属性、方法

特别是对于您的用例:上下文提供了直接读写画布数据的方法,getImageData()-putImageData() 是该方法对。使用它们,您可以在用户开始绘制新矩形时存储画布包含的任何内容,并在调整当前矩形大小时恢复它。存储的数据甚至可以作为副产品提供一步“撤消”功能:

var cnv=document.getElementById("cnv"),
    ctx=cnv.getContext("2d"),
    col=document.getElementById("color"),
    ubtn=document.getElementById("undo"),
    copy,
    pick=false;

function mdown(event){
  copy=ctx.getImageData(0,0,cnv.width,cnv.height);
  pick={
    x:event.offsetX,
    y:event.offsetY
  };
}

function mup(event){
  pick=false;
  ubtn.disabled=false;
}

function mmove(event){
  if(pick){
    ctx.putImageData(copy,0,0);
    ctx.strokeStyle=col.value;
    ctx.lineWidth=2;
    ctx.strokeRect(pick.x,pick.y,event.offsetX-pick.x,event.offsetY-pick.y);
  }
}

function undo(){
  ctx.putImageData(copy,0,0);
  ubtn.disabled=true;
}
<input type="color" id="color"><button id="undo" disabled onclick="undo()">Undo</button><br>
<canvas id="cnv" width="300" height="140" style="border:1px solid black;cursor:crosshair" onmousedown="mdown(event)" onmousemove="mmove(event)" onmouseup="mup(event)"></canvas>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 2014-04-30
    相关资源
    最近更新 更多