update chart dashboard
This commit is contained in:
@@ -81,6 +81,29 @@ window.config = {
|
||||
enableMenuLocalStorage: true // Enable menu state with local storage support
|
||||
};
|
||||
|
||||
// Choose the label color with the higher contrast against each chart slice.
|
||||
window.config.chartTextColor = function (color) {
|
||||
let hex = String(color || '').trim().replace(/^#/, '');
|
||||
if (/^[0-9a-f]{3}$/i.test(hex)) {
|
||||
hex = hex.split('').map(value => value + value).join('');
|
||||
}
|
||||
if (!/^[0-9a-f]{6}$/i.test(hex)) return '#212529';
|
||||
|
||||
const luminance = function (value) {
|
||||
const channels = value.match(/../g).map(channel => {
|
||||
const srgb = parseInt(channel, 16) / 255;
|
||||
return srgb <= 0.04045 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
|
||||
});
|
||||
return channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
|
||||
};
|
||||
const background = luminance(hex);
|
||||
const dark = luminance('212529');
|
||||
const darkContrast = (Math.max(background, dark) + 0.05) / (Math.min(background, dark) + 0.05);
|
||||
const lightContrast = 1.05 / (background + 0.05);
|
||||
|
||||
return darkContrast >= lightContrast ? '#212529' : '#ffffff';
|
||||
};
|
||||
|
||||
window.assetsPath = document.documentElement.getAttribute('data-assets-path');
|
||||
window.templateName = document.documentElement.getAttribute('data-template');
|
||||
|
||||
|
||||
@@ -2011,7 +2011,11 @@
|
||||
series: data.series,
|
||||
colors: colors,
|
||||
stroke: { width: 0 },
|
||||
dataLabels: { enabled: false },
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
style: { colors: colors.map(config.chartTextColor) },
|
||||
dropShadow: { enabled: false },
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
position: 'bottom',
|
||||
@@ -2051,7 +2055,7 @@
|
||||
<div
|
||||
style="
|
||||
background: ${color};
|
||||
color: #fff;
|
||||
color: ${config.chartTextColor(color)};
|
||||
padding: 8px 12px;
|
||||
border-radius: 5px;
|
||||
font-size: 13px;
|
||||
|
||||
@@ -1713,6 +1713,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const totalPetani = lakiLaki + perempuan;
|
||||
|
||||
if (genderChartEl) {
|
||||
const genderColors = [pastelSemantic.info || '#5FC7D6', pastelSemantic.pink || '#F47C86'];
|
||||
const genderChartConfig = {
|
||||
chart: {
|
||||
height: 365,
|
||||
@@ -1732,7 +1733,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
labels: ['Laki-laki', 'Perempuan'],
|
||||
series: [lakiLaki, perempuan],
|
||||
colors: [pastelSemantic.info || '#5FC7D6', pastelSemantic.pink || '#F47C86'],
|
||||
colors: genderColors,
|
||||
stroke: { width: 0 },
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
@@ -1748,15 +1749,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fontSize: '13px',
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: 600,
|
||||
colors: ['#fff']
|
||||
colors: genderColors.map(config.chartTextColor)
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
top: 1,
|
||||
left: 1,
|
||||
blur: 2,
|
||||
opacity: 0.45
|
||||
}
|
||||
dropShadow: { enabled: false }
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
@@ -2120,6 +2115,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const farmerGroupFilters = ['terdaftar', 'tidak_terdaftar', 'belum_terisi'];
|
||||
const totalFarmerGroup = farmerGroupData.reduce((total, value) => total + value, 0);
|
||||
|
||||
const farmerGroupColors = [pastelSemantic.success || '#6FD68F', pastelSemantic.warning || '#FFB46F', pastelSemantic.secondary || '#9EA6B0'];
|
||||
const farmerGroupChartConfig = {
|
||||
chart: {
|
||||
height: 365,
|
||||
@@ -2139,7 +2135,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
labels: ['Terdaftar', 'Tidak Terdaftar', 'Belum Terisi'],
|
||||
series: farmerGroupData,
|
||||
colors: [pastelSemantic.success || '#6FD68F', pastelSemantic.warning || '#FFB46F', pastelSemantic.secondary || '#9EA6B0'],
|
||||
colors: farmerGroupColors,
|
||||
stroke: { width: 0 },
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
@@ -2155,15 +2151,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fontSize: '13px',
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: 600,
|
||||
colors: ['#fff']
|
||||
colors: farmerGroupColors.map(config.chartTextColor)
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
top: 1,
|
||||
left: 1,
|
||||
blur: 2,
|
||||
opacity: 0.45
|
||||
}
|
||||
dropShadow: { enabled: false }
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
@@ -2219,6 +2209,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const commoditySeries = @json($data['komoditas_utama']['series'] ?? []);
|
||||
const totalCommodityFarmers = commoditySeries.reduce((total, value) => total + Number(value), 0);
|
||||
|
||||
const commodityColors = [
|
||||
pastelSemantic.primary || '#9D8EF0',
|
||||
pastelSemantic.warning || '#FFB46F',
|
||||
pastelSemantic.success || '#6FD68F',
|
||||
pastelSemantic.info || '#5FC7D6',
|
||||
pastelSemantic.danger || '#F47C86',
|
||||
pastelSemantic.secondary || '#9EA6B0'
|
||||
];
|
||||
const commodityChartConfig = {
|
||||
chart: {
|
||||
height: 365,
|
||||
@@ -2237,14 +2235,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
labels: commodityLabels,
|
||||
series: commoditySeries.map(Number),
|
||||
colors: [
|
||||
pastelSemantic.primary || '#9D8EF0',
|
||||
pastelSemantic.warning || '#FFB46F',
|
||||
pastelSemantic.success || '#6FD68F',
|
||||
pastelSemantic.info || '#5FC7D6',
|
||||
pastelSemantic.danger || '#F47C86',
|
||||
pastelSemantic.secondary || '#9EA6B0'
|
||||
],
|
||||
colors: commodityColors,
|
||||
stroke: { width: 0 },
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
@@ -2260,15 +2251,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fontSize: '13px',
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: 600,
|
||||
colors: ['#fff']
|
||||
colors: commodityColors.map(config.chartTextColor)
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
top: 1,
|
||||
left: 1,
|
||||
blur: 2,
|
||||
opacity: 0.45
|
||||
}
|
||||
dropShadow: { enabled: false }
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
@@ -2293,7 +2278,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const percentage = totalCommodityFarmers > 0 ? ((value / totalCommodityFarmers) * 100).toFixed(1) : '0.0';
|
||||
const color = w.globals.colors[seriesIndex];
|
||||
return `
|
||||
<div style="background:${color}; color:${headingColor}; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
|
||||
<div style="background:${color}; color:${config.chartTextColor(color)}; padding:8px 12px; border-radius:5px; font-size:13px; font-weight:500; font-family:${fontFamily}; box-shadow:0 4px 12px rgba(0,0,0,.15);">
|
||||
${label}: <strong>${value} petani (${percentage}%)</strong>
|
||||
</div>
|
||||
`;
|
||||
@@ -2433,6 +2418,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const landOwnershipStatusSeries = (@json($data['status_kepemilikan_lahan']['series'] ?? [])).map(Number);
|
||||
const totalLandOwnershipStatusFarmers = landOwnershipStatusSeries.reduce((total, value) => total + value, 0);
|
||||
|
||||
const landOwnershipStatusColors = [
|
||||
pastelSemantic.success || '#6FD68F',
|
||||
pastelSemantic.warning || '#FFB46F',
|
||||
pastelSemantic.info || '#5FC7D6',
|
||||
pastelSemantic.secondary || '#9EA6B0'
|
||||
];
|
||||
const landOwnershipStatusChartConfig = {
|
||||
chart: {
|
||||
height: 365,
|
||||
@@ -2452,12 +2443,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
labels: landOwnershipStatusLabels,
|
||||
series: landOwnershipStatusSeries,
|
||||
colors: [
|
||||
pastelSemantic.success || '#6FD68F',
|
||||
pastelSemantic.warning || '#FFB46F',
|
||||
pastelSemantic.info || '#5FC7D6',
|
||||
pastelSemantic.secondary || '#9EA6B0'
|
||||
],
|
||||
colors: landOwnershipStatusColors,
|
||||
stroke: { width: 0 },
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
@@ -2473,15 +2459,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fontSize: '13px',
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: 600,
|
||||
colors: ['#fff']
|
||||
colors: landOwnershipStatusColors.map(config.chartTextColor)
|
||||
},
|
||||
dropShadow: {
|
||||
enabled: true,
|
||||
top: 1,
|
||||
left: 1,
|
||||
blur: 2,
|
||||
opacity: 0.45
|
||||
}
|
||||
dropShadow: { enabled: false }
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
@@ -2918,6 +2898,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
style: { colors: segmentPalette.map(config.chartTextColor) },
|
||||
dropShadow: { enabled: false },
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
|
||||
@@ -1251,13 +1251,13 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function produksiChartTooltip(color, label, value, unit = '', total = null, digits = 0) {
|
||||
function produksiChartTooltip(color, label, value, unit = '', total = null, digits = 0, textColor = headingColor) {
|
||||
const numericValue = Number(value || 0);
|
||||
const unitText = unit ? ` ${escapeHtml(unit)}` : '';
|
||||
const percentageText = total === null ? '' : ` (${chartPercentage(numericValue, total)}%)`;
|
||||
|
||||
return `
|
||||
<div class="produksi-apex-tooltip" style="background:${escapeHtml(color)}; color:${escapeHtml(headingColor)}; font-family:${fontFamily};">
|
||||
<div class="produksi-apex-tooltip" style="background:${escapeHtml(color)}; color:${escapeHtml(textColor)}; font-family:${fontFamily};">
|
||||
${escapeHtml(label)}: <strong>${formatNumber(numericValue, digits)}${unitText}${percentageText}</strong>
|
||||
</div>
|
||||
`;
|
||||
@@ -1636,6 +1636,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
stroke: { width: 0 },
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
dropShadow: { enabled: false },
|
||||
formatter: function (value) {
|
||||
return value.toFixed(0) + '%';
|
||||
},
|
||||
@@ -1643,7 +1644,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fontSize: '13px',
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: 600,
|
||||
colors: ['#fff'],
|
||||
colors: chartColors.map(config.chartTextColor),
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
@@ -1665,7 +1666,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const label = w.globals.labels[seriesIndex] || 'Data';
|
||||
const color = w.globals.colors?.[seriesIndex] || chartColors[seriesIndex % chartColors.length] || '#9D8EF0';
|
||||
|
||||
return produksiChartTooltip(color, label, value, options.unit || 'data', total);
|
||||
return produksiChartTooltip(color, label, value, options.unit || 'data', total, 0, config.chartTextColor(color));
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
@@ -1742,6 +1743,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
legend: { show: false },
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
dropShadow: { enabled: false },
|
||||
formatter: function (value) {
|
||||
return value >= 8 ? value.toFixed(0) + '%' : '';
|
||||
},
|
||||
@@ -1749,7 +1751,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
fontSize: '11px',
|
||||
fontFamily: fontFamily,
|
||||
fontWeight: 600,
|
||||
colors: ['#fff'],
|
||||
colors: colors.map(config.chartTextColor),
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
@@ -1758,7 +1760,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const label = w.globals.labels[seriesIndex] || 'Data';
|
||||
const color = w.globals.colors?.[seriesIndex] || colors[seriesIndex % colors.length] || '#9D8EF0';
|
||||
|
||||
return produksiChartTooltip(color, label, value, options.unit || 'data', total);
|
||||
return produksiChartTooltip(color, label, value, options.unit || 'data', total, 0, config.chartTextColor(color));
|
||||
},
|
||||
},
|
||||
plotOptions: { pie: { expandOnClick: true } },
|
||||
|
||||
Reference in New Issue
Block a user