Уменьшите масштаб сцены Konvajs без потери качества

Представьте, что у вас есть большая сцена (2000x1000) с текстом. Масштаб рабочей области уменьшается до 1000x500, что делает текст нечитаемым. Затем мы пытаемся увеличить текст, увеличивая его.

Ожидается: в какой-то момент текст должен снова стать читаемым.

Актуально: текст остается нечитаемым (размытым) независимо от того, насколько мы увеличиваем масштаб.

Попробуйте увеличить масштаб страницы (с собственным масштабированием браузера на рабочем столе) после запуска фрагмента:

const stage = new Konva.Stage({
   container: 'container',
   width: 2000,
   height: 1000,
});

const layer = new Konva.Layer();
stage.add(layer);

const rect = new Konva.Text({
   x : 50, y : 50, width: 100, height: 100,
   fontSize: 12,   
   text: "This text should be readable when the viewport gets downscaled"
});

layer.add(rect).draw();

stage.scale({x: 0.5, y: 0.5});
stage.setAttrs({width: 1000,  height: 500});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>

Потери качества можно избежать, уменьшив масштаб только с помощью CSS, например:

const stage = new Konva.Stage({
   container: 'container',
   width: 2000,
   height: 1000,
});

const layer = new Konva.Layer();
stage.add(layer);

const rect = new Konva.Text({
   x : 50, y : 50, width: 100, height: 100,
   fontSize: 12,   
   text: "This text should be readable when the viewport gets downscaled"
});

layer.add(rect).draw();

stage.getChildren().forEach(function(layer) {
    layer.canvas._canvas.style.width = "1000px";
    layer.canvas._canvas.style.height = "500px";

    layer.hitCanvas.setSize(1000, 500);
    layer.hitCanvas.context.scale(0.5, 0.5);
});    

stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>

Обратите внимание, как текст становится читаемым при определенном уровне масштабирования.

Обходной путь нарушает абстракцию Konvajs. Какие проблемы это может потенциально вызвать? Есть ли лучший способ, который использует только общедоступные методы, предоставляемые Konvajs?

В fabric.js это можно сделать следующим образом (полный пример здесь):

canvas.setDimensions({width: '1000px', height: '500px'}, {cssOnly: true});

person eugenesqr    schedule 04.04.2019    source источник
comment
Как вы увеличиваете масштаб? Родной зум с сенсорным экраном на мобильном телефоне?   -  person lavrton    schedule 04.04.2019
comment
Встроенный зум браузера. Я только что заметил, что StackOverflow не запускает фрагменты кода на моем телефоне. Пожалуйста, используйте настольный браузер.   -  person eugenesqr    schedule 04.04.2019


Ответы (1)


Конва - это холст-каркас. Холст - это растровое изображение, в отличие от векторных элементов, таких как SVG. Так что этого «размытия» следовало ожидать. Технически, чтобы решить эту проблему, вы можете перерисовать сцену с более высоким pixelRatio при событии масштабирования:

Konva.pixelRatio = 4
stage.draw();

Этот код сгенерирует больше пикселей для элемента холста. Но в этом случае страница может быть очень тяжелой в ОЗУ, потому что Konva придется создавать очень большой холст. В большинстве мобильных приложений вам не нужно собственное масштабирование, и вы можете использовать адаптивный дизайн. Для масштабирования сцены можно использовать методы Konva.

person lavrton    schedule 04.04.2019
comment
Увеличение pixelRatio после уменьшения масштаба слоя не сработает, поскольку все лишние данные пикселей уже потеряны. Единственный способ предотвратить потерю данных - использовать масштабирование CSS (но только при уменьшении). Мы в основном сохраняем исходное изображение, поэтому, когда мы позже увеличим его снова с помощью увеличения, пиксели все еще будут там. Это рабочий подход, все тесты проходят. Однако это нарушает абстракцию фреймворка, что может вызвать странные ошибки в будущем. Есть мысли о том, что может пойти не так с этим подходом? - person eugenesqr; 05.04.2019
comment
Что вы имеете в виду под потерянными данными? Масштабирование с помощью CSS не позволяет Konva обнаруживать попадания. Так что это не рекомендуется. - person lavrton; 05.04.2019
comment
После уменьшения размера холста мы получаем холст более низкого качества, потому что растровое изображение позади холста фактически изменяется. Если мы затем снова увеличим масштаб холста (либо увеличив масштаб, либо другими способами), мы не получим исходный холст. Я заметил проблему с обнаружением попаданий и обновил код вопроса. Я все еще не уверен в возможных проблемах с кешированием, но пока вроде работает. - person eugenesqr; 05.04.2019
comment
Я пробовал использовать этот подход, так как у меня есть масштабируемый контейнер холста, который меняет свое свойство scale, и для каждого события колеса я устанавливаю и масштаб, и pixelRatio. Последний установлен в классе, импортированном из konva, а моя сцена - это компонент react-konva. Однако вызов draw на нем не вызывает перерисовки, которая могла бы привести к тому, что изображение не будет размытым. Есть ли другой способ предотвратить размытие холста при родительском масштабировании? - person guben; 26.05.2021
comment
Не знаю о konva, но не должны ли закадровые вещи вызывать проблемы или konva не обрабатывает отбраковку? - person Ryan The Leach; 13.06.2021