Статьи

Как я создал приложение для Магазина Windows с HTML5 и SVG

Paint 4 Kids — это приложение для Магазина Windows , специально разработанное для детей. Простое приложение для раскраски и рисования. Вы можете ознакомиться с функциями потребителя непосредственно с сайта Магазина Windows, где также можно увидеть некоторые снимки экрана. Для этой статьи вы можете просто думать о ней как о приложении, в котором есть несколько рисунков, и вы можете взаимодействовать с ними.

С технической точки зрения, он полностью построен с использованием стандартных веб-технологий, таких как HTML, CSS, JavaScript и SVG. Рассмотрим важный аспект: в Windows 8 мы пишем приложение, повторно использующее наши веб-навыки, и разрабатываем для веб-платформы, используя базовую поддержку HTML5 движка рендеринга Internet Explorer 10. Итак, одним из непосредственных преимуществ является то, что нам не нужно тестировать и поддерживать все версии браузера и не нужно использовать полифилы для эмуляции новых функций API в старых браузерах. Мы можем использовать лучшие веб-платформы и использовать некоторые специфические API Windows 8 непосредственно в JavaScript.

В этой статье обсуждается использование масштабируемой векторной графики (SVG) в Paint 4 Kids, начиная с некоторых требований проекта и заканчивая их устранением, а также с некоторыми подводными камнями, использующими SVG. Я надеюсь, что некоторые из этих соображений могут относиться и к вашим приложениям.

Требования и зачем использовать SVG

Приложения Магазина Windows дают вам прекрасную возможность с точки зрения рынков, на которых вы можете распространять и продавать свои приложения, а также с точки зрения устройств, на которых оно может работать. Ваше приложение можно использовать на устройствах с разными размерами экрана, разным разрешением экрана и плотностью пикселей. Это необходимо учитывать, и просмотр этой статьи дает вам очень хорошее техническое понимание того, как масштабировать приложение на разных экранах и как тестировать приложение с помощью симулятора Windows.

Одним из требований является то, что мы хотим иметь один чертеж, который будет хорошо отображаться при разных разрешениях. В итоге мы использовали SVG, векторный формат изображения для двумерной графики. Наш подход заключается в создании рисунка с определенным разрешением 2560 × 1440 с уменьшением до текущего разрешения пользователя.

Преимущество состоит в том, что в SVG очень просто и быстро заполнить путь цветом, и это одна из главных функций приложения. Когда пользователь касается экрана, просто перехватить соответствующую часть рисунка и заполнить путь определенным цветом.

Другое требование состоит в том, что мы хотим повторно использовать некоторые чертежи, сделанные в XAML, и иметь хорошую поддержку инструментов, чтобы мы могли создавать и добавлять новые чертежи в приложение простым и быстрым способом. Inkscape очень хорошо подходит для этой цели. Вы можете импортировать чертеж XAML и экспортировать его в файл SVG, и, поскольку два векторных формата очень похожи, экспорт всегда работает довольно успешно.

Одним из недостатков использования SVG является то, что манипулирование DOM может стать медленным с увеличением количества объектов, добавляемых в DOM, поэтому часто необходимо провести некоторое тестирование и оптимизацию производительности. В этом сообщении в блоге Internet Explorer вы можете прочитать о преимуществах и недостатках использования SVG в отличие от Canvas.

Другое требование Paint 4 Kids заключается в том, что пользователь должен иметь возможность сохранить свой рисунок. К сожалению, на момент написания, невозможно создать изображение из файла SVG, поэтому мы в итоге преобразовали файл SVG в объект Canvas.

Альтернативным подходом может быть использование Canvas вместо SVG. С Canvas вы должны создавать разные необработанные изображения для разных разрешений — по крайней мере, если вы хотите, чтобы ваш рисунок хорошо смотрелся в разных разрешениях, в противном случае линии будут выглядеть неровными.

