Если я изменю размер своего холста, мой текст createJS станет размытым

Я использую createJS для рисования внутри холста. У меня настроен холст, чтобы он занимал окно браузера, сохраняя соотношение сторон, используя функцию resize().

Это код:

    mytext = new createjs.Text("Lorem ipsum dolor sit amet 2","19px Calibri","#073949");
    mytext.x = 450
    mytext.y = 300;
    stage.addChild(mytext);  

    resize = function() {
                var canvas = document.getElementById('canvas');
                var canvasRatio = canvas.height / canvas.width;

                var windowRatio = window.innerHeight / window.innerWidth;
                var width;
                var height;

                if (windowRatio < canvasRatio) {
                    height = window.innerHeight - 35;
                    width = height / canvasRatio;
                } else {
                    width = window.innerWidth;
                    height = width * canvasRatio;
                }

                canvas.style.width = width + 'px';
                canvas.style.height = height + 'px';    
    }()

Что происходит, так это то, что текст становится размытым (ухудшение качества) при изменении размера холста.

http://i.imgur.com/RQOSajs.png против http://i.imgur.com/Xwhf5c5.png

Как я могу решить эту проблему?


person Condward    schedule 28.09.2015    source источник
comment
Не могли бы вы сохранить размер исходного холста width и height, а затем, в зависимости от изменения размера, рассчитать новые масштабы, а затем правильно перерисовать все элементы по новой ширине и высоте? Например. исходная ширина = 400, исходная высота = 400, после изменения размера ширина теперь равна 800, а высота - 600. Запустите функцию рисования следующим образом. `mytext.x = 400 * (canvas.width/originalWidth); затем сделайте то же самое для высоты и размера шрифта   -  person Canvas    schedule 28.09.2015
comment
Я пытался избежать этого решения, потому что я уже создал множество игр с кучей текста и изображений, и мне нужно было создать функцию изменения размера для каждой игры, а также компенсировать изменение координат. Но если это единственное решение, мне придется применить его.   -  person Condward    schedule 28.09.2015


Ответы (5)


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

// just showing width to simplify the example:
var newWidth = 800;
var scale = newWidth/myCanvas.width;
myCanvas.width = newWidth;
myStage.scaleX = myStage.scaleY = scale;
myStage.update(); // draw at the new size.
person gskinner    schedule 30.09.2015

@ Ответ Адама верен в отношении масштабирования холста. Вы НЕ хотите масштабировать с помощью CSS, так как он будет растягивать холст, а не изменять его размеры в пикселях. Вместо этого установите ширину и высоту холста с помощью JavaScript.

stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;

Как вы указали в своем комментарии, это изменит только размер холста, а не переместит или масштабирует ваш контент. Вам придется сделать это вручную. Это довольно просто. Как правило, я рекомендую помещать прослушиватель «resize» в JavaScript в вашем HTML-файле, а не в скрипте фрейма.


Во-первых, определите масштаб, исходя из размера окна и размера вашего контента. Вы можете использовать exportRoot.nominalBounds.width и exportRoot.nominalBounds.height, которые являются границами первого кадра. Если вы хотите масштабировать что-то другое, используйте вместо этого его nominalBounds.

Обратите внимание, что атрибут honorBounds добавляется ко всем мувиклипам, экспортируемым из Flash/Animate. Если вы включили границы нескольких кадров и хотите их использовать, вам придется изменить свой подход.

Основная идея состоит в том, чтобы использовать исходный, немасштабированный размер содержимого.

var bounds = exportRoot.nominalBounds;
// Uses the larger of the width or height. This will "fill" the viewport.
// Change to Math.min to "fit" instead.
var scale = Math.max(window.innerWidth / bounds.width, window.innerHeight / bounds.height);
exportRoot.scaleX = exportRoot.scaleY = scale;

Затем вы можете центрировать его, если хотите.

exportRoot.x = *window.innerWidth - bounds.width*scale)/2;
exportRoot.y = *window.innerHeight - bounds.height*scale)/2;

Вот быстрый пример адаптивного холста, использующего простую фигуру в качестве масштабируемого содержимого: http://jsfiddle.net/lannymcnie/4yy08pax/

Выполнение этого с экспортом Flash/Animate CC поднималось несколько раз, так что это в моем списке будущих демонстраций EaselJS, которые я должен включить в createjs. com и в EaselJS GitHub.

Надеюсь, это поможет.

person Lanny    schedule 29.09.2015
comment
Я использовал ваш подход exportRoot, но он масштабирует только объекты, которые были размещены на экране во Flash CC, все объекты, которые я добавляю с помощью stage.addChild(), не масштабируются. - person Condward; 29.09.2015
comment
Да, вам придется масштабировать и позиционировать любые объекты, на которые вы хотите повлиять. Если вы просто нацелитесь на exportRoot, он будет масштабировать только exportRoot. Я рекомендую поместить всех детей в контейнер на сцене и масштабировать/позиционировать его. - person Lanny; 29.09.2015
comment
Теперь у меня новая проблема. Изменение размера с активной анимацией все испортит. - person Condward; 30.09.2015

Взгляните на мой jsfiddle: https://jsfiddle.net/CanvasCode/ecr7o551/1/

В основном вы просто сохраняете исходный размер холста, а затем используете его для разработки новых позиций и размеров.

HTML

<canvas id="canvas" width="400" height="400">
    Canvas was unable to start up.
</canvas>

<button onclick="resize()">Click me</button>

JavaScript

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var originalWidth = canvas.width;
var originalHeight = canvas.height;

render = function()
{
    context.fillStyle = "#DDD";
    context.fillRect(0,0, originalWidth * (canvas.width / originalWidth), originalHeight * (canvas.height / originalHeight));

    context.fillStyle = "#000";
    var fontSize = 48 * (canvas.width / originalWidth);
    context.font = fontSize+"px serif";
    context.fillText("Hello world", 100 * (canvas.width / originalWidth), 200 * (canvas.height / originalHeight));   
}

resize = function()
{
    canvas.width = 800;
    canvas.height = 600;
    render();
}

render();
person Canvas    schedule 28.09.2015
comment
Я собираюсь использовать ваш ответ в качестве решения. Это будет очень сложно реализовать в моей ситуации, но я думаю, что это единственный вариант, который у меня есть. - person Condward; 28.09.2015
comment
Да, если вам нужно реализовать это в середине сборки или в конце, это может вызвать некоторые проблемы, однако теперь вы знаете, а знание — это полдела :) - person Canvas; 28.09.2015

Элемент холста HTML5 работает с двумя разными размерами.

  • Визуальный размер на экране, управляемый с помощью CSS, как вы устанавливаете с помощью canvas.style.width/height
  • Размер пиксельного буфера для рисования, управляемый числовыми атрибутами ширины и высоты пикселя элемента холста.

Браузер растянет буфер, чтобы он соответствовал размеру экрана, поэтому, если соотношение двух значений не равно 1:1, текст будет выглядеть размытым.

Попробуйте добавить следующие строки в свой код

canvas.width = width;
canvas.height = height;   
person Adam    schedule 28.09.2015
comment
но тогда текст не масштабируется с холстом. - person Condward; 28.09.2015
comment
Можете ли вы опубликовать автономный пример, jsfiddle и т. д., чтобы я мог лучше посмотреть... - person Adam; 28.09.2015
comment
Он думает, что это не будет работать в Jsfiddle, потому что я использую Adobe Flash для создания файла HTML5, и он использует библиотеки createJS и Movieclip. Но весь код здесь: pastebin.com/xbYUi3ew - person Condward; 28.09.2015

Я создал функцию для изменения размера всех элементов на экране после изменения размера холста. Он сохраняет исходные координаты и масштабы для элементов с исходной шириной 900 пикселей, а затем изменяет их в соответствии с текущим соотношением ширины относительно исходного соотношения ширины. Текст больше не размытый/плохого качества.

    resize = function() {
            var canvas = document.getElementById('canvas');
            var canvasRatio = canvas.height / canvas.width;

            var windowRatio = window.innerHeight / window.innerWidth;
            var width;
            var height;

            if (windowRatio < canvasRatio) {
                height = window.innerHeight;
                width = height / canvasRatio;
            } else {
                width = window.innerWidth;
                height = width * canvasRatio;
            }

            canvas.width = width;
            canvas.height = height;
            reziseElements();

        };


    reziseElements = function()
            {
                var canvrat = canvas.width / 900;

                 //Simplified
                stage.scaleX = stage.scaleY = canvrat;

                //Old Version
                /*for (i=0; i<stage.numChildren ;i++)
                {
                    currentChild = stage.getChildAt(i);

                    if (typeof currentChild.oscaleX == 'undefined')
                    {
                        currentChild.oscaleX = currentChild.scaleX;
                        currentChild.ox = currentChild.x;
                        currentChild.oy = currentChild.y;
                    }
                }   


                for (i=0; i<stage.numChildren ;i++)
                {
                    currentChild = stage.getChildAt(i);
                    currentChild.scaleX = currentChild.scaleY = currentChild.oscaleX * canvrat      
                    currentChild.x = currentChild.ox * canvrat
                    currentChild.y = currentChild.oy * canvrat
                }   */
            }
person Condward    schedule 28.09.2015
comment
Вместо того, чтобы масштабировать все ваши элементы, поместите их в контейнер и масштабируйте его. Если вы используете экспорт Flash CC, вы должны иметь возможность просто ориентироваться на exportRoot, который он создает. - person Lanny; 28.09.2015