Библиотеки диаграмм JS с NPrinting
Вы когда-нибудь хотели создать отчет в NPrinting на основе HTML с красивыми, «адаптивными» диаграммами? Я это сделал, и был очень воодушевлен тем, как мне это удалось. В зависимости от выбранной вами библиотеки диаграмм (D3.js, TOAST UI, Chart.js или многие другие…) ваш результат может немного отличаться от моего. Я собираюсь использовать в этом примере диаграммы Google и, очевидно, NPrinting. Важно: вы должны подумать, с какой библиотекой вы хотите работать. Некоторые из них требуют лицензионного ключа, а у других – открытый исходный код.
Задача: создать одностраничный отчет с картой, круговой диаграммой, небольшой таблицей и гистограммой. Он должен выглядеть как на примере ниже:
Это я сделал этот скетч
Прежде чем я начну работу в NPrinting, мне нужно подумать, какие диаграммы я буду использовать в своем HTML-отчете и какой формат данных мне понадобится для этого. Первое, что вам нужно сделать, это прочитать документацию библиотеки, которую вы хотите использовать. В моем случае это скрипты, которые меня интересуют такие:
Карта с использованием GeoChart: (ссылка на исходный код)
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {
'packages':['geochart'],
// Примечание: вам нужно будет получить mapsApiKey для этого проекта.
// См: https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings
'mapsApiKey': 'AIzaSyD-9tSrke72PouQMnMX-a7eZSW0jkFMBWY'
});
google.charts.setOnLoadCallback(drawRegionsMap);
function drawRegionsMap() {
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity'],
['Germany', 200],
['United States', 300],
['Brazil', 400],
['Canada', 500],
['France', 600],
['RU', 700]
]);
var options = {};
var chart = new google.visualization.GeoChart(document.getElementById('regions_div'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="regions_div" style="width: 900px; height: 500px;"></div>
</body>
</html>
Посмотрев на представленный выше код, вы увидите, что данные, которые нам нужно будет заполнять динамически, находятся в массивах [‘Country’, ‘Popularity’]. Для простоты мы будем придерживаться основных настроек карты.
Таблица с использованием табличной диаграммы: (ссылка на исходный код)
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['table']});
google.charts.setOnLoadCallback(drawTable);
function drawTable() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('number', 'Salary');
data.addColumn('boolean', 'Full Time Employee');
data.addRows([
['Mike', {v: 10000, f: '$10,000'}, true],
['Jim', {v:8000, f: '$8,000'}, false],
['Alice', {v: 12500, f: '$12,500'}, true],
['Bob', {v: 7000, f: '$7,000'}, true]
]);
var table = new google.visualization.Table(document.getElementById('table_div'));
table.draw(data, {showRowNumber: true, width: '100%', height: '100%'});
}
</script>
</head>
<body>
<div id="table_div"></div>
</body>
</html>
То же самое относится и к примеру таблицы, где мы будем в основном сосредоточены нестандартных на настройках, а динамическая часть будет представлять собой только массив с такими данными, как: ['Mike', {v: 10000, f: '$ 10,000'}, true] и имена столбцов, объявленные как параметры, например: data.addColumn ('string', 'Name');
Моя круговая и столбчатая диаграммы будут из одной библиотеки (ссылка на документацию), и принципы их построения одинаковы. Библиотека ждет массив со значениями и может иметь параметризованные свойства.
Приступим к созданию источника данных. Для начала я создал приложение Qlik Sense с объектами, требующими детализации и разметки данных. Я также создал еще один лист, на котором есть объекты для NPrinting с выражениями, которые создадут весь массив данных, необходимых для моей библиотеки диаграмм. Смотрите скриншоты:
Макет моего отчета Qlik Sense
Объект Qlik Sense с выражениями, которые создают необходимые массивы данных
Для карты, таблицы и гистограммы с накоплением я использовал одну таблицу Qlik Sense с измерением и показателями страны: меры Sum(Population), Sum({<Gender={Male}>}Population) и Sum({<Gender={Female}>}Population). А вот массивы для HTML-диаграмм:
Карта:
'['&CHR(39)&Only(Country)&CHR(39)&','&sum(Population)&']'
Таблица:
='['&CHR(39)&Country&CHR(39)&',{v: '&sum(Population)&', f: '&CHR(39)&num(sum(Population),'#,##0')&CHR(39)&'},{v: '&sum({<Gender={Male}>}Population)&', f: '&CHR(39)&num(sum({<Gender={Male}>}Population),'#,##0')&CHR(39)&'},{v: '&sum({<Gender={Female}>}Population)&', f: '&CHR(39)&num(sum({<Gender={Female}>}Population),'#,##0')&CHR(39)&'}]'
Столбчатая диаграмма:
='['&CHR(39)&Country&CHR(39)&','&sum({}Population)&','&CHR(39)&'Male: ' &num(sum({}Population))&' ('&num(sum({}Population)/sum(Population),'#,##0.0%')&')'&CHR(39)&',' &sum({}Population)&','&CHR(39)&'Female: '&num(sum({}Population))&' ('&num(sum({}Population)/sum(Population),'#,##0.0%')&')'&CHR(39)&']'
Круговая диаграмма – требует разной степени детализации (только гендерное измерение), поэтому ее поддерживает отдельный объект:
'['&CHR(39)&Only(Gender)&CHR(39)&','&sum(Population)&']'
Все вышеупомянутые выражения созданы как основные меры для упрощения работы с NPrinting в дальнейшем. Теперь я могу перейти к NPrinting, создать соединение с приложением Qlik Sense, перезагрузить метаданные, создать новый отчет HTML и отредактировать шаблон. В NPrinting мы нет много можем сделать. Сначала мы должны ввести наши 2 таблицы как уровни, а также как таблицы. На следующем шаге нам нужно скопировать/вставить скрипты из библиотеки диаграмм и вставить их в нужные места в HTML. Ниже представлен весь сценарий, который я использовал. Я также выведу его как изображение, чтобы объяснить каждый раздел отдельно.
<html>
<head>
<style>
html, body {
height: 100%;
margin: 0;
}
.grid2x2 {
min-height: 100%;
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.grid2x2 > div {
display: flex;
flex-basis: calc(50% - 40px);
justify-content: center;
flex-direction: column;
}
.grid2x2 > div > div {
display: flex;
justify-content: center;
flex-direction: row;
}
.box { margin: 10px; }
.box1 { background-color: white; }
.box2 { background-color: white; }
.box3 { background-color: white; }
.box4 { background-color: white; }
</style>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['table']});
google.charts.load('current', {'packages':['geochart'],'mapsApiKey': 'AIzaSyD-9tSrke72PouQMnMX-a7eZSW0jkFMBWY'});
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback(drawStackedChart);
google.charts.setOnLoadCallback(drawPieChart);
google.charts.setOnLoadCallback(drawRegionsMap);
google.charts.setOnLoadCallback(drawTable);
function drawRegionsMap()
{
var data = google.visualization.arrayToDataTable([
['Country', 'Popultion']
%%273b292c-dda7-477c-9bc9-669706e2b1fb_Level%% ,%%YRMNe_1%%
%%/273b292c-dda7-477c-9bc9-669706e2b1fb_Level%%
]);
var options = {
title: 'Population by Country',
colorAxis: {colors: ['#3D5AA7','#88C2EC','#EAF2FB','#F39C67','#B2213F']},
backgroundColor: '#FFFFFF',
datalessRegionColor: '#E8EAED',
defaultColor: '#f5f5f5',
keepAspectRatio: 'false',
weight: '100%',
height: '400'
};
var chart = new google.visualization.GeoChart(document.getElementById('regions_div'));
chart.draw(data, options);
}
function drawTable()
{
var data = new google.visualization.DataTable();
data.addColumn('string', 'Country');
data.addColumn('number', 'Total Population');
data.addColumn('number', 'Male');
data.addColumn('number', 'Female');
data.addRows([
%%273b292c-dda7-477c-9bc9-669706e2b1fb_Level%% %%FvRkbM_1%%,
%%/273b292c-dda7-477c-9bc9-669706e2b1fb_Level%%
]);
var options = {
page: 'enable',
pageSize: 18,
weight: '550',
showRowNumber: true
}
var table = new google.visualization.Table(document.getElementById('table_div'));
table.draw(data, options);
}
function drawPieChart()
{
var data = google.visualization.arrayToDataTable([
['Gender', 'Popultion']
%%e064296a-2c40-4edd-ace7-859da3589b80_Level%%,%%Gbqphrd_1%%
%%/e064296a-2c40-4edd-ace7-859da3589b80_Level%%
]);
var options = {
title: 'Population by gender',
height: '400'
};
var chart = new google.visualization.PieChart(document.getElementById('piechart'));
chart.draw(data, options);
}
function drawStackedChart()
{
var data = google.visualization.arrayToDataTable([
['Country', 'Male',{ role: 'tooltip' }, 'Female',{ role: 'tooltip' } ]
%%273b292c-dda7-477c-9bc9-669706e2b1fb_Level%% ,%%tuxXKmw_1%%
%%/273b292c-dda7-477c-9bc9-669706e2b1fb_Level%%
]);
var options = {
title: 'Population by country & gender',
legend: { position: 'top', maxLines: 3 },
bar: { groupWidth: '75%' },
isStacked: true,
height: '400'
};
var chart = new google.visualization.ColumnChart(document.getElementById('columnchart_values'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div class="grid2x2">
<div class="box box1"><div id="regions_div" style="border: 1px solid #ccc"></div></div>
<div class="box box2"><div id="table_div" style="border: 1px solid #ccc"></div></div>
<div class="box box3"><div id="piechart" style="border: 1px solid #ccc"></div></div>
<div class="box box4"><div id="columnchart_values" style="border: 1px solid #ccc"></div></div>
</div>
</body>
</html>
- В этом разделе есть несколько стилей, которые я использовал в своем HTML.
- Раздел 2 содержит js-скрипты из библиотек. Ниже описаны динамические компоненты 4-7.
- Основная часть HTML, относящаяся к каждому компоненту диаграммы.
- Динамический раздел образующийся из уровня и таблицы (раздел круговой диаграммы)
- 5-7 Динамические разделы, относящиеся к столбцам уровня и таблицы.
Для всех объектов NPrinting мы должны отключить “Keep source format”, а для объектов таблицы мы должны отключить “HTML Encode”. Я также использую “Show Header”=”Hide”, поскольку мне не нужны заголовки.
Компоненты, которые являются динамическими в шаблоне NPrinting
Как видите, в фактическом шаблоне NPrinting требуется не так много. Вся тяжелая работа выполняется в Qlik Sense, а NPrinting просто создает почву для JS, чтобы сотворить настоящее чудо. Вот как выглядит итоговый отчет:
Готовый HTML-отчет
Резюме:
- Было ли это интересно строить? ДА!
- Вы бы использовали это в своей работе? Возможно
- Можете ли вы отправить этот отчет в теле письма? Нет, нельзя, т.к. JS не поддерживается в почтовых клиентах.
- Можете ли вы использовать его в автономном режиме? Я так не думаю, вам нужен будет доступ к любой JS-библиотеке, на которую указывает ваш скрипт.
- Я не веб-разработчик, и мои навыки HTML/JS ограничены, поэтому я, вероятно, допустил в этом коде массу ошибок.
- Пример приложения QS здесь: ссылка









