- PVSM.RU - https://www.pvsm.ru -
D3 — мощная JavaScript библиотека [1] для визуализации данных. На мой взгляд — просто рай для web-разработчика, казалось бы недоступный для Qt-программиста. Но гибкость фреймворка Qt позволяет интегрировать web-frontend в толстый клиент с помощью механизма Qt Web Bridge [2]. Такие приложения получили наименование гибридные (Qt Hybrid Apps [3]).
Для JavaScript-программистов хорошая новость заключается в том, что их решения можно легко интегрировать в Desktop приложения, что потенциально может увеличить целевую аудиторию пользователей разрабатываемых библиотек (во всяком случае это верно для мира Qt приложений).
На скриншоте ниже изображен виджет Dependency Wheel [4] (Круг Зависимостей), отрисовка которого осуществляется с помощью D3.js а управление данными и отображением — с помощью Qt. При нахождении указателя над соответствующей дугой её взаимосвязи «подсвечиваются», а остальные становятся полупрозначными. Данный виджет можно использовать для визуализации различного рода зависимостей (например библиотек).
В отличии от оригинального JS решения диаграмма динамически изменяет размер под размер виджета, а данные устанавливаются на стороне Qt, а не с помощью загрузки JSON-файла.
Статья больше ориентирована на Qt-программистов, но также может быть интересна и JS программистам.
Отправной точкой идеи гибридных приложений является ряд ограничений, присущих нативным приложениям:
Гибридные приложения решают эти проблемы за счет того, что:
Архитектура гибридных приложений предполагает, что
Таким образом гибридные приложения реализуют идею тонкого клиента.
Одним из примеров гибридных приложений в Qt является WebKit Image Analyzer [5].
В примере, рассматриваемом в статье, будет использована только часть подхода гибридных приложений: отображение компонента за счет JavaScript. При этом все необходимые JS файлы будут расположены в ресурсах, как в классическом StandAlone приложении (автономном и не требующем для работы подключения к интранет/интернет сети).
Общая структура файлов проекта изображена на рисунке:
В директории base находятся:
В директории charts/pie:
Директория resources поделена на две: js и html. В html находится та страница, которая будет загружаться в виджете и в которой находится весь код взаимодействия с Qt, в js — необходимые для работы DependencyWheel js-файлы: общий для D3 — d3.min.js и специфичный для примера — d3.dependencyWheel.js.
Для того, чтобы сократить объем статьи средствами VisualParadigm была создана простая диаграмма: в ней опущены атрибуты и методы классов, которые не имеют прямого отношения к описываемой технологии. Детали реализации можно узнать в исходниках, ссылка на которые находится в конце статьи.
В гибридных приложениях в JavaScript внедряется специальный объект, вызов методов которого обрабатывается на стороне Qt:
void D3Viewer::addContextObject(const QString &name, QObject *object)
{
frame()->addToJavaScriptWindowObject( name, object ); //frame() - QWebFrame
}
Этот метод вызывается в производных от D3Viewer классах в конструкторе перед загрузкой страницы
addContextObject("api", this);
Далее взаимодействие Qt c JS возможно посредством четырех механизмов:
public:
Q_PROPERTY(float padding READ padding WRITE setPadding)
public slots:
float padding(); //getter
void setPadding(const float padding); //setter
После этого можно обращаться к данным свойствам из JS:
var chart = d3.chart.dependencyWheel()
.width(api.width)
.height(api.height)
.margin(api.margin)
.padding(api.padding);
api.update.connect(redraw);
g.append("svg:path")
.style("fill", fill)
.style("stroke", fill)
.attr("d", arc)
.on("mouseover", fade(0.1))
.on("mouseout", fade(1))
.on('click', function (d) { api.itemClicked(packageNames[d.index]) } ); //здесь подключается обработчик
Q_INVOKABLE void thisMethodIsInvokableInJavaScript();
void D3Viewer::evaluateScript(const QString &script)
{
frame()->evaluateJavaScript(script);
}
В примере способы 4 и 5 не используются
У любого решения есть как свои достоинства, так и недостатки. И в данном случае за «красивости» D3.js придется платить свою цену.
function recreateJsonObject(obj)
{
var jsonObj = {};
for(key in obj) {
jsonObj[key] = obj[key];
var dependencies = [];
for (var i = 0 ; i < obj[key].length ; i++ )
{
dependencies.push(obj[key][i]);
}
jsonObj[key] = dependencies;
}
return jsonObj;
}
Еще в Qt 4.8.6 после 15-20 секундного ресайза виджета приложение перестает штатно работать и вываливается ворох сообщений о ошибке в JS. В Qt 5.3.0 все работает штатно, что опять же наводит на мысль о том, что проблема кроется в реализации самого WebKit-а (хотя я могу заблуждаться). Однако вопросы выделения и освобождения памяти на стороне JS остаются актуальными.
Исходный код примера доступен по ссылке [6].
Пример собирался и запускался под Qt 4.8.6 и 5.3.0.
Автор: snasoft
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/83745
Ссылки в тексте:
[1] мощная JavaScript библиотека: https://github.com/mbostock/d3/wiki/Gallery
[2] Qt Web Bridge: http://qt-project.org/doc/qt-4.8/qtwebkit-bridge.html
[3] Qt Hybrid Apps: http://www.slideshare.net/YnonPerek/hybrid-apps-with-qt
[4] Dependency Wheel: http://www.redotheweb.com/DependencyWheel/
[5] WebKit Image Analyzer: http://qt-project.org/doc/qt-4.8/webkit-imageanalyzer.html
[6] по ссылке: http://my-files.ru/Download/icvu78/d3widgets.tar.gz
[7] Источник: http://habrahabr.ru/post/218389/
Нажмите здесь для печати.