当前位置: 首页 > 知识库问答 >
问题:

HTML画布清晰绘制线

鲁旭
2023-03-14

我正在用HTML画布做一些工作,我发现当我画了一条线时,我无法清除或画出它?

所以我要做的是:我有一个带网格的画布,每个单元格在其中绘制自己(一个填充的矩形,在页面加载时完成),当鼠标在网格上时,应该勾勒出鼠标所在的单元格的轮廓(在画布上绘制四条线,没有其他重绘)。当鼠标移动到另一个单元格时,应勾勒出新单元格的轮廓(如前所述),而不应再勾勒出先前勾勒出的单元格的轮廓(目的是重新绘制单元格,绘制线条)。这是“取消概述”被证明是问题所在的单元。

我假设它使用了画家的算法,在画布上绘制的最后一件东西是可见的,但我得到的效果表明,填充的形状和线条是用更高层的线条分别处理的?

以下是演示它的独立页面的源代码:

<!DOCTYPE html>
<html>

<head>

<script type="text/javascript">


var CANVAS_DIMENSION = 200;
var CANVAS_WIDTH = 10;
var CANVAS_HEIGHT = 10;

var GRID_CELL_WIDTH = CANVAS_DIMENSION/CANVAS_WIDTH;
var GRID_CELL_HEIGHT = CANVAS_DIMENSION/CANVAS_HEIGHT;

var canvas;
var context;
var grid;
var mouseCellColumn = -1;
var mouseCellRow = -1;

function init()
{
    canvas = document.getElementById("myCanvas");

    context = canvas.getContext("2d");

    canvas.addEventListener('mousemove', updateMousePosition, false);

    grid = new Array(CANVAS_WIDTH);
    for (var i = 0; i < CANVAS_WIDTH; ++i)
    {
        grid[i] = new Array(CANVAS_HEIGHT);

        for (var j = 0; j < CANVAS_HEIGHT; ++j)
        {
            grid[i][j] = "#0000FF";
        }
    }

    renderScene()
}


function updateMousePosition(event)
{
    var initialColumn = mouseCellColumn;
    var initialRow = mouseCellRow;

    var objectPosition = findPos(this);

    var gridPosition = new Point(event.pageX - objectPosition.x, event.pageY - objectPosition.y);

    mouseCellColumn = getColumn(gridPosition.x);

    mouseCellRow = getRow(gridPosition.y);

    var cell_position = getCellPosition(mouseCellColumn, mouseCellRow);

    // outline the current cell
    drawRectangleOutlineWithColour(cell_position.x, 
                                   cell_position.y, 
                                   GRID_CELL_WIDTH, 
                                   GRID_CELL_HEIGHT, 
                                   "#FF0000");

    // if mouse has moved cell redraw
    if (((initialColumn != mouseCellColumn) ||
        (initialRow != mouseCellRow)) &&
        (initialColumn > -1) && 
        (initialRow > -1))
    {
        renderGridCell(initialColumn, initialRow);
    }

}


function renderScene()
{
    for (var i = 0; i < CANVAS_WIDTH; ++i)
    {
        for (var j = 0; j < CANVAS_HEIGHT; ++j)
        {
            renderGridCell(i, j);                
        }
    }
}


function renderGridCell(Column, Row)
{
    var position = getCellPosition(Column, Row);

    drawRectangleWithColour(position.x, 
                            position.y, 
                            GRID_CELL_WIDTH, 
                            GRID_CELL_HEIGHT, 
                            grid[Column][Row]);
}


function drawRectangleWithColour(minX, minY, width, height, colour)
{
    context.fillStyle = colour;

    context.fillRect(minX,
                     minY,
                     width,
                     height);
}


