Qlik Sense: Создаем расширение с помощью D3
Новый Qlik Sense APIs позволяет легко создавать расширения, которые увеличивают библиотеку стандартных визуализаций. Одна из самых распространенных библиотек – мощная подборка javascript-библиотек d3.js. Именно поэтому хочу сегодня рассказать о том, как создать расширение визуализации с помощью d3. Буду писать очень подробно, чтобы даже новичок легко смог воссоздать то, о чем я расскажу.
НА ЗАМЕТКУ! Само название d3 расшифровывается как Data-Driven Documents, то есть ключевой основой этой библиотеки является созданий мощнейший визуализаций данных. D3 – комбинация трех компонентов, а именно CSS, JS и SVG, поэтому графика у нас будет векторного формата, что очень важно для ее качественного отображения. Прочие подробности можно узнать на официальном сайте библиотеки http://d3js.org/ .
После прочтения я вам обещаю, что всего за 10 минут, вы сможете создать собственное расширение. Тяжело в ученье, легко в бою! В бой, друзья!
РАСШИРЕНИЕ QLIKSENSE: 4 ШАГА К СОЗДАНИЮ
1) Пишем небольшую d3-визуализацию.
2) Получаем тестовые данные для работы и загрузки в Qlik Sense.
3) Запускаем новое расширение и делаем нужные настройки параметров.
4) Вставляем код d3 в расширение и изменяем источник данных из расширения.
НА ЗАМЕТКУ! Я предполагаю, что вам известны основы скриптинга Qlik Sense и JavaScript, поэтому не буду вас учить этому здесь. НО, все-таки, весь код буду сопровождать легкими объяснениями – чтобы вы могли просто копипастить, вникая в суть дела, но так, чтобы не утонули :)).
Источник:
В итоге получим вот такую визуализацию:
Итак, дорогие мои! Стартуем!
D3 В ДЕЛЕ
Наш график создан по двум метрикам и цвет определяется на основе измерения. Qlik Sense имеет встроенную визуализацию с одним измерением, но при этом по умолчанию нет второго измерения, которое позволяет сгруппировать точки по цветам. Как раз в этом нам поможет библиотека решений d3.
Когда вы откроете источник данных, вы увидите два файла: html-файл с графиком и .tsv-файл, который содержит данные. Мы же будем использовать куски кода из html-файла и Qlik Sense, вместо tsv-файла.
Когда будем готовы использовать d3, вернемся к этому шагу. Сейчас идем дальше.
ПОЛУЧАЕМ ТЕСТОВЫЕ ДАННЫЕ И ЗАГРУЖАЕМ В QLIK SENSE
Нам нужные данные с двумя метриками и двумя измерениями для создания диаграммы. Две метрики будут отвечать за оси X и Y. Одно измерение будет использоваться, чтобы нарисовать каждую точку, второе – для назначения цвета. Использую данные из отчета о развитии человечества за 2014 г. Human Development Report 2014. Заголовки таблицы содержат следующие данные:
Development Group |
Country |
Obesity % |
Life Expectancy at age 60
Мои две метрики – процент ожирения и ожидаемая длительность жизни в возрасте 60 лет. Измерением будет каждая страна. В качестве цвета выбираем группу развития страны.
Также я удалил те строки, в которых были пропущены данные.
Сохраните ваши данные в ту директорию, откуда вы сможете загрузить данные.
СОЗДАЕМ НОВОЕ ПРИЛОЖЕНИЕ В QLIK SENSE
Первое, что нам нужно сделать – создать новое приложение Qlik Sense.
Откройте Qlik Sense. Вы увидите хаб. Выбирайте “Создать новое приложение” в верхнем правом углу.
Дайте своему приложение название и затем нажмите на него, чтобы открыть.
ИЗМЕНИТЕ СКРИПТ ЗАГРУЗКИ И ЗАГРУЗИТЕ ВАШИ ДАННЫЕ
Мы создали и открыли приложение, которое сейчас у нас пустое. Сейчас нам нужно загрузить наши данные. Данные могут быть загружены через редактор загрузки данных.
Нажмите на иконку компаса в верхнем левом углу и выберите «Редактор загрузки данных», у вас откроется окно.
Слева, вы увидите панель, которая управляет загрузкой скрипта в разных вкладках. Основная вкладка – конфигурация переменных. Нам не нужно изменять их. Нажмите на “+”, чтобы создать новую вкладку. Задайте название вкладке.
Пустая вкладка скриптинга будет теперь видна справа.
Чтобы сгенерировать наш скрипт загрузки, нам нужно установить соединение с директорией, откуда будем загружать данные В правой части области скриптинга нажимаем «Создать соединение». Выбираем директорию, где сохранен CSV-файл (назначаем имя и жмем сохранить).
Создав соединение с директорией, мы можем использовать это соединение для загрузки данных из директории. Справа появится наше соединение в виде иконки. Нажимая на эту иконку, мы увидим меню, из которого можем загружать файлы из директории. Нажмите на сохраненный файл в директории, нажимайте выбрать.
Загрузчик поможет нам сконфигурировать нашу загрузку. Нам будет доступен предпросмотр и можем настроить параметры. У нас есть источник данных, разделенный запятыми и ярлыки первой строки источника, которые мы будем использовать как наши имена столбцов. Измените настройки загрузки, как показано ниже:
Нажмите кнопку «Вставить скрипт», чтобы импортировать сгенерированный скрипт загрузки в ваш редактор скрипта. Получится как-то так:
Теперь мы можем загрузить данные в наше приложение, нажав кнопку «Загрузка данных» в верхнем правом углу.
ЗАПУСК НОВОГО РАСШИРЕНИЯ И НАСТРОЙКА ЕГО ПАРАМЕТРОВ
Теперь у нас готовые данные к тестированию, и мы можем настроить фреймворк для нашего расширения. Вместо написания кода, используем готовое решение Qlik Sense и изменим код под наши цели.
Заходим в директорию расширения. Директория по умолчанию находится по следующему пути My Documents\Qlik\Sense\Extensions. Дублируем расширение “SimpleTable”.
ЗАПУСКАЕМ РАСШИРЕНИЕ
Дублируем расширение “SimpleTable” и называем его “TwoDimScatter”. Затем открываем директорию. Вы увидите следующие файлы:
- com-qliktech-simpletable.js – файл Javascript , который подгружает данные в Qlik Sense и создает пользовательскую визуализацию.
- com-qliktech-simpletable.qext – файл настроек, который состоит из таких атрибутов как название расширения.
- simpletable.css – файл стиля, где мы можем определить стиль визуализации (шрифты и цвета).
- wbfolder.wbl – просто оставим как есть и не трогаем.
Обновите все имена файлов, кроме wbfolder.wbl на “twodimscatter”. Например, “com-qliktech-simpletable.js” станет “twodimscatter.js”.
Также нам необходимо добавить в эту директорию d3.min.js, который позволяет нам использовать библиотеку D3. Последняя версия связана с разделом Resources. В итоге получится такая структура файлов:
Конфигурация файла Расширение
Открываем файл “twodimscatter.qext” в редакторе текста. У меня такие настройки:
{ «name» : «Two Dimensional Scatter», «description» : «A scatter plot that uses two dimensions», «icon» : «table», «type» : «visualization», «version»: «1.0», «preview» : «table», «author»: «Speros» }
Сохраняем и закрываем.
ГОТОВИМ CSS
Открываем файл “twodimscatter.css” в редакторе текста. CSS состоит из правил стиля для элементов нашей визуализации. Теперь давайте оптимизируем наш файл и оставим только то, что нам нужно.
Первая строка имеет запись для “.qv-object-com-qliktech-simpletable div.qv-object-content-container”. “div.qv-object-content-container” – див-блок, которые содержит наше расширение. Первый класс из списка — “.qv-object-com-qliktech-simpletable”, описывает наш класс. Делаем так, чтобы CSS применялся только для вновь созданных объектов в расширении. Оставляем все как есть, кроме двух правок:
1) меняем название класса с “.qv-object-com-qliktech-simpletable” на “.qv-object-twodimscatter”.
2) удаляем строчку “overflow: auto;”
Весь остальной CSS удаляем. В итоге, файл CSS должен получиться таким:
qv-object-twodimscatter div.qv-object-content-container { }
НАСТРАИВАЕМ ФАЙЛ JS
Открывает Javascript-файл в текстовом редакторе. Файл определяет поведение объекта. Настраиваем конфигурацию и функции расширения, для начала.
ХАРАКТЕРИСТИКИ
В самой первой строчки написан определитель define(), который назначает порядок загрузки, а затем запускает функцию после загрузки. Define() — часть AMD API и доступна нам из нашего расширения, потому что Qlik Sense использует RequireJS.
Изменяем файл: jQuery, css и наш файл d3.min.js.
Меняем
[«jquery», «text!./simpletable.css»]
на
[«jquery», «text!./twodimscatter.css»,»./d3.min»]
Теперь код расширения будет сначала загружать эти файлы, прежде чем делать что-то еще.
НА ЗАМЕТКУ! Qlik Sense работает с jQuery, поэтому нам не нужно сохранять локальные копии расширения.
НАСТРОЙКИ И ОПРЕДЕЛЕНИЯ
Проработав со всеми нужными нам файлами, меняем настройки и определения нашего расширения. В них определяется объем получаемых данных, а также определяется, сколько измерений и выражений нужно для запуска расширения.
В этом файле, в самом начале вы увидите такой код:
return { initialProperties : { version: 1.0, qHyperCubeDef : { qDimensions : [], qMeasures : [], qInitialDataFetch : [{ qWidth : 10, qHeight : 50 }] } }, definition : { type : «items», component : «accordion», items : { dimensions : { uses : «dimensions», min : 1 }, measures : { uses : «measures», min : 0 }, sorting : { uses : «sorting» }, settings : { uses : «settings», items : { initFetchRows : { ref : «qHyperCubeDef.qInitialDataFetch.0.qHeight», label : «Initial fetch rows», type : «number», defaultValue : 50 }, } } } },
В строке 2 создается initialProperties-объект. В 10 строке, qWidth определяется, сколько столбцов будет иметь расширение. Измените ширину qWidth с “10″ на “4″, поскольку у нас всего два измерения и две меры. Атрибут qHeight определяет, сколько строк может быть загружено. Измените значение с “50″на “1000″.
НА ЗАМЕТКУ! Qlik Sense .96, 1000 – максимальное число, введенных строк.
Строка 13 определяет ограничения строк и измерений. В строке 19 и 23 написано, что минимальное число измерений равно 1, а минимальное число мер — 0. Мы же изменим четко значения на две меры и два измерения.
В 19 строке меняем минимум с “1″ на “2″. Затем добавляем запятую и добавляем новую строку и выбираем максимальное значение равное двум. Делаем то же самое для мер. Получится вот так:
dimensions : { uses : «dimensions», min : 2, max: 2 }, measures : { uses : «measures», min : 2, max: 2 },
В 32 строке создаются элементы расширения. Удаляем 32 и 39 строку. Результат должен выглядеть так:
settings : { uses : «settings» }
ФУНКЦИЯ РИСОВАНИЯ
Последняя из наши настроек – работа с функцией рисования. Эта функция подключается каждый раз, когда меняется визуализация. Например, фильтрация данных в Qlik Sense вызывает функцию перерисовки визуализации. Для наших целей делаем такие изменения:
1) измените функцию по двум параметрам: $ и макет
function($element,layout) {
2) очистите текущее содержание
function($element,layout) {}
3) назначьте эти два элемента, чтобы мы могли видеть их содержимое
function($element,layout) { console.log($element); console.log(layout); }
Console.log() будет обрабатывать все значения и передавать их в консоль JavaScript, которую можно просмотреть в QS и в браузере. Функция рисования визуализации должна выглядеть так:
paint : function($element,layout) { console.log($element); console.log(layout); }
ЗАПУСК РАСШИРЕНИЯ В QLIK SENSE И ПРОСМОТР
Давайте отдохнем от кодинга расширения и посмотрим, как оно работает. Мы также можем посмотреть на объекты, которые мы внесли в консоль.
Откройте созданное вами приложение Qlik Sense и создайте новый лист из окна просмотра приложений.
Дайте листу имя и откройте его. Он первоначально будет пустым. В правом верхнем углу нажмите кнопку «Изменить», чтобы войти в режим редактирования. В левой части страницы, есть панель, где вы можете выбрать диаграммы, которые будем добавлять. Перейдите к двумерной диаграмме рассеяния и перетащите ее на дэшборд.
После добавления диаграммы, Qlik даст вам возможность добавлять свои измерения и меры. Добавьте «Уровень развития» в качестве первого измерения и «Страна» в качестве второго измерения. Для мер, нам нужно будет выбрать поле, чтобы определить то, что в нем будет рассчитываться.
Выберите «Ожирение%» и «Ожидаемая продолжительность жизни в возрасте 60» для мер. Для функций могут быть использованы «Сумма» или «AVG». Поскольку эти значения записываются на страновом уровне, мы будем суммировать единичные значения. Я предлагаю использовать функцию AVG, чтобы возвращалось верное значение, если будет идти глубже в данные.
После того, как размеры и меры добавлены, мы можем настроить ярлыки и метки. На правой панели, нажмите на заголовок измерения, чтобы расширить панель. Каждая мера должна быть указана.
Откроем Инструменты разработчика (можно открыть через Ctrl + Shift + щелчок правой кнопкой мыши на странице) и выбираем «Показать инструменты разработчика».
Выберите «Консоль» сверху, чтобы посмотреть на консоль JavaScript. Вы можете использовать консоль, чтобы исследовать эти элементы. Если открыть консоль, будет вот такое изображение:
На картинке выше, видно, где хранится строка Албании. Мы видим, что макет имеет объект, называемый qHyperCube, который содержит массив с именем qDataPages, внутри которого есть массив QMatrix. Он описывает все строки данных. Каждый объект в строке представляет собой другой столбец. Мы можем использовать эту информацию, чтобы написать наш код JavaScript, который будет собирать данные для визуализации d3.
ВСТАВЛЯЕМ И ИЗМЕНЯЕМ КОД D3
Открываем файл “twodimscatter.js” в текстовом редакторе.
РАБОТАЕМ С ДАННЫМИ И DIV-БЛОКОМ
Первое, что нам нужно сделать – извлечь полезную информацию из нашего расширения. Нам нужны данные, чтобы задать ширину и высоту объекта и уникальное id нашей диаграммы. Уникальный идентификатор пригодится, когда будем создавать новый элемент DOM.
Теперь, когда мы использовали консоль, чтобы выяснить, где наш источник данных находится и меры, мы можем строить нашу область данных в JavaScript с помощью следующих строк кода
// get qMatrix data array var qMatrix = layout.qHyperCube.qDataPages[0].qMatrix; // create a new array that contains the measure labels var measureLabels = layout.qHyperCube.qMeasureInfo.map(function(d) { return d.qFallbackTitle; }); // Create a new array for our extension with a row for each row in the qMatrix var data = qMatrix.map(function(d) { // for each element in the matrix, create a new object that has a property // for the grouping dimension, the first metric, and the second metric return { «Dim1»:d[0].qText, «Metric1»:d[2].qNum, «Metric2»:d[3].qNum } });
Теперь у нас есть массив данных, который называется measureLabels, содержащий текстовые значения наших меток.
Теперь давайте пропишем ширину, высоту и идентификатор объекта диаграммы. Получит так.
// Chart object width var width = $element.width(); // Chart object height var height = $element.height(); // Chart object id var id = «container_» + layout.qInfo.qId; // Check to see if the chart element has already been created if (document.getElementById(id)) { // if it has been created, empty it’s contents so we can redraw it $(«#» + id).empty(); } else { // if it hasn’t been created, create it with the appropiate id and size $element.append($(‘<div />’).attr(«id», id).width(width).height(height)); }
И наконец, создаем функцию визуализации.
viz(data,measureLabels,width,height,id);
Вся функция работы с визуализацией получится такой:
paint : function($element,layout) { // get qMatrix data array var qMatrix = layout.qHyperCube.qDataPages[0].qMatrix; // create a new array that contains the measure labels var measureLabels = layout.qHyperCube.qMeasureInfo.map(function(d) { return d.qFallbackTitle; }); // Create a new array for our extension with a row for each row in the qMatrix var data = qMatrix.map(function(d) { // for each element in the matrix, create a new object that has a property // for the grouping dimension, the first metric, and the second metric return { «Dim1»:d[0].qText, «Metric1»:d[2].qNum, «Metric2»:d[3].qNum } }); // Chart object width var width = $element.width(); // Chart object height var height = $element.height(); // Chart object id var id = «container_» + layout.qInfo.qId; // Check to see if the chart element has already been created if (document.getElementById(id)) { // if it has been created, empty it’s contents so we can redraw it $(«#» + id).empty(); } else { // if it hasn’t been created, create it with the appropiate id and size $element.append($(‘<div />;’).attr(«id», id).width(width).height(height)); } viz(data,measureLabels,width,height,id); }
Создаем новую функцию визуализации viz в верхней части файла JS, вне выражения define(). Она должна описывать соответствующее число значений:
var viz = function(data,labels,width,height,id) { };
КОПИРУЕМ КОД D3
Запускаем d3 и копируем его в JavaScript. Часть JavaScript находится внутри html-файла, внутри тега <script> в теле страницы. Вставляем такой код в функцию визуализации. Получится так:
var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 — margin.left — margin.right, height = 500 — margin.top — margin.bottom; var x = d3.scale.linear() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.category10(); var xAxis = d3.svg.axis() .scale(x) .orient(«bottom»); var yAxis = d3.svg.axis() .scale(y) .orient(«left»); var svg = d3.select(«body»).append(«svg») .attr(«width», width + margin.left + margin.right) .attr(«height», height + margin.top + margin.bottom) .append(«g») .attr(«transform», «translate(» + margin.left + «,» + margin.top + «)»); d3.tsv(«data.tsv», function(error, data) { data.forEach(function(d) { d.sepalLength = +d.sepalLength; d.sepalWidth = +d.sepalWidth; }); x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice(); y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice(); svg.append(«g») .attr(«class», «x axis») .attr(«transform», «translate(0,» + height + «)») .call(xAxis) .append(«text») .attr(«class», «label») .attr(«x», width) .attr(«y», -6) .style(«text-anchor», «end») .text(«Sepal Width (cm)»); svg.append(«g») .attr(«class», «y axis») .call(yAxis) .append(«text») .attr(«class», «label») .attr(«transform», «rotate(-90)») .attr(«y», 6) .attr(«dy», «.71em») .style(«text-anchor», «end») .text(«Sepal Length (cm)») svg.selectAll(«.dot») .data(data) .enter().append(«circle») .attr(«class», «dot») .attr(«r», 3.5) .attr(«cx», function(d) { return x(d.sepalWidth); }) .attr(«cy», function(d) { return y(d.sepalLength); }) .style(«fill», function(d) { return color(d.species); }); var legend = svg.selectAll(«.legend») .data(color.domain()) .enter().append(«g») .attr(«class», «legend») .attr(«transform», function(d, i) { return «translate(0,» + i * 20 + «)»; }); legend.append(«rect») .attr(«x», width — 18) .attr(«width», 18) .attr(«height», 18) .style(«fill», color); legend.append(«text») .attr(«x», width — 24) .attr(«y», 9) .attr(«dy», «.35em») .style(«text-anchor», «end») .text(function(d) { return d; }); });
Изменяем код D3
Вот, что нам нужно изменить для того, чтобы все шло по плану:
- Убираем описание загрузки в коде D Наши данные уже загружены через расширение.
- Изменяем размер значений.
- Настраиваем SVG.
- Меняем ссылки на данные.
- Удаляем загрузку данных D3
Вот, что мы видим
d3.tsv(«data.tsv», function(error, data) { data.forEach(function(d) { d.sepalLength = +d.sepalLength; d.sepalWidth = +d.sepalWidth; });
Функция d3.tsv имеет два параметра: путь к файлу, а также функцию возврата для вычисления. Функция возврата включается как только запускается код создания визуализации, после загрузки файла “data.tsv”. Мы уберем, как это обращение, так и файл data.forEach. Результат будет таким:
var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 960 — margin.left — margin.right, height = 500 — margin.top — margin.bottom; var x = d3.scale.linear() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.category10(); var xAxis = d3.svg.axis() .scale(x) .orient(«bottom»); var yAxis = d3.svg.axis() .scale(y) .orient(«left»); var svg = d3.select(«body»).append(«svg») .attr(«width», width + margin.left + margin.right) .attr(«height», height + margin.top + margin.bottom) .append(«g») .attr(«transform», «translate(» + margin.left + «,» + margin.top + «)»); x.domain(d3.extent(data, function(d) { return d.sepalWidth; })).nice(); y.domain(d3.extent(data, function(d) { return d.sepalLength; })).nice(); svg.append(«g») .attr(«class», «x axis») .attr(«transform», «translate(0,» + height + «)») .call(xAxis) .append(«text») .attr(«class», «label») .attr(«x», width) .attr(«y», -6) .style(«text-anchor», «end») .text(«Sepal Width (cm)»); svg.append(«g») .attr(«class», «y axis») .call(yAxis) .append(«text») .attr(«class», «label») .attr(«transform», «rotate(-90)») .attr(«y», 6) .attr(«dy», «.71em») .style(«text-anchor», «end») .text(«Sepal Length (cm)») svg.selectAll(«.dot») .data(data) .enter().append(«circle») .attr(«class», «dot») .attr(«r», 3.5) .attr(«cx», function(d) { return x(d.sepalWidth); }) .attr(«cy», function(d) { return y(d.sepalLength); }) .style(«fill», function(d) { return color(d.species); }); var legend = svg.selectAll(«.legend») .data(color.domain()) .enter().append(«g») .attr(«class», «legend») .attr(«transform», function(d, i) { return «translate(0,» + i * 20 + «)»; }); legend.append(«rect») .attr(«x», width — 18) .attr(«width», 18) .attr(«height», 18) .style(«fill», color); legend.append(«text») .attr(«x», width — 24) .attr(«y», 9) .attr(«dy», «.35em») .style(«text-anchor», «end») .text(function(d) { return d; });
- Обновляем размер значений
Вторая и третья строка D3 кода определяет, какая ширина и высота значений будет, за минусом отступов. Выглядит так:
width = width — margin.left — margin.right, height = height — margin.top — margin.bottom;
- Настройка элемента svg
Вставляем новый элемент svg.
var svg = d3.select(«#»+id).append(«svg»)
- Использование корректных имен
Просмотрим код D3, увидим, что там используются изначальные названия таблиц. Например:
svg.selectAll(«.dot») .data(data) .enter().append(«circle») .attr(«class», «dot») .attr(«r», 3.5) .attr(«cx», function(d) { return x(d.sepalWidth); }) .attr(«cy», function(d) { return y(d.sepalLength); }) .style(«fill», function(d) { return color(d.species); });
Все ссылки надо заменить с d.sepalWidth на d.Metric1; d.sepalLength на d.Metric2, а также с d.species на d.Dim1.
Ярлыки для осей представлены вот так:
svg.append(«g») .attr(«class», «x axis») .attr(«transform», «translate(0,» + height + «)») .call(xAxis) .append(«text») .attr(«class», «label») .attr(«x», width) .attr(«y», -6) .style(«text-anchor», «end») .text(«Sepal Width (cm)»);
Вместо того чтобы делать тяжелый код для осей, мы можем просто использовать переменные:
svg.append(«g») .attr(«class», «x axis») .attr(«transform», «translate(0,» + height + «)») .call(xAxis) .append(«text») .attr(«class», «label») .attr(«x», width) .attr(«y», -6) .style(«text-anchor», «end») .text(labels[0]);
Получит так:
var viz = function (data,labels,width,height,id) { var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = width — margin.left — margin.right, height = height — margin.top — margin.bottom; var x = d3.scale.linear() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.category10(); var xAxis = d3.svg.axis() .scale(x) .orient(«bottom»); var yAxis = d3.svg.axis() .scale(y) .orient(«left»); var svg = d3.select(«#»+id).append(«svg») .attr(«width», width + margin.left + margin.right) .attr(«height», height + margin.top + margin.bottom) .append(«g») .attr(«transform», «translate(» + margin.left + «,» + margin.top + «)»); x.domain(d3.extent(data, function(d) { return d.Metric1; })).nice(); y.domain(d3.extent(data, function(d) { return d.Metric2; })).nice(); svg.append(«g») .attr(«class», «x axis») .attr(«transform», «translate(0,» + height + «)») .call(xAxis) .append(«text») .attr(«class», «label») .attr(«x», width) .attr(«y», -6) .style(«text-anchor», «end») .text(labels[0]); svg.append(«g») .attr(«class», «y axis») .call(yAxis) .append(«text») .attr(«class», «label») .attr(«transform», «rotate(-90)») .attr(«y», 6) .attr(«dy», «.71em») .style(«text-anchor», «end») .text(labels[1]) svg.selectAll(«.dot») .data(data) .enter().append(«circle») .attr(«class», «dot») .attr(«r», 3.5) .attr(«cx», function(d) { return x(d.Metric1); }) .attr(«cy», function(d) { return y(d.Metric2); }) .style(«fill», function(d) { return color(d.Dim1); }); var legend = svg.selectAll(«.legend») .data(color.domain()) .enter().append(«g») .attr(«class», «legend») .attr(«transform», function(d, i) { return «translate(0,» + i * 20 + «)»; }); legend.append(«rect») .attr(«x», width — 18) .attr(«width», 18) .attr(«height», 18) .style(«fill», color); legend.append(«text») .attr(«x», width — 24) .attr(«y», 9) .attr(«dy», «.35em») .style(«text-anchor», «end») .text(function(d) { return d; }); }
Изменяем CSS
Завершающий шаг — изменение CSS. Если вы посмотрите на оригинал d3 диаграммы в HTML, у вас будет такой код:
body { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .dot { stroke: #000; }
Мы можем изменить код и вставить его twodimscatter.css file. Что надо изменить:
- Изменить стиль “body”
- Добавить класс “.qv-object-twodimscatter” , чтобы наш CSS не влиял не на какие элементы вне диаграммы.
Изменения в twodimscatter.css выглядят так:
qv-object-twodimscatter div.qv-object-content-container { font: 10px sans-serif; } .qv-object-twodimscatter .axis path, .qv-object-twodimscatter .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .qv-object-twodimscatter .dot { stroke: #000; }
ПРОСМОТР РАСШИРЕНИЯ
После всех изменений все сохраняем и смотрим, как изменилось наше приложение. Открываем приложение Qlik Sense и находим лист с расширением.
НА ЗАМЕТКУ! ЕСЛИ ЛИСТ УЖЕ ОТКРЫТ, ТО ОБНОВЛЯЕМ СТРАНИЦУ КНОПКОЙ “F5″.
Теперь на графике добавилась легенда, цветная.
НАПОСЛЕДОК
Мы можем продолжить работу с файлом JavaScript, чтобы снабдить визуализацию интерактивными компонентами и всплывающими ярлыками. Но в этот раз уже пора остановиться – позже вам напишу, если вам интересно узнать, как это сделать.
Код для нашего расширения. Файл JavaScript весь откомментирован, так что все качественно прописано, поэтому изучайте.
До новых встреч в эфире! Делитесь своим мнением в комментариях!
Источник – Блог Data Daily