diff --git a/src/bundle/Resources/public/js/scripts/core/doughnut.chart.js b/src/bundle/Resources/public/js/scripts/core/doughnut.chart.js index 90a9bfce1a..6d4abb0e6a 100644 --- a/src/bundle/Resources/public/js/scripts/core/doughnut.chart.js +++ b/src/bundle/Resources/public/js/scripts/core/doughnut.chart.js @@ -1,4 +1,7 @@ (function (global, doc, ibexa, ChartDataLabels) { + const IBEXA_WHITE = '#fff'; + const IBEXA_COLOR_BASE_DARK = '#878b90'; + const dataLabelsMap = new Map(); const doughnutOptions = { plugins: { datalabels: { @@ -8,11 +11,18 @@ size: 18, }, formatter: (value, context) => { - const sum = context.dataset.data.reduce((acc, curValue) => acc + curValue, 0); + const visibleData = context.dataset.data.filter((dataValue, dataIndex) => dataLabelsMap.get(dataIndex)); + const sum = visibleData.reduce((acc, curValue) => acc + curValue, 0); const percentage = (value / sum) * 100; return `${Math.floor(percentage)}%`; }, + display: (context) => { + const { dataIndex } = context; + const isVisible = dataLabelsMap.get(dataIndex); + + return isVisible; + }, }, }, }; @@ -24,8 +34,11 @@ this.setOptions(options); this.type = 'doughnut'; + this.chartNode = data.ref; + this.canvas = this.chartNode.querySelector('.ibexa-chart__canvas'); + this.legendNode = this.chartNode.querySelector('.ibexa-chart-legend'); - this.initialize(data.ref); + this.initialize(this.chartNode); } initialize(ref) { @@ -48,7 +61,85 @@ setPlugins(plugins) { super.setPlugins(plugins); - this.plugins = [...doughnutPlugins, ...this.plugins]; + const beforeInitPlugin = [ + { + beforeInit: (chart) => { + const { itemTemplate } = this.legendNode.dataset; + const fragment = doc.createDocumentFragment(); + const data = chart.data.datasets[0]; + + data.legend.forEach((legendItem, index) => { + dataLabelsMap.set(index, true); + + const container = doc.createElement('div'); + const renderedItemTemplate = itemTemplate + .replace('{{ checked_color }}', data.backgroundColor[index]) + .replace('{{ dataset_index }}', index) + .replace('{{ label }}', legendItem); + + container.insertAdjacentHTML('beforeend', renderedItemTemplate); + + const checkboxNode = container.querySelector('.ibexa-chart-legend__item-wrapper'); + + checkboxNode.querySelector('input').checked = true; + fragment.append(checkboxNode); + }); + + this.legendNode.appendChild(fragment); + + return fragment; + }, + }, + ]; + + this.plugins = [...beforeInitPlugin, ...doughnutPlugins, ...this.plugins]; + } + + setLegendCheckboxBackground(checkbox) { + const { checkedColor } = checkbox.dataset; + const { checked } = checkbox; + + if (checked) { + checkbox.style.backgroundColor = checkedColor; + checkbox.style.borderColor = checkedColor; + } else { + checkbox.style.backgroundColor = IBEXA_WHITE; + checkbox.style.borderColor = IBEXA_COLOR_BASE_DARK; + } + } + + updateDataLabels(checkbox, datasetIndex) { + const { checked } = checkbox; + + if (typeof datasetIndex !== 'number') { + return; + } + + dataLabelsMap.set(datasetIndex, checked); + } + + setLegendCheckboxes() { + if (!this.legendNode) { + return; + } + + this.legendNode.querySelectorAll('.ibexa-input--legend-item-checkbox').forEach((checkbox) => { + this.setLegendCheckboxBackground(checkbox); + checkbox.addEventListener('change', (event) => { + const datasetIndex = parseInt(event.currentTarget.dataset.datasetIndex, 10); + + this.setLegendCheckboxBackground(event.currentTarget); + this.updateDataLabels(event.currentTarget, datasetIndex); + + const chartMethod = event.currentTarget.checked ? 'show' : 'hide'; + + this.chart[chartMethod](0, datasetIndex); + }); + }); + } + + callbackAfterRender() { + this.setLegendCheckboxes(); } }