Понимание HTML Retina Canvas Поддержка

Недавно я попал в HTML canvas рисунок и поддержка сетчатки для него. Без дальнейших линий конфигурации, нарисованных на canvas -элемент выглядит немного размытым на дисплеях сетчатки.

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

Пример:
Нарисуйте HTML canvas с width: 50px а также height: 50px,

<canvas height="50px" width="50px">

Браузер на обычном экране просто рисует его (50*50 пикселей). Браузер на сетчатке отображает холст размером 50x50 пикселей, но, поскольку это сетчатка, пиксели устройства размером 50 * 50 будут меньше, чем предполагалось. Поэтому браузер рисует его на сетчатке 100*100 пикселей.

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

Как это исправить:
Часть кода должна решить проблему:

// Returns: 1 on 'normal' screens, 2 on retina displays
var PIXEL_RATIO = (function () {
    var ctx = document.createElement("canvas").getContext("2d"),
        dpr = window.devicePixelRatio || 1,
        bsr = ctx.webkitBackingStorePixelRatio ||
              ctx.mozBackingStorePixelRatio ||
              ctx.msBackingStorePixelRatio ||
              ctx.oBackingStorePixelRatio ||
              ctx.backingStorePixelRatio || 1;

    return dpr / bsr;
})();


function makeCanvasHiPPI(canvas) {
  canvas.style.width  = canvas.width  + "px";
  canvas.style.height = canvas.height + "px";

  canvas.width  *= PIXEL_RATIO;
  canvas.height *= PIXEL_RATIO;

  var context = canvas.getContext('2d');
  context.scale(PIXEL_RATIO, PIXEL_RATIO)
}

Что я думаю, код делает:
С помощью этого фрагмента кода, используемого на холсте, браузер получает информацию об использовании 50 * 50 пикселей (это то, что canvas.style устанавливается на), как в примере выше - 50*50 пикселей на обычных экранах, 100*100 пикселей на сетчатках. Но он внутренне обрабатывает холст как холст двойного размера (по крайней мере, на устройствах с сетчаткой) и поэтому способен рисовать пиксели, которые обычно заполняются браузером.

Сложная часть (я не совсем понимаю):
Масштабирование. Двойной 'canvas.width'? Хорошо, теперь у нас есть больше пикселей, которые мы можем записать - больше информации. Хорошо.
Но теперь он масштабируется, поэтому мы не пишем лишний пиксель (на холсте будет отображаться только 0 - 50) - кто на этот раз заполняет пиксели устройства? Я пробовал это без масштабирования, и это позволяет мне рисовать более тонкие линии на сетчатке (~1 пиксель устройства) в диапазоне 0 - 100 - хотя эти пиксели все еще немного размыты, масштабированные линии более толстые, но кристально чистые. Нечеткий виден только с большим увеличением.

Про шкалу:

  • хрустальные линии
  • Никакой масштаб не дает сильного черного цвета в моем примере (видно при сильном увеличении)

Про без шкалы:

  • умение рисовать тонкие линии
  • canvas.width действительно представляет пиксели, в которые я могу писать. Например:
context.moveTo(0, context.canvas.height/2);
context.lineTo(context.canvas.width, context.canvas.height/2);

работает. Это не работает с масштабированием, так как context.canvas.width возвращает немасштабированные значения.

Мои вопросы:

  • Почему линия чиста при масштабировании, даже если я не заполняю лишние пиксели самостоятельно?
  • Как мне поступить с вводящим в заблуждение возвращаемым значением?
  • Должен ли я всегда использовать context.canvas.width / PIXEL_RATIO (с масштабированием)? Это решает проблему, но не выглядит красиво в коде ( OCD включается). Я пойду с этим, пока не получу что-то лучше, хотя.

1 ответ

  1. Линия может выглядеть четкой без масштабирования, потому что в вашем случае у canvas есть резервное хранилище с высоким разрешением: http://www.html5rocks.com/en/tutorials/canvas/hidpi/

  2. Я не понимаю вопроса о вводящих в заблуждение возвращаемых значениях. Кажется, все идеально соответствует. Вы пытались установить ширину линии на 0,5 в "немасштабированном" случае?

  3. Это действительно зависит от вашего варианта использования. Если "немасштабированный" достаточно хорош, сделайте это. В противном случае, если вам нужен контроль над DPI для вашего приложения, выберите подход с высоким DPI.

Просто удалите из своего HTML:

<meta name='viewport' content='width=device-width' />

Нет вообще этой строчки. Тогда ваша веб-страница / игра будет использовать полное разрешение экрана устройства. Пиксель всегда будет пикселем. canvas.style.width будет равно canvas.width, масштабирование не требуется. На iPhone X ширина вашего сайта будет 980 пикселей. Поэтому, если вы используете ширину, определите, хотите ли вы показывать мобильный сайт, тогда эта проверка не сработает. Это для холст-страниц и игр.

Другие вопросы по тегам