Как решить проблему с пропорциями на chartJS?
Проблема заключается в том, что при подключении библиотеки chartJs и создании столбцов с нужными показателями, значения показываются не пропорционально. Т.е например, как в прикреплённом фото:
Тут очевидно, реальный заработок должен занимать 80% от возможного, но он почему-то занимает менее 50%
Код привёл ниже, кто знает как, помогите пожалуйста решить вопрос.
const ctx = document.querySelector('#earningsChart').getContext('2d');
let earningsChart;
let isNightMode = localStorage.getItem('nightMode');
const dataSets = {
months: {
labels: ['Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь', 'Январь', 'Февраль', 'Март', 'Апрель', 'Май'],
data: [10, 80, 0, 0, 0, 0, 0, 0, 0]
},
days: {
labels: ['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье'],
data: [0, 0, 0, 0, 0, 0, 0]
},
years: {
labels: ['2020', '2021', '2022', '2023', '2024'],
data: [0, 0, 0, 0, 0]
}
};
function updateChart(timePeriod, isNightmode ) {
const { labels, data } = dataSets[timePeriod];
if (earningsChart) {
earningsChart.destroy();
}
if (isNightmode) {
colors = {
'bg' : '#B5F5BF',
'bg1' : '#383535',
'text-color' :'#fff',
}
} else {
colors = {
'bg' : '#1D4ECC',
'bg1' : 'rgba(54, 162, 235, 0.1)',
'text-color': '#000'
}
}
earningsChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Реальный',
barPercentage: 0.6, // Уменьшает ширину столбцов
data: data,
backgroundColor:colors['bg'],
borderColor: 'rgba(54, 162, 235, 1)',
stack: 'combined',
borderRadius: 10 // Закругленные края столбцов
}, {
label: 'Возможный',
barPercentage: 0.6, // Уменьшает ширину столбцов
data: data.map(d => 100), // Генерация случайных значений для демонстрации
backgroundColor: colors['bg1'],
borderColor: 'rgba(255, 206, 86, 0.1)',
stack: 'combined',
borderRadius: 10 // Закругленные края столбцов
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
left: 10,
right: 10,
top: 10,
bottom: 10
}
},
plugins: {
legend: {
display: false, // Убрать легенду
},
tooltip: {
enabled: false,
external: function(context) {
let tooltipEl = document.getElementById('chartjs-tooltip');
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.id = 'chartjs-tooltip';
tooltipEl.innerHTML = '<table></table>';
document.body.appendChild(tooltipEl);
}
const tooltipModel = context.tooltip;
if (tooltipModel.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
if (tooltipModel.body) {
const titleLines = tooltipModel.title || [];
const bodyLines = tooltipModel.body.map(item => item.lines);
const header = titleLines.join(' ');
document.getElementById('chartjs-tooltip-header').innerText = header;
const body = bodyLines[0][0].split(':');
document.getElementById('chartjs-tooltip-body').innerText = body[0];
const value = tooltipModel.dataPoints[0].parsed.y;
document.getElementById('chartjs-tooltip-value').innerText = `${Math.round(value)}₽`;
}
const position = context.chart.canvas.getBoundingClientRect();
tooltipEl.style.opacity = 1;
tooltipEl.style.left = tooltipModel.caretX + '' + 'px';
tooltipEl.style.top = tooltipModel.caretY + 100 + 'px';
tooltipEl.style.transform = 'translateX(-50%)';
}
},
},
scales: {
x: {
border: {
display: false,
},
stacked: true,
grid: {
color: '#fff',
display: false
},
ticks: {
font: {
size: 10,
weight: 'normal',
family: 'Arvo'
},
color: colors['text-color']
},
},
y: {
border: {
display: false,
},
stacked: true,
beginAtZero: true,
grid: {
display: false
},
ticks: {
display: false,
font: {
size: 10,
weight: 'bold'
},
color: colors['text-color']
}
}
},
barSpacing: 20 // Расстояние между столбцами
},
});
}
// Initialize the chart with 'months' data
if (isNightMode == 'true'){
updateChart('months', true);
} else {
updateChart('months', false);
}
switcher = document.querySelector('.switcher');
switcher.addEventListener('click', ()=>{
isNightMode = document.body.classList.contains('night__mode');
if (isNightMode) {
updateChart('months', !isNightMode);
document.querySelector('.drop-toggle').innerHTML = 'По месяцам';
}
else {
updateChart('months', !isNightMode);
document.querySelector('.drop-toggle').innerHTML = 'По месяцам';
}
})
buttons = document.querySelectorAll('.btn-bar-chart');
container = document.querySelector('.drop-toggle')
menu = document.querySelector('.drop-menu')
buttons.forEach(btn =>{
btn.addEventListener('click', ()=>{
if (btn.dataset.period == 'days') {
container.innerHTML = 'По дням'
menu.style.display = 'none'
}
else if (btn.dataset.period == 'months') {
container.innerHTML = 'По месяцам'
menu.style.display = 'none'
}
else if (btn.dataset.period == 'years') {
container.innerHTML = 'По годам'
menu.style.display = 'none'
}
})
})
Ответы (1 шт):
Исправьте данные для возможного заработка: Вместо использования data.map(d => 100), вы можете динамически указывать возможный заработок для каждого месяца.
Настройте ось y: Добавьте больше контроля над минимальным и максимальным значением оси, чтобы они точно отражали пропорции между реальным и возможным заработком.
Используйте categoryPercentage и barPercentage: Для того, чтобы изменить относительные размеры столбцов.
function updateChart(timePeriod, isNightmode ) {
const { labels, data } = dataSets[timePeriod];
if (earningsChart) {
earningsChart.destroy();
}
if (isNightmode) {
colors = {
'bg' : '#B5F5BF',
'bg1' : '#383535',
'text-color' :'#fff',
}
} else {
colors = {
'bg' : '#1D4ECC',
'bg1' : 'rgba(54, 162, 235, 0.1)',
'text-color': '#000'
}
}
earningsChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Реальный заработок',
barPercentage: 0.6,
categoryPercentage: 0.8, // Изменяем относительную ширину столбцов
data: data,
backgroundColor: colors['bg'],
borderColor: 'rgba(54, 162, 235, 1)',
stack: 'combined',
borderRadius: 10
}, {
label: 'Возможный заработок',
barPercentage: 0.6,
categoryPercentage: 0.8, // Изменяем относительную ширину столбцов
data: data.map(d => d * 1.25), // Делаем возможный заработок на 25% больше для демонстрации
backgroundColor: colors['bg1'],
borderColor: 'rgba(255, 206, 86, 0.1)',
stack: 'combined',
borderRadius: 10
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
left: 10,
right: 10,
top: 10,
bottom: 10
}
},
plugins: {
legend: {
display: true, // Показать легенду
},
tooltip: {
enabled: true,
},
},
scales: {
x: {
stacked: true,
grid: {
display: false,
},
ticks: {
color: colors['text-color'],
},
},
y: {
beginAtZero: true, // Начало с нуля
max: 150, // Устанавливаем максимальное значение на оси Y
grid: {
display: true,
},
ticks: {
color: colors['text-color'],
},
}
},
},
});
}