function drawRectangleOutlineWithColour(minX, minY, width, height, colour)
{
    context.strokeStyle = colour;

    context.moveTo(minX, minY);
    context.lineTo(minX + width, minY);
    context.moveTo(minX + width, minY);
    context.lineTo(minX + width, minY + height);
    context.moveTo(minX + width, minY + height);
    context.lineTo(minX, minY + height);
    context.moveTo(minX, minY + height);
    context.lineTo(minX, minY);

    context.stroke();
}


function Point(x, y)
{
    this.x = x;
    this.y = y;
}

function getColumn(xPosition)
{
    if (xPosition < 0)
    {
        xPosition = 0;
    }

    if (xPosition > CANVAS_DIMENSION)
    {
        xPosition = CANVAS_DIMENSION;
    }

    return Math.floor(xPosition/GRID_CELL_WIDTH);
}

function getRow(yPosition)
{
    if (yPosition < 0)
    {
        yPosition = 0;
    }

    if (yPosition > CANVAS_DIMENSION)
    {
        yPosition = CANVAS_DIMENSION;
    }

    return Math.floor(yPosition/GRID_CELL_HEIGHT);
}

function getCellPosition(column, row)
{
    if (row < 0)
    {
        row = 0;
    }

    if (row > CANVAS_HEIGHT)
    {
        row = CANVAS_HEIGHT - 1;
    }

    if (column < 0)
    {
        row = 0;
    }

    if (column > CANVAS_WIDTH)
    {
        column = CANVAS_WIDTH - 1;
    }

    var result = new Point(column * GRID_CELL_WIDTH, row * GRID_CELL_HEIGHT);
    return result;
}