Другое соображение — как заполнить фигуру на чертеже. Когда вы используете Canvas с точками касания, вы имеете дело с необработанным изображением, состоящим только из пикселей; Вы не можете иметь дело с формами, такими как прямоугольник, круг и путь, простым способом. Если вы хотите, чтобы фигура была граничит с черной линией, вам нужно реализовать алгоритм заливки (или начального заполнения) для достижения этой цели, и если площадь для заполнения будет большой (относительно размера экрана), вы увидите область постепенно заполняется, тогда как с SVG эффект заполнения довольно мгновенный.

Адаптация чертежа к различным форм-факторам: viewport и viewBox

Как указано выше, мы начинаем наш чертеж SVG с определенным разрешением 2560 x 1440 пикселей, и каждый рисунок динамически загружается в DOM из файла в приложении Магазина Windows. Это конкретное значение было выбрано для удобства — вы можете использовать другие отправные точки. В Paint 4 Kids мы хотим использовать один рисунок и масштабировать его в разных разрешениях. Посмотрите на следующие изображения одного и того же чертежа, запущенного в симуляторе Windows, в разных разрешениях.

фигура 1

фигура 2

Первый снимок моделируется на 10-дюймовом мониторе с разрешением 1024 x 768 пикселей, а второй — на 27-дюймовом мониторе с разрешением 2560 x 1440.

Это фиксированное разрешение дает нам своего рода виртуальную пространственную систему координат. В SVG мы можем установить эту систему координат, используя атрибут viewBox. Если вы используете инструмент для рисования с использованием этой системы координат, все графические элементы относятся к ней.

Вы можете уменьшить (или увеличить) от этого разрешения до другого конкретного. Предположим, например, что ваш планшет имеет разрешение 1366 x 768, вам нужно только установить атрибуты width и height для элемента SVG, который содержит ваш чертеж. Эти два атрибута определяют область просмотра SVG, то есть фактическое разрешение устройства.

Значение viewBox состоит из четырех чисел, которые представляют минимальную x -координату, минимальную y -координату, ширину и высоту системы координат, которую вы хотите отобразить и масштабировать в области просмотра. Таким образом, объединение атрибутов viewBox, width и height дает нам ожидаемый результат.

Ниже приведен корневой элемент SVG каждого чертежа, простой файл XML. Система координат начинается в верхнем левом углу экрана, как и следовало ожидать, если вы уже работали с SVG.

  <svg viewbox = "0 0 2560 1440"> ... 

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

Чтобы найти корень безымянного элемента SVG, мы используем API document.querySelector , используя селектор псевдокласса, чтобы найти первый элемент SVG. Поскольку этот API вызывается только один раз, когда пользователь выбирает элемент для рисования, мы можем пропустить любое отставание в производительности.

  var svgd;

 svgd = document.querySelector ("svg: first-of-type");

 svgd.setAttribute ("width", window.innerWidth);

 svgd.setAttribute ("высота", window.innerHeight); 

В примере кода также используется объект window и его свойства inner *, чтобы получить фактическое разрешение в пикселях во время выполнения.

Другим соображением при работе с областями просмотра и viewBox является соотношение сторон . Если две системы координат имеют различное соотношение ширины и высоты, иногда вы хотите, чтобы получающееся изображение соответствовало неравномерно. В других сценариях может потребоваться сохранить соотношение сторон и равномерное масштабирование изображения. SVG использует атрибут preserveAspectRatio, чтобы решить, нужно ли масштабировать изображение равномерно или нет. Мы обсудим это позже, когда будем говорить о «марках». Для чертежей поведение по умолчанию, которое масштабирует viewBox равномерно, чтобы соответствовать области просмотра, работает так, как мы хотим.

Как заполнить путь цветами и изображениями

