Пытаетесь нарисовать прямоугольник на холсте, желательно в Javascript? - PullRequest
0 голосов
/ 04 апреля 2020

Я пытаюсь нарисовать прямоугольник, как в Paint. Но сейчас, когда я пытаюсь нарисовать прямоугольник, вот как выглядит мой холст - двойные рисунки, грязные прямоугольники.

Вот как выглядит весь мой код:

(удаленный код)

Как нарисовать прямоугольник, который выглядит следующим образом: как один прямоугольник?

Ответы [ 3 ]

0 голосов
/ 04 апреля 2020

Прежде всего, я думаю, что более понятно, если вы храните координаты в отдельных переменных вместо массива (startX, startY, lastX, lastY).

Также вы должны вычесть позицию холста из позиции мыши чтобы получить координату внутри холста, сейчас это своего рода работа, потому что холст находится в верхней части страницы.

Я вижу, вы хотите сохранить старое содержимое, я использовал холст для хранения предыдущего нарисованного содержимого, затем перед тем, как нарисовать текущий прямоугольник, вы должны перерисовать старое содержимое (используя ctx.drawImage).

Вы должны добавить 0,5 к координатам, чтобы линии не становились размытыми, это происходит, только если вы рисуете линия с нечетной шириной (1, 3, 5). это потому, что если вы попытаетесь нарисовать линию в 1 пиксель, скажем, по координате x = 1, вы должны нарисовать половину пикселя в обе стороны (от 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>
0 голосов
/ 04 апреля 2020

Контекст холста - очень мощная вещь, я предлагаю вам проверить все его свойства, методы 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>
0 голосов
/ 04 апреля 2020

Код, который вы публикуете, имеет массивы:
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();
<canvas height="100" width="300" id="c">

Только прямоугольники - ничто другое, никаких двойных рисунков или беспорядка, код, который вы предоставили, не должен вызывать проблем, подобных тому, что вы видите на картинке.


Это обновление на основе вашего нового кода ...

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()
<canvas id="myCanvas" width="300" height="160" style="border:1px solid #000000;" onmousedown="down()" onmousemove="move()" onmouseup="up()"> </canvas>

у вас был беспорядок переменных, я удалил все, что не обязательно для рисования прямоугольника, вы можете усложнить это позже, в любом случае вам нравится рисовать несколько объектов, но Я бы порекомендовал вам часто тестировать код, внося небольшие изменения, чтобы убедиться, что он выполняет то, что вам нужно

...