[Из песочницы] Пример создания веб-приложения на PureQML

7e01f81ea88f473a8f07bcdeaaaa8a90.png

Вступление


Недавно мы открылись миру (совершили coming out, так сказать) и опубликовали статью про наш скромный фреймворк (исходники на GitHub). После общения с заинтересовавшимися участниками (большое им спасибо!) мы пришли к выводу, что для раскрытия темы необходимо написать подобие туториала на каком-нибудь реальном примере. На сайте проекта есть раздел с уроками, но эти уроки скорее описывают специфические ситуации, нежели картину в целом. Вот почему мы решили написать небольшой гайд. Для реалистичности, по шагам опишем создание простого, но реального, проекта, который хорошо показывает портируемость решений из веба в SmartTV. И да, результат этого гайда уже доступен в LG Smart World для телевизоров на базе WebOS (вы можете найти это приложение по названию «Earth Online»). В этой статье мы описываем создание ровно такого же приложения для десктопных и мобильных браузеров.

Идея


Идея довольно проста: показывать виды Земли с борта МКС (за эту возможность надо благодарить NASA, а именно, проект High Definition Earth-Viewing System). Помимо видео, приложение будет показывать текущее положение МКС над Землей. Для этих целей мы воспользуемся сервисом Where the ISS at?. Приступим!

Начало


Создаем папку для нашего проекта:
$ mkdir earth-online
$ cd earth-online

Чтобы создать новый проект, нужно скопировать qmlcore в папку с проектом. Можно просто скачать и скопировать содержимое или склонировать с помощью GIT:
$ git clone git@github.com:pureqml/qmlcore.git

Чтобы поменьше писать руками, сгенерируем каркас приложения:
$ qmlcore/build --boilerplate

После выполнения команды в папке проекта появится два новых файла:
  • src/app.qml — PureQML код приложения
  • .manifest — минимальный манифест, описывающий приложение

Папка src используется для хранения qml исходников проекта.

В app.qml, оставим только такой код:

Item {
	anchors.fill: context; // растягиваем Item по размерам всего окна
}

Чтобы собрать приложение, нужно выполнить команду:
$ qmlcore/build

и если все прошло успешно, то в папке проекта появится новая папка build.web с результирующими файлами.
$ ls build.web/
flashlsChromeless.swf  index.html  modernizr-custom.js  qml.app.min.js

На секунду отвлечемся и посмотрим, что это за файлы:
  • index.html — полученная html-страница
  • qml.app.min.js — полученный js файл, который загружается в index.html
  • modernizr-custom.js — используемый кастомный modernizr файл
  • flashlsChromeless.swf — файл, который используется для проигрывания видео с помощью флеша (буэ), в нашем случае он не нужен, но он автоматически добавляется в проекты web платформы.

Controls


Помимо qmlcore, необходимой и наиболее стабильной части проекта, есть еще отдельный модуль controls, в котором найдется много полезных компонент уже готовых к использованию. Для подключения этого модуля его также достаточно скопировать в src папки проекта или склонировать:
$ cd src
$ git clone git@github.com:pureqml/controls.git

Для нашего приложения как раз понадобится один компонент из controls, который позволит играть live stream видео с youtube, он так и называется — YouTube. Добавим его в app.qml:
Item {
	anchors.fill: context; // растягиваем Item по размерам всего окна

	YouTube {
		anchors.fill: parent;
		source: "https://www.youtube.com/embed/ddFvjfvPnqk?autoplay=1&controls=0&showinfo=0";
	}
}

В результате, если открыть Index.html в браузере, то можно увидеть видео с МКС:

146e5be1191e45aeb602e2cfbf8a5896.png

Карта


С видео разобрались. Теперь перейдем к местоположению станции. Так как для задачи достаточно отобразить позицию станции над Землей, то можно использовать просто картинку с развернутой поверхностью планеты и двигать точку по ней согласно текущим координатам (хотя в controls есть компонента YandexMap для работы с картами).

31d1a07b3bab42e6b0a8d604aaed59ea.png

Мы подготовили картинку с картой Земли. Чтобы наша картинка, или любые другие ресурсы, попали в сборку, нужно создать специальную папку в корне проекта — dist:

$ mkdir dist

Все содержимое этой папки будет копироваться после сборки в build.web. Добавим в dist картинку с картой:
$ mkdir dist/res
$ cp  dist/res

Если попробуете собрать проект сейчас, то увидите как в build.web появилась папка res с добавленной картинкой:
$ ls build.web/res/
map.png

Логика работы с карта у нас будет в отдельной компоненте, создадим новый файл для нее IssMap.qml в src и напишем следующий код:
Item {
	anchors.fill: context;	// компонента растягивается на весь экран

	// картинка с картой
	Image {
		anchors.fill: parent;	// растягиваем по размерам родителя
		source: "res/map.png";	// путь к картинке
		fillMode: Image.Stretch;	// тип заливки, Stretch растягивает по размерам Image

		// точка для обозначения позиции станции
		Rectangle {
			id: station;		// id, по которому можно обращаться к компоненте
			width: 30;
			height: width;		// высота равна ширине
			radius: width / 2;	// радиус, чтобы скруглить прямоугольник до круга
			visible: false;		// по умолчанию точку не видно
			color: "red";
		}
	}

	// метод для установки точки соответственно долготе long и широте lat
	setPos(long, lat): {
		// делаем точку видимой
		station.visible = true

		// все константы используются для преобразования из координат
		// широты, долготы в координаты карты
		station.x = (long + 180) * this.width / 360 - (this.width / 28.4)
		station.y = (90 - lat) * this.height / 180 + (this.height / 19.45)
	}
}

