diff --git a/script.js b/script.js index f02e797..031d26b 100644 --- a/script.js +++ b/script.js @@ -4,12 +4,12 @@ const headerMap = { 'фио': 'name', 'ф.и.о': 'name', 'сотрудник': 'name', 'employee': 'name', 'имя': 'name', 'дивизион': 'division', 'подразделение': 'division', 'отдел': 'division', 'division': 'division', 'department': 'division', 'курс': 'course', 'обучение': 'course', 'training': 'course', 'программа': 'course', - 'тренинг': 'course', 'тренинг/курс': 'course', 'название тренинга': 'course', 'название курса': 'course', - 'what': 'course', 'название': 'course', 'тема': 'course', 'дисциплина': 'course', 'module': 'course', 'модуль': 'course', + 'тренинг': 'course', 'название тренинга': 'course', 'название курса': 'course', + 'название': 'course', 'тема': 'course', 'дисциплина': 'course', 'модуль': 'course', 'статус': 'status', 'status': 'status', 'состояние': 'status', - 'оценка': 'score', 'ball': 'score', 'score': 'score', 'рейтинг': 'score', 'балл': 'score', - 'тренер': 'trainer', 'trainer': 'coach', 'преподаватель': 'trainer', 'coach': 'trainer', - 'дата': 'date', 'date': 'date', 'дата прохождения': 'date' + 'оценка': 'score', 'балл': 'score', 'баллы': 'score', 'рейтинг': 'score', + 'тренер': 'trainer', 'преподаватель': 'trainer', 'coach': 'trainer', + 'дата': 'date', 'дата прохождения': 'date' }; document.getElementById('excelFile').addEventListener('change', function(e) { @@ -18,124 +18,130 @@ document.getElementById('excelFile').addEventListener('change', function(e) { const reader = new FileReader(); reader.onload = function(event) { - const data = new Uint8Array(event.target.result); - const workbook = XLSX.read(data, { type: 'array' }); - const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; - const jsonData = XLSX.utils.sheet_to_json(firstSheet, { defval: '' }); + try { + const data = new Uint8Array(event.target.result); + const workbook = XLSX.read(data, { type: 'array' }); + const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; + const jsonData = XLSX.utils.sheet_to_json(firstSheet, { defval: '' }); - if (jsonData.length === 0) { - alert('Файл пуст или имеет неверный формат'); - return; + if (jsonData.length === 0) { + alert('Файл пуст или имеет неверный формат'); + return; + } + + var sampleRow = jsonData[0]; + var rawCols = Object.keys(sampleRow); + var normalized = normalizeHeaders([sampleRow])[0]; + var debugHtml = 'Оригинальные столбцы: ' + rawCols.join(', ') + '

'; + rawCols.forEach(function(k) { + var nk = k.toLowerCase().trim(); + var mapped = headerMap[nk] || nk; + var val = normalized[mapped] || '(пусто)'; + debugHtml += '' + k + ' → ' + mapped + ' = "' + val + '"
'; + }); + + var debugEl = document.getElementById('debug'); + var debugColsEl = document.getElementById('debugColumns'); + if (debugEl && debugColsEl) { + debugEl.classList.remove('hidden'); + debugColsEl.innerHTML = debugHtml; + } + + processAndRender(jsonData); + } catch (err) { + alert('Ошибка чтения файла: ' + err.message); + console.error(err); } - - const sampleRow = jsonData[0] || {}; - const rawCols = Object.keys(sampleRow); - const normalized = normalizeHeaders([sampleRow])[0]; - const mapping = rawCols.map(k => { - const nk = k.toLowerCase().trim(); - const mapped = headerMap[nk] || nk; - const val = normalized[mapped] || '(пусто)'; - return `${k} → ${mapped} = "${val}"`; - }).join('
'); - - document.getElementById('debug').classList.remove('hidden'); - document.getElementById('debugColumns').innerHTML = - `Оригинальные столбцы: ${rawCols.join(', ')}

${mapping}`; - - processAndRender(jsonData); }; reader.readAsArrayBuffer(file); }); function normalizeHeaders(rows) { - return rows.map(row => { - const normalized = {}; - for (const key in row) { - const cleanKey = key.toLowerCase().trim(); - const mapped = headerMap[cleanKey] || cleanKey; + return rows.map(function(row) { + var normalized = {}; + for (var key in row) { + var cleanKey = key.toLowerCase().trim(); + var mapped = headerMap[cleanKey] || cleanKey; normalized[mapped] = row[key]; } return normalized; }); } +function isCompleted(status) { + var s = (status || '').toLowerCase(); + return s.includes('завершен') || s.includes('прошёл') || s.includes('прошел') || s === 'completed' || s.includes('ок') || s.includes('пройден'); +} + function processAndRender(rawData) { - const data = normalizeHeaders(rawData); + var data = normalizeHeaders(rawData); document.querySelector('.upload-section').classList.add('hidden'); document.getElementById('dashboard').classList.remove('hidden'); - const totalEmployees = new Set(data.map(r => r.name)).size; - const completed = data.filter(r => { - const s = (r.status || '').toLowerCase(); - return s.includes('завершен') || s.includes('прошёл') || s.includes('прошел') || s === 'completed' || s.includes('ок'); - }); - const completedEmployees = new Set(completed.map(r => r.name)).size; - const rate = totalEmployees ? Math.round(completedEmployees / totalEmployees * 100) : 0; + var allNames = new Set(); + var completedNames = new Set(); + var scores = []; + var trainingStats = {}; + var divisionStats = {}; + var trainerLoad = {}; - const scores = data.map(r => parseFloat(r.score)).filter(s => !isNaN(s) && s > 0); - const avgScore = scores.length ? (scores.reduce((a, b) => a + b, 0) / scores.length).toFixed(1) : '—'; + data.forEach(function(r) { + allNames.add(r.name); + if (isCompleted(r.status)) completedNames.add(r.name); + + var sc = parseFloat(r.score); + if (!isNaN(sc) && sc > 0) scores.push(sc); + + var course = r.course || 'Без названия'; + if (!trainingStats[course]) trainingStats[course] = { completed: new Set(), all: new Set(), scores: [], trainers: new Set(), divisions: {} }; + trainingStats[course].all.add(r.name); + if (isCompleted(r.status)) trainingStats[course].completed.add(r.name); + if (!isNaN(sc) && sc > 0) trainingStats[course].scores.push(sc); + if (r.trainer) trainingStats[course].trainers.add(r.trainer); + var div = r.division || 'Без дивизиона'; + if (!trainingStats[course].divisions[div]) trainingStats[course].divisions[div] = { total: new Set(), completed: new Set() }; + trainingStats[course].divisions[div].total.add(r.name); + if (isCompleted(r.status)) trainingStats[course].divisions[div].completed.add(r.name); + + if (!divisionStats[div]) divisionStats[div] = { total: new Set(), completed: new Set() }; + divisionStats[div].total.add(r.name); + if (isCompleted(r.status)) divisionStats[div].completed.add(r.name); + + var t = r.trainer || 'Не указан'; + if (!trainerLoad[t]) trainerLoad[t] = { count: 0, scores: [] }; + trainerLoad[t].count++; + if (!isNaN(sc) && sc > 0) trainerLoad[t].scores.push(sc); + }); + + var totalEmployees = allNames.size; + var completedCount = completedNames.size; + var rate = totalEmployees ? Math.round(completedCount / totalEmployees * 100) : 0; + var avgScore = scores.length ? (scores.reduce(function(a, b) { return a + b; }, 0) / scores.length).toFixed(1) : '—'; document.getElementById('totalEmployees').textContent = totalEmployees; - document.getElementById('completedCount').textContent = completedEmployees; + document.getElementById('completedCount').textContent = completedCount; document.getElementById('completionRate').textContent = rate + '%'; document.getElementById('avgScore').textContent = avgScore; - const trainingStats = {}; - data.forEach(r => { - const course = r.course || 'Без названия'; - if (!trainingStats[course]) trainingStats[course] = { completed: new Set(), all: new Set(), scores: [], trainers: new Set(), divisions: {} }; - trainingStats[course].all.add(r.name); - const s = (r.status || '').toLowerCase(); - const isCompleted = s.includes('завершен') || s.includes('прошёл') || s.includes('прошел') || s === 'completed' || s.includes('ок'); - if (isCompleted) { - trainingStats[course].completed.add(r.name); - } - const score = parseFloat(r.score); - if (!isNaN(score) && score > 0) trainingStats[course].scores.push(score); - if (r.trainer) trainingStats[course].trainers.add(r.trainer); - const div = r.division || 'Без дивизиона'; - if (!trainingStats[course].divisions[div]) trainingStats[course].divisions[div] = { total: new Set(), completed: new Set() }; - trainingStats[course].divisions[div].total.add(r.name); - if (isCompleted) trainingStats[course].divisions[div].completed.add(r.name); - }); - - const trainingLabels = Object.keys(trainingStats); - const trainingCompletedCounts = trainingLabels.map(t => trainingStats[t].completed.size); - const trainingTotalCounts = trainingLabels.map(t => trainingStats[t].all.size); + var trainingLabels = Object.keys(trainingStats); + var trainingCompletedCounts = trainingLabels.map(function(t) { return trainingStats[t].completed.size; }); + var trainingTotalCounts = trainingLabels.map(function(t) { return trainingStats[t].all.size; }); renderChart('trainingChart', 'bar', { labels: trainingLabels, datasets: [ - { - label: 'Всего записей', - data: trainingTotalCounts, - backgroundColor: 'rgba(33, 150, 243, 0.4)', - borderColor: '#2196F3', - borderWidth: 1 - }, - { - label: 'Прошли', - data: trainingCompletedCounts, - backgroundColor: 'rgba(76, 175, 80, 0.7)', - borderColor: '#4caf50', - borderWidth: 1 - } + { label: 'Всего записей', data: trainingTotalCounts, backgroundColor: 'rgba(33,150,243,0.4)', borderColor: '#2196F3', borderWidth: 1 }, + { label: 'Прошли', data: trainingCompletedCounts, backgroundColor: 'rgba(76,175,80,0.7)', borderColor: '#4caf50', borderWidth: 1 } ] - }, { - indexAxis: 'y', - scales: { - x: { beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, - y: { ticks: { color: '#e0e0e0', font: { size: 11 } }, grid: { color: '#1e2d3d' } } - } - }); + }, { indexAxis: 'y', scales: { x: { beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, y: { ticks: { color: '#e0e0e0', font: { size: 11 } }, grid: { color: '#1e2d3d' } } } }); - const allDivisions = [...new Set(data.map(r => r.division || 'Без дивизиона'))]; - const trainingByDivDatasets = allDivisions.map((div, i) => { - const colors = ['#2196F3', '#4caf50', '#ff9800', '#9c27b0', '#00bcd4', '#ff5722', '#8bc34a', '#e91e63']; + var allDivisions = Object.keys(divisionStats); + var colors = ['#2196F3', '#4caf50', '#ff9800', '#9c27b0', '#00bcd4', '#ff5722', '#8bc34a', '#e91e63']; + var trainingByDivDatasets = allDivisions.map(function(div, i) { return { label: div, - data: trainingLabels.map(t => trainingStats[t].divisions[div] ? trainingStats[t].divisions[div].completed.size : 0), + data: trainingLabels.map(function(t) { return trainingStats[t].divisions[div] ? trainingStats[t].divisions[div].completed.size : 0; }), backgroundColor: colors[i % colors.length] + 'aa', borderColor: colors[i % colors.length], borderWidth: 1 @@ -145,230 +151,91 @@ function processAndRender(rawData) { renderChart('trainingByDivisionChart', 'bar', { labels: trainingLabels, datasets: trainingByDivDatasets - }, { - scales: { - x: { stacked: true, ticks: { color: '#90a4ae', maxRotation: 45 }, grid: { color: '#1e2d3d' } }, - y: { stacked: true, beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } } - } - }); - - const divisionStats = {}; - data.forEach(r => { - const div = r.division || 'Без дивизиона'; - if (!divisionStats[div]) divisionStats[div] = { total: new Set(), completed: new Set() }; - divisionStats[div].total.add(r.name); - const s = (r.status || '').toLowerCase(); - if (s.includes('завершен') || s.includes('прошёл') || s.includes('прошел') || s === 'completed' || s.includes('ок')) { - divisionStats[div].completed.add(r.name); - } - }); + }, { scales: { x: { stacked: true, ticks: { color: '#90a4ae', maxRotation: 45 }, grid: { color: '#1e2d3d' } }, y: { stacked: true, beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } } } }); renderChart('divisionChart', 'bar', { labels: Object.keys(divisionStats), datasets: [ - { - label: 'Всего', - data: Object.values(divisionStats).map(d => d.total.size), - backgroundColor: 'rgba(33, 150, 243, 0.6)', - borderColor: '#2196F3', - borderWidth: 1 - }, - { - label: 'Прошли', - data: Object.values(divisionStats).map(d => d.completed.size), - backgroundColor: 'rgba(76, 175, 80, 0.6)', - borderColor: '#4caf50', - borderWidth: 1 - } + { label: 'Всего', data: Object.values(divisionStats).map(function(d) { return d.total.size; }), backgroundColor: 'rgba(33,150,243,0.6)', borderColor: '#2196F3', borderWidth: 1 }, + { label: 'Прошли', data: Object.values(divisionStats).map(function(d) { return d.completed.size; }), backgroundColor: 'rgba(76,175,80,0.6)', borderColor: '#4caf50', borderWidth: 1 } ] }); - const trainerLoad = {}; - data.forEach(r => { - const t = r.trainer || 'Не указан'; - if (!trainerLoad[t]) trainerLoad[t] = { count: 0, scores: [] }; - trainerLoad[t].count++; - const s = parseFloat(r.score); - if (!isNaN(s) && s > 0) trainerLoad[t].scores.push(s); - }); - - const trainerLabels = Object.keys(trainerLoad); - const trainerCounts = trainerLabels.map(t => trainerLoad[t].count); - const trainerAvg = trainerLabels.map(t => { - const sc = trainerLoad[t].scores; - return sc.length ? (sc.reduce((a, b) => a + b, 0) / sc.length).toFixed(1) : 0; - }); - + var trainerLabels = Object.keys(trainerLoad); renderChart('trainerChart', 'bar', { labels: trainerLabels, datasets: [ - { - label: 'Занятий', - data: trainerCounts, - backgroundColor: 'rgba(255, 152, 0, 0.6)', - borderColor: '#ff9800', - borderWidth: 1 - }, - { - label: 'Средняя оценка', - data: trainerAvg, - backgroundColor: 'rgba(156, 39, 176, 0.6)', - borderColor: '#9c27b0', - borderWidth: 1, - yAxisID: 'y1' - } + { label: 'Занятий', data: trainerLabels.map(function(t) { return trainerLoad[t].count; }), backgroundColor: 'rgba(255,152,0,0.6)', borderColor: '#ff9800', borderWidth: 1 }, + { label: 'Средняя оценка', data: trainerLabels.map(function(t) { var sc = trainerLoad[t].scores; return sc.length ? (sc.reduce(function(a, b) { return a + b; }, 0) / sc.length).toFixed(1) : 0; }), backgroundColor: 'rgba(156,39,176,0.6)', borderColor: '#9c27b0', borderWidth: 1, yAxisID: 'y1' } ] - }, { - scales: { - y: { beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, - y1: { position: 'right', beginAtZero: true, max: 5, ticks: { color: '#90a4ae' }, grid: { display: false } }, - x: { ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } } - } - }); - - const scoreDist = { '5': 0, '4': 0, '3': 0, '2': 0, '1': 0 }; - scores.forEach(s => { - const rounded = Math.round(s); - if (scoreDist[String(rounded)] !== undefined) scoreDist[String(rounded)]++; - }); + }, { scales: { y: { beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, y1: { position: 'right', beginAtZero: true, max: 5, ticks: { color: '#90a4ae' }, grid: { display: false } }, x: { ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } } } }); + var scoreDist = { '5': 0, '4': 0, '3': 0, '2': 0, '1': 0 }; + scores.forEach(function(s) { var r = Math.round(s); if (scoreDist[String(r)] !== undefined) scoreDist[String(r)]++; }); renderChart('scoreChart', 'doughnut', { - labels: Object.keys(scoreDist).map(k => 'Оценка ' + k), - datasets: [{ - data: Object.values(scoreDist), - backgroundColor: ['#4caf50', '#8bc34a', '#ff9800', '#ff5722', '#f44336'], - borderWidth: 0 - }] - }); - - const statusCounts = {}; - data.forEach(r => { - const s = (r.status || 'Неизвестно').trim(); - statusCounts[s] = (statusCounts[s] || 0) + 1; + labels: Object.keys(scoreDist).map(function(k) { return 'Оценка ' + k; }), + datasets: [{ data: Object.values(scoreDist), backgroundColor: ['#4caf50', '#8bc34a', '#ff9800', '#ff5722', '#f44336'], borderWidth: 0 }] }); + var statusCounts = {}; + data.forEach(function(r) { var s = (r.status || 'Неизвестно').trim(); statusCounts[s] = (statusCounts[s] || 0) + 1; }); renderChart('statusChart', 'pie', { labels: Object.keys(statusCounts), - datasets: [{ - data: Object.values(statusCounts), - backgroundColor: ['#4caf50', '#ff9800', '#f44336', '#2196F3', '#9c27b0', '#00bcd4'], - borderWidth: 0 - }] - }); - - const trainingAvgScores = trainingLabels.map(t => { - const sc = trainingStats[t].scores; - return sc.length ? (sc.reduce((a, b) => a + b, 0) / sc.length).toFixed(1) : 0; + datasets: [{ data: Object.values(statusCounts), backgroundColor: ['#4caf50', '#ff9800', '#f44336', '#2196F3', '#9c27b0', '#00bcd4'], borderWidth: 0 }] }); + var trainingAvgScores = trainingLabels.map(function(t) { var sc = trainingStats[t].scores; return sc.length ? (sc.reduce(function(a, b) { return a + b; }, 0) / sc.length).toFixed(1) : 0; }); renderChart('trainingScoreChart', 'bar', { labels: trainingLabels, - datasets: [{ - label: 'Средняя оценка', - data: trainingAvgScores, - backgroundColor: trainingAvgScores.map(v => v >= 4 ? 'rgba(76,175,80,0.7)' : v >= 3 ? 'rgba(255,152,0,0.7)' : 'rgba(244,67,54,0.7)'), - borderColor: trainingAvgScores.map(v => v >= 4 ? '#4caf50' : v >= 3 ? '#ff9800' : '#f44336'), - borderWidth: 1 - }] - }, { - scales: { - y: { beginAtZero: true, max: 5, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, - x: { ticks: { color: '#e0e0e0', maxRotation: 45 }, grid: { color: '#1e2d3d' } } - } - }); + datasets: [{ label: 'Средняя оценка', data: trainingAvgScores, backgroundColor: trainingAvgScores.map(function(v) { return v >= 4 ? 'rgba(76,175,80,0.7)' : v >= 3 ? 'rgba(255,152,0,0.7)' : 'rgba(244,67,54,0.7)'; }), borderColor: trainingAvgScores.map(function(v) { return v >= 4 ? '#4caf50' : v >= 3 ? '#ff9800' : '#f44336'; }), borderWidth: 1 }] + }, { scales: { y: { beginAtZero: true, max: 5, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, x: { ticks: { color: '#e0e0e0', maxRotation: 45 }, grid: { color: '#1e2d3d' } } } }); - const trainingDetailBody = document.querySelector('#trainingDetailTable tbody'); - trainingDetailBody.innerHTML = trainingLabels.map(t => { - const st = trainingStats[t]; - const total = st.all.size; - const done = st.completed.size; - const pct = total ? Math.round(done / total * 100) : 0; - const avg = st.scores.length ? (st.scores.reduce((a, b) => a + b, 0) / st.scores.length).toFixed(1) : '—'; - const trainers = [...st.trainers].join(', ') || '—'; - return ` - ${t} - ${done} - ${total - done} - ${pct}% - ${avg} - ${trainers} - `; + var trainingDetailBody = document.querySelector('#trainingDetailTable tbody'); + trainingDetailBody.innerHTML = trainingLabels.map(function(t) { + var st = trainingStats[t]; + var total = st.all.size; + var done = st.completed.size; + var pct = total ? Math.round(done / total * 100) : 0; + var avg = st.scores.length ? (st.scores.reduce(function(a, b) { return a + b; }, 0) / st.scores.length).toFixed(1) : '—'; + var trainers = Array.from(st.trainers).join(', ') || '—'; + return '' + t + '' + done + '' + (total - done) + '' + pct + '%' + avg + '' + trainers + ''; }).join(''); - const coursesPerPerson = {}; - data.forEach(r => { + var coursesPerPerson = {}; + data.forEach(function(r) { if (!coursesPerPerson[r.name]) coursesPerPerson[r.name] = { division: r.division || '', courses: new Set() }; if (r.course) coursesPerPerson[r.name].courses.add(r.course); }); - - const champions = Object.entries(coursesPerPerson) - .map(([name, d]) => ({ name, division: d.division, count: d.courses.size })) - .sort((a, b) => b.count - a.count) + var champions = Object.entries(coursesPerPerson) + .map(function(e) { return { name: e[0], division: e[1].division, count: e[1].courses.size }; }) + .sort(function(a, b) { return b.count - a.count; }) .slice(0, 10); + document.querySelector('#championsTable tbody').innerHTML = champions.map(function(c) { + return '' + c.name + '' + c.division + '' + c.count + ''; + }).join(''); - const championsBody = document.querySelector('#championsTable tbody'); - championsBody.innerHTML = champions.map(c => - `${c.name}${c.division}${c.count}` - ).join(''); + var noTraining = Array.from(allNames).filter(function(n) { return !completedNames.has(n); }); + var noTrainingDivs = {}; + data.forEach(function(r) { if (noTraining.indexOf(r.name) !== -1) noTrainingDivs[r.name] = r.division || ''; }); + document.querySelector('#noTrainingTable tbody').innerHTML = noTraining.slice(0, 20).map(function(n) { + return '' + n + '' + (noTrainingDivs[n] || '') + ''; + }).join(''); - const completedNames = new Set(completed.map(r => r.name)); - const allNames = new Set(data.map(r => r.name)); - const noTraining = [...allNames].filter(n => !completedNames.has(n)); - const noTrainingDivs = {}; - data.forEach(r => { - if (noTraining.includes(r.name)) noTrainingDivs[r.name] = r.division || ''; - }); - - const noTrainingBody = document.querySelector('#noTrainingTable tbody'); - noTrainingBody.innerHTML = noTraining.slice(0, 20).map(n => - `${n}${noTrainingDivs[n]}` - ).join(''); - - const detailBody = document.querySelector('#detailTable tbody'); - detailBody.innerHTML = data.map(r => { - const s = (r.status || '').toLowerCase(); - let cls = ''; - if (s.includes('завершен') || s.includes('прошёл') || s.includes('прошел') || s === 'completed' || s.includes('ок')) cls = 'status-completed'; - else if (s.includes('ходе') || s.includes('progress')) cls = 'status-in-progress'; - else cls = 'status-not-started'; - return ` - ${r.name || ''} - ${r.division || ''} - ${r.course || ''} - ${r.status || ''} - ${r.score || ''} - ${r.trainer || ''} - `; + document.querySelector('#detailTable tbody').innerHTML = data.map(function(r) { + var cls = isCompleted(r.status) ? 'status-completed' : 'status-not-started'; + return '' + (r.name || '') + '' + (r.division || '') + '' + (r.course || '') + '' + (r.status || '') + '' + (r.score || '') + '' + (r.trainer || '') + ''; }).join(''); } function renderChart(canvasId, type, chartData, extraOptions) { if (chartInstances[canvasId]) chartInstances[canvasId].destroy(); - - const defaults = { - responsive: true, - maintainAspectRatio: true, - plugins: { - legend: { labels: { color: '#e0e0e0', font: { size: 12 } } } - } - }; - + var defaults = { responsive: true, maintainAspectRatio: true, plugins: { legend: { labels: { color: '#e0e0e0', font: { size: 12 } } } } }; if (type === 'bar' || type === 'line') { - defaults.scales = { - y: { beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, - x: { ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } } - }; + defaults.scales = { y: { beginAtZero: true, ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } }, x: { ticks: { color: '#90a4ae' }, grid: { color: '#1e2d3d' } } }; } - if (extraOptions) { - Object.assign(defaults, extraOptions); - if (extraOptions.scales) defaults.scales = extraOptions.scales; + Object.keys(extraOptions).forEach(function(k) { defaults[k] = extraOptions[k]; }); } - - const ctx = document.getElementById(canvasId).getContext('2d'); - chartInstances[canvasId] = new Chart(ctx, { - type: type, - data: chartData, - options: defaults - }); + var ctx = document.getElementById(canvasId).getContext('2d'); + chartInstances[canvasId] = new Chart(ctx, { type: type, data: chartData, options: defaults }); }