Библиотеки диаграмм 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 здесь: ссылка