JS холст белые линии при масштабировании - PullRequest
0 голосов
/ 27 января 2019

Использование JavaScript Я отображаю массив на холсте HTML 5.Программа использует c.fillRect() для каждого значения в массиве.Все выглядит нормально, пока я не масштабирую его, используя c.scale().После масштабирования белые квадраты видны между квадратами.Я знаю их белый цвет, потому что это цвет фона (когда фон меняет цвет, их цвет тоже меняется).

Поскольку квадраты расположены на расстоянии 5 единиц, я попытался установить их ширину 5,5 вместо 5;это только удаляет белые линии при увеличении достаточно далеко, но при уменьшении белые линии все еще были там.

Это мой код (ненужные детали удалены):

function loop()
{
    c.resetTransform();

    c.fillStyle = "white";
    c.fillRect(0, 0, c.canvas.width, c.canvas.height);

    c.scale(scale, scale);
    c.translate(xViewportOffset, yViewportOffset);

    ...

    for(var x = 0; x < array.length; x++)
    {
        for(var y = 0; y < array[x].length; y++)
        {
            ...

            c.fillStyle = 'rgb(' + r + ',' + g + ',' + b + ')';
            c.fillRect(0 + x * 5, 200 + y * 5, 5, 5);
        }
    }

    ...
}

Без масштабирования:

no scaling image

Увеличено:

zoomed in image

Уменьшено:

zoomed out image

(рисунок меняется в зависимости от величины увеличения)

Спасибо за любую помощь и, если нужна какая-либо другая информация, пожалуйста, дайте мне знать.

Обновление:

Я использую Google Chrome

Версия 71.0.3578.98 (официальная сборка) (64-разрядная версия)

1 Ответ

0 голосов
/ 28 января 2019

Вероятно, это связано с тем, что вы используете нецелые значения для установки масштаба контекста и / или перевода.

При этом ваши ректы больше не находятся на границах пикселей, а на плавающихценности.

Давайте создадим простой пример:

Два пикселя, один по координатам (x, y) (11,10), другой по координатам (12,10).
В масштабе по умолчаниюоба пикселя должны быть соседями.
Теперь, если мы применим масштаб 1.3, реальные координаты пикселей первого квадрата будут в (14,3,13), а те извторой (15.6,13).
Ни одна из этих координат не может содержать один пиксель, поэтому браузеры будут применять сглаживание, которое заключается в сглаживании вашего цвета цветом фона, чтобы создать впечатление меньших пикселей.Это то, что делает ваши сетки.

const ctx = small.getContext('2d');

ctx.scale(1.3, 1.3);

ctx.fillRect(2,10,10,10);

ctx.fillRect(12,10,10,10);


const mag = magnifier.getContext('2d');
mag.scale(10,10);
mag.imageSmoothingEnabled = false;
mag.drawImage(small, 0,-10);
/* it is actually transparent, not just more white */
body:hover{background:yellow}
<canvas id="small" width="50" height="50"></canvas><br>
<canvas id="magnifier" width="300" height="300"></canvas>

Чтобы избежать этого, несколько решений, все зависит от того, что вы делаете точно.

В вашем случае, кажется, выЯ бы много выиграл, работая над ImageData , который позволил бы вам заменить все эти fillRect вызовы на более простые и быстрые манипуляции с пикселями.
Используя маленький ImageData, размер вашей матрицы,Вы можете заменить каждый прямоугольник на один пиксель.Затем вам нужно просто поместить эту матрицу на холст и перерисовать холст над собой в правильном масштабе после отключения флага imageSmootingEnabled , который позволяет отключить сглаживание для drawImage и CanvasPatterns * 1036.* только.

// the original matrix will be 20x20 squares
const width = 20;
const height = 20;
const ctx = canvas.getContext('2d');
// create an ImageData the size of our matrix
const img = ctx.createImageData(width, height);
// wrap it inside an Uint32Array so that we can work on it faster
const pixels = new Uint32Array(img.data.buffer);
// we could have worked directly with the Uint8 version
// but our loop would have needed to iterate 4 pixels every time

// just to draw a radial-gradient
const rad = width / 2;
// iterate over every pixels
for(let x=0; x<width; x++) {
  for(let y=0; y<height; y++) {
    // make a radial-gradient
    const dist = Math.min(Math.hypot(rad - x, rad - y), rad);
    const color = 0xFF * ((rad - dist) / rad) + 0xFF000000;
    pixels[(y * width) + x] = color;
  }
}
// here we are still at 50x50 pixels
ctx.putImageData(img, 0, 0);
// in case we had transparency, this composite mode will ensure 
// that only what we draw after is kept on the canvas
ctx.globalCompositeOperation = "copy";
// remove anti-aliasing for drawImage
ctx.imageSmoothingEnabled = false;
// make it bigger
ctx.scale(30,30);
// draw the canvas over itself
ctx.drawImage(canvas, 0,0);

// In case we draw again, reset all to defaults
ctx.setTransform(1,0,0,1,0,0);
ctx.globalCompositeOperation = "source-over";
body:hover{background:yellow}
<canvas id="canvas" width="600" height="600"></canvas>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...