update chart dashboard
This commit is contained in:
@@ -81,6 +81,29 @@ window.config = {
|
|||||||
enableMenuLocalStorage: true // Enable menu state with local storage support
|
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.assetsPath = document.documentElement.getAttribute('data-assets-path');
|
||||||
window.templateName = document.documentElement.getAttribute('data-template');
|
window.templateName = document.documentElement.getAttribute('data-template');
|
||||||
|
|
||||||
|
|||||||
@@ -2011,7 +2011,11 @@
|
|||||||
series: data.series,
|
series: data.series,
|
||||||
colors: colors,
|
colors: colors,
|
||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
dataLabels: { enabled: false },
|
dataLabels: {
|
||||||
|
enabled: false,
|
||||||
|
style: { colors: colors.map(config.chartTextColor) },
|
||||||
|
dropShadow: { enabled: false },
|
||||||
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: true,
|
show: true,
|
||||||
position: 'bottom',
|
position: 'bottom',
|
||||||
@@ -2051,7 +2055,7 @@
|
|||||||
<div
|
<div
|
||||||
style="
|
style="
|
||||||
background: ${color};
|
background: ${color};
|
||||||
color: #fff;
|
color: ${config.chartTextColor(color)};
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|||||||
@@ -1713,6 +1713,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const totalPetani = lakiLaki + perempuan;
|
const totalPetani = lakiLaki + perempuan;
|
||||||
|
|
||||||
if (genderChartEl) {
|
if (genderChartEl) {
|
||||||
|
const genderColors = [pastelSemantic.info || '#5FC7D6', pastelSemantic.pink || '#F47C86'];
|
||||||
const genderChartConfig = {
|
const genderChartConfig = {
|
||||||
chart: {
|
chart: {
|
||||||
height: 365,
|
height: 365,
|
||||||
@@ -1732,7 +1733,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
},
|
},
|
||||||
labels: ['Laki-laki', 'Perempuan'],
|
labels: ['Laki-laki', 'Perempuan'],
|
||||||
series: [lakiLaki, perempuan],
|
series: [lakiLaki, perempuan],
|
||||||
colors: [pastelSemantic.info || '#5FC7D6', pastelSemantic.pink || '#F47C86'],
|
colors: genderColors,
|
||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -1748,15 +1749,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
colors: ['#fff']
|
colors: genderColors.map(config.chartTextColor)
|
||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: { enabled: false }
|
||||||
enabled: true,
|
|
||||||
top: 1,
|
|
||||||
left: 1,
|
|
||||||
blur: 2,
|
|
||||||
opacity: 0.45
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: true,
|
show: true,
|
||||||
@@ -2120,6 +2115,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const farmerGroupFilters = ['terdaftar', 'tidak_terdaftar', 'belum_terisi'];
|
const farmerGroupFilters = ['terdaftar', 'tidak_terdaftar', 'belum_terisi'];
|
||||||
const totalFarmerGroup = farmerGroupData.reduce((total, value) => total + value, 0);
|
const totalFarmerGroup = farmerGroupData.reduce((total, value) => total + value, 0);
|
||||||
|
|
||||||
|
const farmerGroupColors = [pastelSemantic.success || '#6FD68F', pastelSemantic.warning || '#FFB46F', pastelSemantic.secondary || '#9EA6B0'];
|
||||||
const farmerGroupChartConfig = {
|
const farmerGroupChartConfig = {
|
||||||
chart: {
|
chart: {
|
||||||
height: 365,
|
height: 365,
|
||||||
@@ -2139,7 +2135,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
},
|
},
|
||||||
labels: ['Terdaftar', 'Tidak Terdaftar', 'Belum Terisi'],
|
labels: ['Terdaftar', 'Tidak Terdaftar', 'Belum Terisi'],
|
||||||
series: farmerGroupData,
|
series: farmerGroupData,
|
||||||
colors: [pastelSemantic.success || '#6FD68F', pastelSemantic.warning || '#FFB46F', pastelSemantic.secondary || '#9EA6B0'],
|
colors: farmerGroupColors,
|
||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -2155,15 +2151,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
colors: ['#fff']
|
colors: farmerGroupColors.map(config.chartTextColor)
|
||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: { enabled: false }
|
||||||
enabled: true,
|
|
||||||
top: 1,
|
|
||||||
left: 1,
|
|
||||||
blur: 2,
|
|
||||||
opacity: 0.45
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: true,
|
show: true,
|
||||||
@@ -2219,6 +2209,14 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const commoditySeries = @json($data['komoditas_utama']['series'] ?? []);
|
const commoditySeries = @json($data['komoditas_utama']['series'] ?? []);
|
||||||
const totalCommodityFarmers = commoditySeries.reduce((total, value) => total + Number(value), 0);
|
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 = {
|
const commodityChartConfig = {
|
||||||
chart: {
|
chart: {
|
||||||
height: 365,
|
height: 365,
|
||||||
@@ -2237,14 +2235,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
},
|
},
|
||||||
labels: commodityLabels,
|
labels: commodityLabels,
|
||||||
series: commoditySeries.map(Number),
|
series: commoditySeries.map(Number),
|
||||||
colors: [
|
colors: commodityColors,
|
||||||
pastelSemantic.primary || '#9D8EF0',
|
|
||||||
pastelSemantic.warning || '#FFB46F',
|
|
||||||
pastelSemantic.success || '#6FD68F',
|
|
||||||
pastelSemantic.info || '#5FC7D6',
|
|
||||||
pastelSemantic.danger || '#F47C86',
|
|
||||||
pastelSemantic.secondary || '#9EA6B0'
|
|
||||||
],
|
|
||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -2260,15 +2251,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
colors: ['#fff']
|
colors: commodityColors.map(config.chartTextColor)
|
||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: { enabled: false }
|
||||||
enabled: true,
|
|
||||||
top: 1,
|
|
||||||
left: 1,
|
|
||||||
blur: 2,
|
|
||||||
opacity: 0.45
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: true,
|
show: true,
|
||||||
@@ -2293,7 +2278,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const percentage = totalCommodityFarmers > 0 ? ((value / totalCommodityFarmers) * 100).toFixed(1) : '0.0';
|
const percentage = totalCommodityFarmers > 0 ? ((value / totalCommodityFarmers) * 100).toFixed(1) : '0.0';
|
||||||
const color = w.globals.colors[seriesIndex];
|
const color = w.globals.colors[seriesIndex];
|
||||||
return `
|
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>
|
${label}: <strong>${value} petani (${percentage}%)</strong>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -2433,6 +2418,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const landOwnershipStatusSeries = (@json($data['status_kepemilikan_lahan']['series'] ?? [])).map(Number);
|
const landOwnershipStatusSeries = (@json($data['status_kepemilikan_lahan']['series'] ?? [])).map(Number);
|
||||||
const totalLandOwnershipStatusFarmers = landOwnershipStatusSeries.reduce((total, value) => total + value, 0);
|
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 = {
|
const landOwnershipStatusChartConfig = {
|
||||||
chart: {
|
chart: {
|
||||||
height: 365,
|
height: 365,
|
||||||
@@ -2452,12 +2443,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
},
|
},
|
||||||
labels: landOwnershipStatusLabels,
|
labels: landOwnershipStatusLabels,
|
||||||
series: landOwnershipStatusSeries,
|
series: landOwnershipStatusSeries,
|
||||||
colors: [
|
colors: landOwnershipStatusColors,
|
||||||
pastelSemantic.success || '#6FD68F',
|
|
||||||
pastelSemantic.warning || '#FFB46F',
|
|
||||||
pastelSemantic.info || '#5FC7D6',
|
|
||||||
pastelSemantic.secondary || '#9EA6B0'
|
|
||||||
],
|
|
||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -2473,15 +2459,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
colors: ['#fff']
|
colors: landOwnershipStatusColors.map(config.chartTextColor)
|
||||||
},
|
},
|
||||||
dropShadow: {
|
dropShadow: { enabled: false }
|
||||||
enabled: true,
|
|
||||||
top: 1,
|
|
||||||
left: 1,
|
|
||||||
blur: 2,
|
|
||||||
opacity: 0.45
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: true,
|
show: true,
|
||||||
@@ -2918,6 +2898,8 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
},
|
},
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
style: { colors: segmentPalette.map(config.chartTextColor) },
|
||||||
|
dropShadow: { enabled: false },
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
show: false,
|
show: false,
|
||||||
|
|||||||
@@ -1251,13 +1251,13 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
}, 0);
|
}, 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 numericValue = Number(value || 0);
|
||||||
const unitText = unit ? ` ${escapeHtml(unit)}` : '';
|
const unitText = unit ? ` ${escapeHtml(unit)}` : '';
|
||||||
const percentageText = total === null ? '' : ` (${chartPercentage(numericValue, total)}%)`;
|
const percentageText = total === null ? '' : ` (${chartPercentage(numericValue, total)}%)`;
|
||||||
|
|
||||||
return `
|
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>
|
${escapeHtml(label)}: <strong>${formatNumber(numericValue, digits)}${unitText}${percentageText}</strong>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -1636,6 +1636,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
stroke: { width: 0 },
|
stroke: { width: 0 },
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
dropShadow: { enabled: false },
|
||||||
formatter: function (value) {
|
formatter: function (value) {
|
||||||
return value.toFixed(0) + '%';
|
return value.toFixed(0) + '%';
|
||||||
},
|
},
|
||||||
@@ -1643,7 +1644,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fontSize: '13px',
|
fontSize: '13px',
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
colors: ['#fff'],
|
colors: chartColors.map(config.chartTextColor),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -1665,7 +1666,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const label = w.globals.labels[seriesIndex] || 'Data';
|
const label = w.globals.labels[seriesIndex] || 'Data';
|
||||||
const color = w.globals.colors?.[seriesIndex] || chartColors[seriesIndex % chartColors.length] || '#9D8EF0';
|
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: {
|
plotOptions: {
|
||||||
@@ -1742,6 +1743,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
legend: { show: false },
|
legend: { show: false },
|
||||||
dataLabels: {
|
dataLabels: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
dropShadow: { enabled: false },
|
||||||
formatter: function (value) {
|
formatter: function (value) {
|
||||||
return value >= 8 ? value.toFixed(0) + '%' : '';
|
return value >= 8 ? value.toFixed(0) + '%' : '';
|
||||||
},
|
},
|
||||||
@@ -1749,7 +1751,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
fontSize: '11px',
|
fontSize: '11px',
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
colors: ['#fff'],
|
colors: colors.map(config.chartTextColor),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@@ -1758,7 +1760,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const label = w.globals.labels[seriesIndex] || 'Data';
|
const label = w.globals.labels[seriesIndex] || 'Data';
|
||||||
const color = w.globals.colors?.[seriesIndex] || colors[seriesIndex % colors.length] || '#9D8EF0';
|
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 } },
|
plotOptions: { pie: { expandOnClick: true } },
|
||||||
|
|||||||
Reference in New Issue
Block a user