Заполнить SVG-фигуру, например, путь, прямоугольник или другие объекты, — это очень простой шаг, и он довольно мгновенный, потому что это похоже на установку свойства стиля в CSS, поэтому вам не нужно писать код, чтобы найти каждый пиксель. в окружении линии. Вы можете посмотреть на код ниже, что это функция обратного вызова, когда происходит событие касания в области SVG.

  var el = document.elementFromPoint (ex, ey);

 var selectedColor = "255,0,0,1";

 el.setAttribute ("style", "fill: rgba (" + selectedColor + "); ширина-ход: 3;); 

В приведенном выше коде e является объектом типа MSPointerEvent . Этот объект очень важен, его можно получить, подписавшись на некоторые события MSPointer * (например, MSPointerDown ). С помощью одной строки кода вы можете подписаться на событие, которое приходит с помощью мыши, прикосновения и даже с ручкой! Также внутри MSPointerEvent вы можете, при необходимости, прочитать свойство pointerType, которое дает вам подробную информацию о том, какое устройство генерирует событие. Если вас интересует эта тема, вы можете прочитать этот пост в блоге об API для сенсорного ввода в приложениях IE 10 и Магазина Windows .

Возвращаясь к коду, объект e здесь используется только для получения координат точек x, y с устройства ввода, используя API elementFromPoint. Теперь el — это конкретная фигура, которую мы хотим заполнить цветом, и она имеет тип SVGPathElement . Остальная часть кода проста, задает цвет заливки и ширину обводки линии SVGPathElement, независимо от фактической формы, которой он является на самом деле.

Вместо использования API setAttirbute вы также можете напрямую установить свойство fill и strokeWidth в SVGPathElement, избегая анализа строк, что может повысить производительность; даже если не будет восприниматься пользователем в этом сценарии.

В этом примере цвет является стандартным сплошным цветом RGBA, который пользователь может выбрать из цветовой палитры, но вы также можете заполнить фигуру путем, исходящим из изображения или используя градиенты. Paint 4 Kids определяет не только общий набор цветов, но и некоторые изображения, такие как камни, трава и т. Д. Для этого в SVG вы можете определить некоторые шаблоны, как показано в коде ниже:

  <pattern id = "imgPatterns_1" patternUnits = "userSpaceOnUse" width = "128" height = "128">

     <image xlink: href = "../ images / BRICK.PNG" width = "128" height = "128" />

 </ Образец> 

В коде нужно отметить две вещи: во-первых, мы определяем SVGPatternElement, который он основывает на содержащемся изображении. Во-вторых, вы можете определить свойство patternUnits, которое определяет, как заполнить фигуру самим шаблоном. UserSpaceOnuse просто повторяет изображение все больше и больше, не добавляя между ними отступы. Как только шаблон определен, мы можем использовать его в свойстве fill, используя следующий синтаксис:

  var selectedColor = "url (# imgPatterns_1)";

 el.setAttribute ("style", "fill:" + selectedColor + "; ширина-ход: 3;); 

Глядя на код, вы можете заметить, что свойство fill теперь является URL-адресом, в котором используется идентификатор элемента шаблона, определенного выше, с предшествующим символом # (например, # imgPattern_1).

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

Рисунок 3

Повторное использование элементов SVG для «Штампов»

Paint 4 Kids также дает вам возможность вставить некоторые фигуры в ваш рисунок в виде штампов, которые вы можете прикрепить к картине. Для пользователя штамп — это форма, похожая на тыкву, или шарик, который они могут поместить в чертеж, где бы они ни пожелали, они также могут определить размер формы; и они могут вставлять одну и ту же форму все больше и больше раз в чертеж.

С точки зрения SVG, каждая фигура может быть сложной, как вы хотите, поэтому вставка одной и той же фигуры все больше и больше может в конечном итоге сделать ваш DOM все больше и больше, и в конечном итоге ваше приложение несколько замедлится в производительности на медленных устройствах. Здесь важно оптимизировать управление этим сценарием.

Для реализации этой функции мы использовали комбинацию символа и элемента использования в SVG. Элемент символа обеспечивает способ группировки элемента , но когда элемент символа добавляется в DOM страницы, он не отображается, поэтому вы можете использовать его как нечто, что вы можете использовать повторно . Следовательно, мы можем вставить сложную форму SVG один раз и использовать ее снова и снова, используя ключевое слово use. В следующем примере вы видите некоторый код SVG.

  <symbol id = "bottiglia" viewBox = "0 0 40 40" preserveAspectRatio = "xMinYMin meet">

     <путь…>

 </ Символ>

 <use id = "onlyforimg" xlink: href = "# bottiglia" height = "80" width = "80"> </ use> 

Путь — пропущенный для краткости — который содержит фактическую форму, содержится в элементе символа, который также определяет viewBox, чтобы установить размер формы, когда она была первоначально нарисована. ViewBox здесь необходим, потому что мы можем изменить размер фигуры в используемом элементе внизу, где мы устанавливаем высоту и ширину, удваивающие первоначальный размер — это было еще одним желанием, как объяснено выше. Элемент use имеет ссылку на атрибут id элемента symbol, как вы можете легко заметить из приведенного выше кода. Кроме того, использование очень мало, и благодаря этому мы можем использовать его все больше и больше раз, в конечном итоге изменяя размер чертежа, уменьшая размер DOM.

В реальном приложении элемент use создается в JavaScript динамически, устанавливая не только ширину и высоту, но также координаты x и y, чтобы расположить фигуру таким образом, чтобы центр фигуры находился там, где пользователь нажимает на экран. Чтобы сделать это немного математики — что это здесь не объясняется — необходимо установить эти две координаты. Чтобы все вещи работали, нам нужно использовать preserveAspectRatio, используя атрибут meet, чтобы получить равномерное масштабирование, чтобы viewBox полностью содержался, не разрезался при отображении в окне просмотра, а также устанавливал выравнивание . xMin выравнивает минимальный x viewBox по левому углу области просмотра, а yMin выравнивает минимальный y viewBox по верхнему краю области просмотра. Вы можете получить полную ссылку на эти значения из спецификации SVG здесь .

Загрузка файлов SVG

В предыдущей части статьи рассказывалось о стандартном SVG, который в конечном итоге мог работать непосредственно в современном браузере. Теперь мы будем смешивать некоторые API-интерфейсы Магазина Windows, которые можно использовать для создания приложения Магазина Windows, которые относятся к платформе Windows 8 и могут в конечном итоге вызываться из других поддерживаемых языков.

Поскольку Paint 4 Kids использует много рисунков, один рисунок загружается асинхронно при необходимости из файла appx и затем помещается в DOM страницы. Асинхронная загрузка выполняется с использованием Windows 8, загружающего асинхронный API, как показано в коде. Приложение Магазина Windows не позволяет нам загружать динамический код в DOM, потому что в общем случае этот код может исходить от внешнего вызова и в конечном итоге создавать некоторые проблемы безопасности в вашем приложении, если код является злокачественным. Однако код, который мы загружаем, является доверенным, поскольку он уже находится в файле appx и предоставлен нами. Вы можете безопасно вызывать функцию WinJS.Utilities.setInnerHTMLUnsafe, которая позволяет при необходимости загружать чертеж в DOM.

  svgfolder.getFileAsync ("drawing.svg"). then (function (file) {

     file.openAsync (Windows.Storage.FileAccessMode.read) .then (function (stream) {

         inputStream = stream.getInputStreamAt (0);

         reader = новый Windows.Storage.Streams.DataReader (inputStream);

         size = stream.size;

         reader.loadAsync (размер) .then (function () {

             svg = reader.readString (размер);

             WinJS.Utilities.setInnerHTMLUnsafe (document.getElementById ("s1"), svg);

         });

     });

 }); 

SvgFolder — это объект типа StorageFolder , вы можете вызвать асинхронный метод для поиска объекта storageFile — здесь обработка ошибок здесь опущена — для которого мы можем открыть поток и объект dataReader для чтения содержимого. В конце переменная svg содержит строку, которая представляет весь чертеж SVG. Как объяснено выше, мы можем вызвать setInnerHTMLUnsafe, чтобы добавить чертеж к элементу DOM s1.

Приятно, что SVG можно проверить в DOM Explorer в Visual Studio 2012, как показано ниже:

figure4

Например, вы можете выбрать конкретную фигуру из приложения во время выполнения — она ​​также работает в симуляторе — и DOM Explorer покажет вам связанный SVG во время выполнения, тот, который может быть результатом динамической загрузки и последующего преобразования применяется к нему. Очень классные вещи!

Преобразование рисунка SVG в Canvas и сохранение в изображение

Что-то, что вам нужно в формате JPEG чертежа, например, если вы хотите сохранить рисунок в файловой системе или если вы хотите использовать Windows 8 Share Charm или вообще в других частях приложения. Для этого мы использовали библиотеку canvg, которая преобразует файл SVG в объект Canvas . Преобразование может занять несколько раз, в зависимости от размера файла SVG и вашей аппаратной платформы, поэтому вы можете уведомить пользователя, что что-то происходит, мы используем всплывающее окно с индикатором хода выполнения, который отображается при запуске преобразования.

Теперь, когда у вас есть объект Canvas, вы можете получить ссылку на весь байтовый массив, а затем вы можете использовать API кодирования Windows, чтобы получить изображение нужного формата и размера. Ниже образец функции:

  function doSaveDrawingToFileEnd (fil) {

     var Imaging = Windows.Graphics.Imaging;

     var stream, encoderId, cc, offset, outputPixelData;

     fil.openAsync (Windows.Storage.FileAccessMode.readWrite) .then (function (_stream) {

         поток = _stream;

         return Imaging.BitmapEncoder.createAsync (jpegEncoderId, stream);

     }). then (function (encoder) {

         cc = document.getElementById ('canvas');

         // игнорируем переменную realBRectHeight ниже

         // это не важно для понимания логики

         смещение = (высота - realBRectHeight) / 2;

         outputPixelData =

 cc.getContext ("2d"). getImageData (0, смещение, cc.width, cc.height - смещение);

         encoder.setPixelData (Imaging.BitmapPixelFormat.rgba8, Imaging.BitmapAlphaMode.straight, width, realBRectHeight, 90, 90, outputPixelData.data);

         return encoder.flushAsync ();

     }). then (null, function (error) {

     console.log (Error.message);

     }). then (function () {

     if (stream) stream.close ();

     })

 } 

Сначала вы получаете ссылку на объект storageFile — не выделенный в коде — переменную fil, которая будет нашим окончательным изображением в формате jpeg; чем открыть поток для записи и создать объект BitmapEncoder, устанавливающий тип кодировки jpegEncoderId, это используется для кодирования массива байтов в требуемое изображение. Переменная cc является ссылкой на объект canvas, который содержит преобразованный файл SVG. Используя стандартный метод getImageData, мы получаем байты, которые мы хотим преобразовать — в коде вы можете увидеть значение смещения, используемое для обрезания определенной части чертежа, но вы можете игнорировать это значение здесь, потому что это не особенно полезно для понимания логика Теперь, используя API setPixelData с кодировщиком, вы можете установить некоторые значения для изображения, которое будет сгенерировано, изображение фактически генерируется при вызове flushAsync.

Завершение

В этой статье мы видели некоторые технические соображения о SVG и о том, как он использовался в Paint 4 Kids. SVG — очень интересная и мощная веб-технология, которую вы можете использовать для создания удивительных приложений для Магазина Windows с помощью JavaScript. Вы также можете поиграть с SVG прямо в браузере, найдя несколько забавных примеров на сайте IE Test Drive . Я надеюсь, что это поможет, если у вас есть похожий сценарий.

Если вы хотите узнать больше о том, как создать приложение для Магазина Windows, посмотрите приложение Generation .