Теперь нам нужно получить координаты станции и установить точку в нужную позицию. Для этого воспользуемся API, о котором говорилось выше.

Для выполнения HTTP запросов в controls есть специальный объект Request, сделаем на его базе контрол для асинхронного запроса координат в файле IssRequest.qml в папке src:

Request {
	// метод запроса координат
	// callback - функция, которая будет выполнена в случае успешного запроса
	call(callback): {
		this.ajax({
			url: "https://api.wheretheiss.at/v1/satellites/25544",
			done: callback,
			withCredentials: true
		})
	}
}

Теперь нужно сложить все в одно место и добавить еще текст с координатам станции. Назовем этот контрол OSD и создадим для него файл Osd.qml с кодом:
// WebItem - это обычный Item
// но с возможностью отслеживать hover и click события у мыши
WebItem {
	property bool active: false;	// объявим bool свойство - флаг отображения OSD
	anchors.fill: parent;
	opacity: active ? 1.0 : 0.0;	// прозрачность в зависимости от флага active

	// инстанциируем протокол
	IssRequest { id: request; }

	// инстанцируем нашу карту из IssMap.qml
	IssMap { id: map; }

	// текст о видимости Земли (на темной стороне или освещенной)
	// прижимаем к правому нижнему краю
	Text {
		id: visibilityText;
		anchors.right: parent.right;
		anchors.bottom: parent.bottom;
		anchors.margins: 10;
		font.pixelSize: 24;
		color: "#fff";
		text: "Earth visibility: -";
	}

	// текст с координатами: долготой и широтой
	// текст прижимаем к левому нижнему краю
	Text {
		id: positionText;
		anchors.left: parent.left;
		anchors.bottom: parent.bottom;
		anchors.margins: 10;
		font.pixelSize: 24;
		color: "#fff";
		text: "Lon: -
Lat: -"; // в текст можно вставлять html теги } // таймер для повторения запросов Timer { running: parent.active; // таймер работает пока активен OSD triggeredOnStart: true; // таймер срабатывает при старте interval: 10000; // интервал повторения 10 секунд repeat: true; // таймер повторяется // обработчик срабатывания, зовем метод updatePositionRequest onTriggered: { this.parent.updatePositionRequest() } } // делаем запрос координат, в случае успеха парсим результат // передаем его в doUpdatePosition updatePositionRequest: { var self = this request.call(function(res) { var data = JSON.parse(res.target.response) if (data) self.doUpdatePosition(data) else log("Request error") }) } // заполняем полученные данные doUpdatePosition(data): { var long = parseFloat(data.longitude) // долгота var lat = parseFloat(data.latitude) // широта // заполняем текст с координатами станции positionText.text = "Lon: " + Number((long).toFixed(1)) + "
Lat: " + Number((lat).toFixed(1)) // заполняем текст видимости data.visibility возвращает строку 'eclipsed' или 'daylight' visibilityText.text = "Earth visibility: " + data.visibility map.setPos(long, lat) // передаем координаты станции карте } // объявляем анимацию на изменение прозрачности // время анимации 300 мс Behavior on opacity { Animation { duration: 300; } } }

Теперь нужно разместить OSD в нашем приложении поверх видео и отображать его, скажем, по клику мыши на экране и также (по клику) закрывать. Теперь app.qml примет следующий вид:
Item {
	anchors.fill: context;

	Youtube {
		anchors.fill: parent;
		source: "https://www.youtube.com/embed/ddFvjfvPnqk?autoplay=1&controls=0&showinfo=0";
	}

	Osd {
		// обработчик клика мыши
		// инвертируем флаг отображения OSD по клику
		onClicked: { this.active = !this.active }
	}
}

Собираем проект, открываем в браузере build.web/index.html, кликаем по экрану и OSD появляется с анимацией по прозрачности!

ea27a475b3be471a8d3d21fac007d647.png

Последние штрихи


Попробуем внести еще небольшое улучшение: было бы здорово, если бы текст с координатами был выровнен:
fc2db3b04a8540709193e81c2b890e9a.png

для решения проблемы можно использовать какой-нибудь monospace шрифт.

Чтобы добавить новый шрифт, нужно подредактировать выходной index.html файл. Помните, как мы использовали папку dist, чтобы добавлять файлы в build.web после сборки? Важным моментом является именно тот факт, что копирование происходит после сборки, и таким образом, мы можем переопределить index.html. За основу возьмем текущий index.html:

$ cp build.web/index.html dist

и добавим линк на новый шрифт. После небольших правок dist/index.html будет выглядеть вот так:



	
	
	
	
	


	














Текст с координатами примет вот такой вид:
5d6fba6a7b98476b9ae8ededa6d27c25.png

Заключение


Конечно же, это приложение не раскрывает всех возможностей фреймворка, но дает наглядное представление о том, как быстро и непринужденно написать single page приложение на QML, код которого можно портировать на SmartTV платформы.

Ссылки


  • High Definition Earth-Viewing System — трансляции с МКС
  • Where the ISS at? — сервис предоставляющий API для получения координат станции
  • earth-online — исходный код из этого гайда
  • PureQML — страница проекта PureQML

Комментарии (1)

  • 9 апреля 2017 в 12:38

    0

    Очень похоже по духу RAD на Polymer, только он использует HTML (Web Components) вместо JSON и CSS Flex вместо anchors.

© Habrahabr.ru