Новый 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” в редакторе текста. У меня такие настройки:
1 |
2
3
4
5
6
7
8
9{
«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 должен получиться таким:
1 |
2.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, поэтому нам не нужно сохранять локальные копии расширения.
Настройки и определения
Проработав со всеми нужными нам файлами, меняем настройки и определения нашего расширения. В них определяется объем получаемых данных, а также определяется, сколько измерений и выражений нужно для запуска расширения.
В этом файле, в самом начале вы увидите такой код:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40return {
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″. Затем добавляем запятую и добавляем новую строку и выбираем максимальное значение равное двум. Делаем то же самое для мер. Получится вот так:
1 |
2
3
4
5
6
7
8
9
10dimensions : {
uses : «dimensions»,
min : 2,
max: 2
},
measures : {
uses : «measures»,
min : 2,
max: 2
},
В 32 строке создаются элементы расширения. Удаляем 32 и 39 строку. Результат должен выглядеть так:
1 |
2
3settings : {
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 и в браузере. Функция рисования визуализации должна выглядеть так:
1 |
2
3
4paint : 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 с помощью следующих строк кода
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 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, содержащий текстовые значения наших меток.
Теперь давайте пропишем ширину, высоту и идентификатор объекта диаграммы. Получит так.
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 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));
}
И наконец, создаем функцию визуализации.
1 | viz(data,measureLabels,width,height,id); |
Вся функция работы с визуализацией получится такой:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38paint : 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(). Она должна описывать соответствующее число значений:
1 |
2var viz = function(data,labels,width,height,id) {
};
Копируем код D3
Запускаем d3 и копируем его в JavaScript. Часть JavaScript находится внутри html-файла, внутри тега <script> в теле страницы. Вставляем такой код в функцию визуализации. Получится так:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86var 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
Вот, что мы видим
1 |
2
3
4
5d3.tsv(«data.tsv», function(error, data) {
data.forEach(function(d) {
d.sepalLength = +d.sepalLength;
d.sepalWidth = +d.sepalWidth;
});
Функция d3.tsv имеет два параметра: путь к файлу, а также функцию возврата для вычисления. Функция возврата включается как только запускается код создания визуализации, после загрузки файла “data.tsv”. Мы уберем, как это обращение, так и файл data.forEach. Результат будет таким:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78var 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 кода определяет, какая ширина и высота значений будет, за минусом отступов. Выглядит так:
1 |
2width = width — margin.left — margin.right,
height = height — margin.top — margin.bottom;
- Настройка элемента svg
Вставляем новый элемент svg.
1 | var svg = d3.select(«#»+id).append(«svg») |
- Использование корректных имен
Просмотрим код D3, увидим, что там используются изначальные названия таблиц. Например:
1 |
2
3
4
5
6
7
8svg.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.
Ярлыки для осей представлены вот так:
1 |
2
3
4
5
6
7
8
9
10svg.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)»);
Вместо того чтобы делать тяжелый код для осей, мы можем просто использовать переменные:
1 |
2
3
4
5
6
7
8
9
10svg.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]);
Получит так:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82var 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, у вас будет такой код:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14body {
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 выглядят так:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14.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 весь откомментирован, так что все качественно прописано, поэтому изучайте.
До новых встреч в эфире! Делитесь своим мнением в комментариях!
Добрый день!
Вроде ссылка на ГитХаб не рабочая на min.js
Андрей, спасибо! Ссылку обновили.
Если можно отредактируйте визуализацию кода, очень не удобно читать(