Понимание 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 ответ
Линия может выглядеть четкой без масштабирования, потому что в вашем случае у canvas есть резервное хранилище с высоким разрешением: http://www.html5rocks.com/en/tutorials/canvas/hidpi/
Я не понимаю вопроса о вводящих в заблуждение возвращаемых значениях. Кажется, все идеально соответствует. Вы пытались установить ширину линии на 0,5 в "немасштабированном" случае?
Это действительно зависит от вашего варианта использования. Если "немасштабированный" достаточно хорош, сделайте это. В противном случае, если вам нужен контроль над DPI для вашего приложения, выберите подход с высоким DPI.
Просто удалите из своего HTML:
<meta name='viewport' content='width=device-width' />
Нет вообще этой строчки. Тогда ваша веб-страница / игра будет использовать полное разрешение экрана устройства. Пиксель всегда будет пикселем. canvas.style.width будет равно canvas.width, масштабирование не требуется. На iPhone X ширина вашего сайта будет 980 пикселей. Поэтому, если вы используете ширину, определите, хотите ли вы показывать мобильный сайт, тогда эта проверка не сработает. Это для холст-страниц и игр.