219 lines
8.3 KiB
JavaScript
219 lines
8.3 KiB
JavaScript
(function (global) {
|
|
var MODES = [
|
|
{ id: 'neo-bars', label: 'Neo staafdiagram' },
|
|
{ id: 'neo-rings', label: 'Neo ringen' },
|
|
{ id: 'neo-equalizer', label: 'Neo equalizer' },
|
|
{ id: 'neo-cards', label: 'Neo kaarten' },
|
|
{ id: 'neo-table', label: 'Neo tabel' },
|
|
];
|
|
|
|
var charts = {};
|
|
|
|
function destroy(key) {
|
|
if (charts[key]) {
|
|
charts[key].destroy();
|
|
charts[key] = null;
|
|
}
|
|
}
|
|
|
|
function colors() {
|
|
return {
|
|
gold: 'rgba(252, 211, 77, 0.9)', cyan: 'rgba(56, 189, 248, 0.9)',
|
|
green: 'rgba(74, 222, 128, 0.9)', red: 'rgba(251, 113, 133, 0.9)',
|
|
purple: 'rgba(168, 85, 247, 0.9)', gray: 'rgba(159, 176, 196, 0.85)',
|
|
grid: 'rgba(159, 176, 196, 0.15)', text: '#c8d4e0',
|
|
};
|
|
}
|
|
|
|
function eqBars(counts, cls) {
|
|
var max = Math.max.apply(null, counts.concat([1]));
|
|
return '<div class="hm-eq viz-eq ' + (cls || '') + '">' +
|
|
counts.map(function (v) {
|
|
var h = Math.max(18, Math.round((v / max) * 92));
|
|
return '<span style="height:' + h + '%"></span>';
|
|
}).join('') + '</div>';
|
|
}
|
|
|
|
function findPanel(canvas, alt) {
|
|
var el = (canvas && canvas.closest('.page-viz-panel')) || (alt && alt.closest('.page-viz-panel'));
|
|
return el || null;
|
|
}
|
|
|
|
function applyPanelLayout(canvas, alt, mode) {
|
|
var panel = findPanel(canvas, alt);
|
|
if (!panel) return;
|
|
var isCanvas = mode === 'neo-bars' || mode === 'neo-rings';
|
|
panel.classList.toggle('viz-mode-chart', isCanvas);
|
|
panel.classList.toggle('viz-mode-alt', !isCanvas);
|
|
panel.classList.toggle('viz-mode-rings', mode === 'neo-rings');
|
|
}
|
|
|
|
function useHorizontal(labels, opts) {
|
|
if (opts && opts.horizontal !== undefined) return opts.horizontal;
|
|
return (labels || []).length >= 6;
|
|
}
|
|
|
|
function renderBars(canvas, labels, values, opts) {
|
|
if (!canvas || typeof Chart === 'undefined') return;
|
|
opts = opts || { key: 'chart' };
|
|
var c = colors();
|
|
var horiz = useHorizontal(labels, opts);
|
|
destroy(opts.key);
|
|
charts[opts.key] = new Chart(canvas, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{ data: values, backgroundColor: opts.color || c.cyan, borderRadius: 6, barThickness: horiz ? 'flex' : undefined, maxBarThickness: horiz ? 28 : 48 }],
|
|
},
|
|
options: {
|
|
indexAxis: horiz ? 'y' : 'x',
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
layout: { padding: { top: 4, right: 8, bottom: 4, left: 4 } },
|
|
plugins: { legend: { display: false }, title: { display: !!opts.title, text: opts.title, color: c.text, padding: { bottom: 8 } } },
|
|
scales: {
|
|
y: horiz
|
|
? { ticks: { color: c.text, autoSkip: false, font: { size: 11 } }, grid: { color: c.grid } }
|
|
: { ticks: { color: c.text }, grid: { color: c.grid }, beginAtZero: true },
|
|
x: horiz
|
|
? { ticks: { color: c.text }, grid: { display: false }, beginAtZero: true }
|
|
: { ticks: { color: c.text, maxRotation: 45, minRotation: 0, autoSkip: false, font: { size: 10 } }, grid: { display: false } },
|
|
},
|
|
},
|
|
});
|
|
requestAnimationFrame(function () {
|
|
if (charts[opts.key]) charts[opts.key].resize();
|
|
});
|
|
}
|
|
|
|
function renderRings(canvas, labels, values, key, title) {
|
|
if (!canvas || typeof Chart === 'undefined') return;
|
|
var c = colors();
|
|
destroy(key);
|
|
charts[key] = new Chart(canvas, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{ data: values, backgroundColor: [c.green, c.gray, c.red, c.gold, c.cyan, c.purple], borderWidth: 0 }],
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
cutout: '62%',
|
|
layout: { padding: 4 },
|
|
plugins: {
|
|
legend: { position: 'bottom', labels: { color: c.text, boxWidth: 10, padding: 8, font: { size: 10 } } },
|
|
title: { display: !!title, text: title, color: c.text, font: { size: 11 } },
|
|
},
|
|
},
|
|
});
|
|
requestAnimationFrame(function () {
|
|
if (charts[key]) charts[key].resize();
|
|
});
|
|
}
|
|
|
|
function renderCards(container, rows) {
|
|
if (!container) return;
|
|
container.innerHTML = '<div class="viz-cards">' + rows.map(function (r) {
|
|
return '<div class="viz-card"><span class="viz-card-label">' + r.label + '</span><strong class="viz-card-val">' + r.value + '</strong></div>';
|
|
}).join('') + '</div>';
|
|
}
|
|
|
|
function renderTable(container, rows) {
|
|
if (!container) return;
|
|
container.innerHTML = '<table class="data-table viz-table"><thead><tr><th>Item</th><th>Waarde</th></tr></thead><tbody>' +
|
|
rows.map(function (r) { return '<tr><td>' + r.label + '</td><td>' + r.value + '</td></tr>'; }).join('') +
|
|
'</tbody></table>';
|
|
}
|
|
|
|
function renderEqualizer(container, rows, cls) {
|
|
if (!container) return;
|
|
container.innerHTML = rows.map(function (r) {
|
|
return '<div class="viz-eq-row"><span>' + r.label + '</span><strong>' + r.value + '</strong></div>';
|
|
}).join('') + eqBars(rows.map(function (r) { return Number(r.raw) || 0; }), cls);
|
|
}
|
|
|
|
function renderWidget(mode, spec) {
|
|
var canvas = spec.canvas;
|
|
var alt = spec.altContainer;
|
|
applyPanelLayout(canvas, alt, mode);
|
|
if (mode === 'neo-bars' && canvas) {
|
|
if (alt) alt.innerHTML = '';
|
|
canvas.style.display = '';
|
|
renderBars(canvas, spec.labels, spec.values, spec.chartOpts || { key: spec.key });
|
|
return;
|
|
}
|
|
if (mode === 'neo-rings' && canvas) {
|
|
if (alt) alt.innerHTML = '';
|
|
canvas.style.display = '';
|
|
renderRings(canvas, spec.labels, spec.values, spec.key, spec.title);
|
|
return;
|
|
}
|
|
if (canvas) canvas.style.display = 'none';
|
|
if (!alt) return;
|
|
if (mode === 'neo-equalizer') renderEqualizer(alt, spec.rows, spec.eqClass);
|
|
else if (mode === 'neo-cards') renderCards(alt, spec.rows);
|
|
else if (mode === 'neo-table') renderTable(alt, spec.rows);
|
|
else {
|
|
if (canvas) { canvas.style.display = ''; renderBars(canvas, spec.labels, spec.values, spec.chartOpts || { key: spec.key }); }
|
|
}
|
|
}
|
|
|
|
global.VizEngine = {
|
|
MODES: MODES,
|
|
renderWidget: renderWidget,
|
|
destroyAll: function () { Object.keys(charts).forEach(destroy); },
|
|
renderSentiment: function (mode, canvas, alt, stats, widgetMode) {
|
|
var m = widgetMode || mode;
|
|
var files = stats.nas_files || [];
|
|
var counts = { positive: 0, neutral: 0, negative: 0 };
|
|
files.forEach(function (f) {
|
|
var s = (f.sentiment_label || 'neutral').toLowerCase();
|
|
if (counts[s] !== undefined) counts[s]++;
|
|
});
|
|
if (!files.length) counts.neutral = 1;
|
|
renderWidget(m, {
|
|
canvas: canvas, altContainer: alt, key: 'sentiment',
|
|
labels: ['Positief', 'Neutraal', 'Negatief'],
|
|
values: [counts.positive, counts.neutral, counts.negative],
|
|
title: 'NAS sentiment',
|
|
rows: [
|
|
{ label: 'Positief', value: counts.positive, raw: counts.positive },
|
|
{ label: 'Neutraal', value: counts.neutral, raw: counts.neutral },
|
|
{ label: 'Negatief', value: counts.negative, raw: counts.negative },
|
|
],
|
|
eqClass: 'hm-eq-purple',
|
|
});
|
|
},
|
|
renderAgents: function (mode, canvas, alt, stats, widgetMode) {
|
|
var m = widgetMode || mode;
|
|
var map = {};
|
|
(stats.recent_events || []).forEach(function (e) {
|
|
var a = e.agent_name || 'other';
|
|
map[a] = (map[a] || 0) + 1;
|
|
});
|
|
var labels = Object.keys(map);
|
|
var values = labels.map(function (k) { return map[k]; });
|
|
if (!labels.length) { labels = ['geen']; values = [0]; }
|
|
renderWidget(m, {
|
|
canvas: canvas, altContainer: alt, key: 'agents',
|
|
labels: labels, values: values, title: 'Agent activiteit',
|
|
chartOpts: { key: 'agents', color: colors().gold },
|
|
rows: labels.map(function (l, i) { return { label: l, value: values[i], raw: values[i] }; }),
|
|
eqClass: 'hm-eq-lime',
|
|
});
|
|
},
|
|
renderFromRows: function (mode, canvas, alt, key, title, rows, eqClass, chartColor) {
|
|
var labels = rows.map(function (r) { return r.label; });
|
|
var values = rows.map(function (r) { return Number(r.raw) || 0; });
|
|
renderWidget(mode, {
|
|
canvas: canvas, altContainer: alt, key: key,
|
|
labels: labels, values: values, title: title,
|
|
chartOpts: { key: key, color: chartColor || colors().cyan },
|
|
rows: rows,
|
|
eqClass: eqClass || 'hm-eq-cyan',
|
|
});
|
|
},
|
|
};
|
|
})(window);
|