2

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");
    }
*/

キャンバスがこれをどのように処理しているかについての適切な説明が見つからないようです。MacOSX の Safari と Windows7 の Chrome および Firefox で同じ動作が得られます。

4

1 に答える 1

4

ここでは 2 つのことが行われています。

最初で最も重要なことは、決して電話をかけないことですcontext.beginPath()

新しい赤いアウトラインを描いていると思うたびに、実際にはコンテキストの現在のパスに追加して長くしています。最初にコンテキストに rect が 1 つだけある場合は、次に 2 つ、次に 3 つというようになります。

コンテキストの現在のパスにはそれらすべてが含まれているため、ストロークを呼び出すたびに、これまでに描画したすべての長方形をストロークしています。これを解決するには、 を呼び出して現在のパスをリセットする必要がありますbeginPath

2 つ目の問題は、線が完全なピクセルで描画されていないことです。線を消去すると、アンチエイリアシングによるグラフィックの問題が発生します。これを修正するには、完全なピクセルで描画し、消去する四角形に注意する必要があります。詳細については、Loktar の回答を参照してください: HTML5 Canvas and Line Width

これら2つの修正で実装されたコードは次のとおりです。

http://jsfiddle.net/QjKAp/

于 2012-07-20T15:50:26.733 に答える