function findPos(obj)
{
    var result = new Point(0, 0);

    if (obj.offsetParent)
    {
        do
        {
            result.x += obj.offsetLeft;
            result.y += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }

    return result;
}


</script>
</head>

<body onload="init()">


<div id="test" style="width: 200px; height:200px; margin: 0px auto;">
    <canvas id="myCanvas" width="200" height="200">
    Your browser does not support the canvas element.
    </canvas>
</div>

</body>
</html>

冒犯的地方在这里:

// outline the current cell
drawRectangleOutlineWithColour(cell_position.x, 
                               cell_position.y, 
                               GRID_CELL_WIDTH, 
                               GRID_CELL_HEIGHT, 
                               "#FF0000");

// if mouse has moved cell redraw
if (((initialColumn != mouseCellColumn) ||
    (initialRow != mouseCellRow)) &&
    (initialColumn > -1) && 
    (initialRow > -1))
{
    renderGridCell(initialColumn, initialRow);
}

这没有效果,轮廓会累积。

一些深入研究画布重画的人建议使用“clearRect”,但这似乎没有帮助,轮廓仍然存在:

// outline the current cell
drawRectangleOutlineWithColour(cell_position.x, 
                               cell_position.y, 
                               GRID_CELL_WIDTH, 
                               GRID_CELL_HEIGHT, 
                               "#FF0000");

// if mouse has moved cell redraw
if (((initialColumn != mouseCellColumn) ||
    (initialRow != mouseCellRow)) &&
    (initialColumn > -1) && 
    (initialRow > -1))
{
    context.clearRect(position.x, 
                      position.y, 
                      GRID_CELL_WIDTH, 
                      GRID_CELL_HEIGHT);

    renderGridCell(initialColumn, initialRow);
}

让我们用不同的颜色重新绘制轮廓区域?

// outline the current cell
drawRectangleOutlineWithColour(cell_position.x, 
                               cell_position.y, 
                               GRID_CELL_WIDTH, 
                               GRID_CELL_HEIGHT, 
                               "#FF0000");

// if mouse has moved cell redraw
if (((initialColumn != mouseCellColumn) ||
    (initialRow != mouseCellRow)) &&
    (initialColumn > -1) && 
    (initialRow > -1))
{
    var position = getCellPosition(initialColumn, initialRow);

    drawRectangleWithColour(position.x, 
                            position.y, 
                            GRID_CELL_WIDTH, 
                            GRID_CELL_HEIGHT, 
                            "#00FF00");
}

不,网格重新绘制,但对线条没有影响。重新绘制整个网格?

    renderScene();

    // outline the current cell
    drawRectangleOutlineWithColour(cell_position.x, 
                                   cell_position.y, 
                                   GRID_CELL_WIDTH, 
                                   GRID_CELL_HEIGHT, 
                                   "#FF0000");
/*
    // if mouse has moved cell redraw
    if (((initialColumn != mouseCellColumn) ||
        (initialRow != mouseCellRow)) &&
        (initialColumn > -1) && 
        (initialRow > -1))
    {
        var position = getCellPosition(initialColumn, initialRow);

        drawRectangleWithColour(position.x, 
                                position.y, 
                                GRID_CELL_WIDTH, 
                                GRID_CELL_HEIGHT, 
                                "#00FF00");
    }
*/

我似乎无法很好地解释canvas是如何处理这个问题的,我在MacOSX上的Safari和Windows7上的Chrome和Firefox中也有同样的行为。

共有1个答案

钱焕
2023-03-14

这里有两件事。

首先也是最重要的是,您永远不会调用context.beginPath()

每次你认为你在画一个新的红色轮廓时,你实际上是在添加上下文的当前路径并使其更长。第一次上下文只有一个矩形,然后它有两个,然后它有三个,等等。

每次调用stroke时,您都在对所绘制的每个矩形进行笔划,因为上下文的当前路径包含所有矩形。要解决此问题,必须通过调用beginPath重置当前路径。

第二个问题是,您的线条不是在完美像素上绘制的,因此当您删除它们时,您将看到由于抗锯齿而产生的图形问题。要解决这个问题,您需要绘制完美的像素,并注意要擦除的矩形。有关这方面的更多信息,请参见Loktar的答案:HTML5画布和线宽

以下是使用这两个修复程序实现的代码:

http://jsfiddle.net/QjKAp/

 类似资料:
  • 我目前正在使用画布开发一个JavaFX-Drawing-Application。在GraphicsContext的帮助下,我使用beginPath()和lineTo()方法绘制线条,但我无法找到实现橡皮擦的适当方法。

  • 我编写了这段代码,可以在JavaFX画布上绘制。它可以很好地工作,但我不知道如何重新绘制画布(比如在Swing中),以便在新画布上重新开始绘制。这是我的代码,非常感谢你的帮助!马里奥

  • 前面的例子中我们经常在各种样式之间切换,甚至有时候会在不同颜色之间反复切换。这种重复是很麻烦的,它意味着如果你想要返回之前使用的一些样式,必须重写大量的代码。 幸好,画布能够记住一些样式和属性,这样将来你就可以再次使用。这就是所谓的保存和恢复画布绘图状态。然而,问题是,如果要记住多个状态,操作起来可能令人困惑,因为你必须跟踪所有发生的变化。 画布绘图状态是什么 无论是在现实世界还是画布中,“状态”

  • 在这个例子中我们将使用画布(Canvas)创建一个简单的绘制程序。 在我们场景的顶部我们使用行定位器排列四个方形的颜色块。一个颜色块是一个简单的矩形,使用鼠标区域来检测点击。 Row { id: colorTools anchors { horizontalCenter: parent.horizontalCenter

  • 我想在HTML5画布/或SVG上执行以下操作: 有一个背景路径,将光标移过去并绘制(填充)背景路径 用户完成绘图后有回调函数 我的问题是,我不知道如何检查抽屉线是否遵循路径。 有人能给我解释一下如何做到这一点,或者给我一些建议吗? http://jsbin.com/reguyuxawo/edit?html,js,控制台,输出

  • 有没有可能通过它们的方程式在画布中画出曲线呢?如果是,怎么做?假设我有一个数学方程y=0,5*x^2,如何打印方程的图形? 我尝试使用和方法,但未成功。