1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

feat: show placeholders when no data is available (resolve #42)

feat: add jsx as custom language by default (resolve #50)
This commit is contained in:
Ferdinand Mütsch 2020-08-30 16:51:37 +02:00
parent cecb5e113c
commit 97cb29ee4d
5 changed files with 198 additions and 122 deletions

View File

@ -11,4 +11,5 @@ cleanup = false
max_connections = 2 max_connections = 2
[languages] [languages]
vue = Vue vue = Vue
jsx = JSX

View File

@ -1,5 +1,5 @@
const SHOW_TOP_N = 10 const SHOW_TOP_N = 10
const CHART_TARGET_SIZE = 170 const CHART_TARGET_SIZE = 200
const projectsCanvas = document.getElementById('chart-projects') const projectsCanvas = document.getElementById('chart-projects')
const osCanvas = document.getElementById('chart-os') const osCanvas = document.getElementById('chart-os')
@ -7,6 +7,16 @@ const editorsCanvas = document.getElementById('chart-editor')
const languagesCanvas = document.getElementById('chart-language') const languagesCanvas = document.getElementById('chart-language')
const machinesCanvas = document.getElementById('chart-machine') const machinesCanvas = document.getElementById('chart-machine')
const projectContainer = document.getElementById('project-container')
const osContainer = document.getElementById('os-container')
const editorContainer = document.getElementById('editor-container')
const languageContainer = document.getElementById('language-container')
const machineContainer = document.getElementById('machine-container')
const containers = [projectContainer, osContainer, editorContainer, languageContainer, machineContainer]
const canvases = [projectsCanvas, osCanvas, editorsCanvas, languagesCanvas, machinesCanvas]
const data = [wakapiData.projects, wakapiData.operatingSystems, wakapiData.editors, wakapiData.languages, wakapiData.machines]
let charts = [] let charts = []
let resizeCount = 0 let resizeCount = 0
@ -29,11 +39,6 @@ String.prototype.toHHMMSS = function () {
} }
function draw() { function draw() {
let titleOptions = {
display: true,
fontSize: 16
}
function getTooltipOptions(key, type) { function getTooltipOptions(key, type) {
return { return {
mode: 'single', mode: 'single',
@ -49,131 +54,158 @@ function draw() {
charts.forEach(c => c.destroy()) charts.forEach(c => c.destroy())
let projectChart = new Chart(projectsCanvas.getContext('2d'), { let projectChart = !projectsCanvas.classList.contains('hidden')
type: 'horizontalBar', ? new Chart(projectsCanvas.getContext('2d'), {
data: { type: 'horizontalBar',
datasets: wakapiData.projects data: {
.slice(0, Math.min(SHOW_TOP_N, wakapiData.projects.length)) datasets: wakapiData.projects
.map(p => { .slice(0, Math.min(SHOW_TOP_N, wakapiData.projects.length))
return { .map(p => {
label: p.key, return {
data: [parseInt(p.total) / 60], label: p.key,
backgroundColor: getRandomColor(p.key) data: [parseInt(p.total) / 60],
} backgroundColor: getRandomColor(p.key)
}) }
}, })
options: {
title: Object.assign(titleOptions, {text: `Projects (top ${SHOW_TOP_N})`}),
tooltips: getTooltipOptions('projects', 'bar'),
legend: {
display: false
}, },
scales: { options: {
xAxes: [{ tooltips: getTooltipOptions('projects', 'bar'),
scaleLabel: { legend: {
display: true, display: false
labelString: 'Minutes' },
} scales: {
}] xAxes: [{
}, scaleLabel: {
maintainAspectRatio: false, display: true,
onResize: onChartResize labelString: 'Minutes'
} }
}) }]
},
maintainAspectRatio: false,
onResize: onChartResize
}
})
: null
let osChart = new Chart(osCanvas.getContext('2d'), { let osChart = !osCanvas.classList.contains('hidden')
type: 'pie', ? new Chart(osCanvas.getContext('2d'), {
data: { type: 'pie',
datasets: [{ data: {
data: wakapiData.operatingSystems datasets: [{
data: wakapiData.operatingSystems
.slice(0, Math.min(SHOW_TOP_N, wakapiData.operatingSystems.length))
.map(p => parseInt(p.total)),
backgroundColor: wakapiData.operatingSystems.map(p => getRandomColor(p.key))
}],
labels: wakapiData.operatingSystems
.slice(0, Math.min(SHOW_TOP_N, wakapiData.operatingSystems.length)) .slice(0, Math.min(SHOW_TOP_N, wakapiData.operatingSystems.length))
.map(p => parseInt(p.total)), .map(p => p.key)
backgroundColor: wakapiData.operatingSystems.map(p => getRandomColor(p.key)) },
}], options: {
labels: wakapiData.operatingSystems tooltips: getTooltipOptions('operatingSystems', 'pie'),
.slice(0, Math.min(SHOW_TOP_N, wakapiData.operatingSystems.length)) maintainAspectRatio: false,
.map(p => p.key) onResize: onChartResize
}, }
options: { })
title: Object.assign(titleOptions, {text: `Operating Systems (top ${SHOW_TOP_N})`}), : null
tooltips: getTooltipOptions('operatingSystems', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
}
})
let editorChart = new Chart(editorsCanvas.getContext('2d'), { let editorChart = !editorsCanvas.classList.contains('hidden')
type: 'pie', ? new Chart(editorsCanvas.getContext('2d'), {
data: { type: 'pie',
datasets: [{ data: {
data: wakapiData.editors datasets: [{
data: wakapiData.editors
.slice(0, Math.min(SHOW_TOP_N, wakapiData.editors.length))
.map(p => parseInt(p.total)),
backgroundColor: wakapiData.editors.map(p => getRandomColor(p.key))
}],
labels: wakapiData.editors
.slice(0, Math.min(SHOW_TOP_N, wakapiData.editors.length)) .slice(0, Math.min(SHOW_TOP_N, wakapiData.editors.length))
.map(p => parseInt(p.total)), .map(p => p.key)
backgroundColor: wakapiData.editors.map(p => getRandomColor(p.key)) },
}], options: {
labels: wakapiData.editors tooltips: getTooltipOptions('editors', 'pie'),
.slice(0, Math.min(SHOW_TOP_N, wakapiData.editors.length)) maintainAspectRatio: false,
.map(p => p.key) onResize: onChartResize
}, }
options: { })
title: Object.assign(titleOptions, {text: `Editors (top ${SHOW_TOP_N})`}), : null
tooltips: getTooltipOptions('editors', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
}
})
let languageChart = new Chart(languagesCanvas.getContext('2d'), { let languageChart = !languagesCanvas.classList.contains('hidden')
type: 'pie', ? new Chart(languagesCanvas.getContext('2d'), {
data: { type: 'pie',
datasets: [{ data: {
data: wakapiData.languages datasets: [{
data: wakapiData.languages
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length))
.map(p => parseInt(p.total)),
backgroundColor: wakapiData.languages.map(p => languageColors[p.key.toLowerCase()] || getRandomColor(p.key))
}],
labels: wakapiData.languages
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length)) .slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length))
.map(p => parseInt(p.total)), .map(p => p.key)
backgroundColor: wakapiData.languages.map(p => languageColors[p.key.toLowerCase()] || getRandomColor(p.key)) },
}], options: {
labels: wakapiData.languages tooltips: getTooltipOptions('languages', 'pie'),
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length)) maintainAspectRatio: false,
.map(p => p.key) onResize: onChartResize
}, }
options: { })
title: Object.assign(titleOptions, {text: `Languages (top ${SHOW_TOP_N})`}), : null
tooltips: getTooltipOptions('languages', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
}
})
let machineChart = new Chart(machinesCanvas.getContext('2d'), { let machineChart = !machinesCanvas.classList.contains('hidden')
type: 'pie', ? new Chart(machinesCanvas.getContext('2d'), {
data: { type: 'pie',
datasets: [{ data: {
data: wakapiData.machines datasets: [{
data: wakapiData.machines
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length))
.map(p => parseInt(p.total)),
backgroundColor: wakapiData.machines.map(p => getRandomColor(p.key))
}],
labels: wakapiData.machines
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length)) .slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length))
.map(p => parseInt(p.total)), .map(p => p.key)
backgroundColor: wakapiData.machines.map(p => getRandomColor(p.key)) },
}], options: {
labels: wakapiData.machines tooltips: getTooltipOptions('machines', 'pie'),
.slice(0, Math.min(SHOW_TOP_N, wakapiData.machines.length)) maintainAspectRatio: false,
.map(p => p.key) onResize: onChartResize
}, }
options: { })
title: Object.assign(titleOptions, {text: `Machines (top ${SHOW_TOP_N})`}), : null
tooltips: getTooltipOptions('machines', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
}
})
getTotal(wakapiData.operatingSystems) getTotal(wakapiData.operatingSystems)
document.getElementById('grid-container').style.visibility = 'visible'
charts = [projectChart, osChart, editorChart, languageChart, machineChart] charts = [projectChart, osChart, editorChart, languageChart, machineChart].filter(c => !!c)
charts.forEach(c => c.options.onResize(c.chart)) charts.forEach(c => c.options.onResize(c.chart))
equalizeHeights() equalizeHeights()
} }
function setTopLabels() {
[...document.getElementsByClassName('top-label')]
.forEach(e => e.innerText = `(top ${SHOW_TOP_N})`)
}
function togglePlaceholders(mask) {
const placeholderElements = containers.map(c => c.querySelector('.placeholder-container'))
for (let i = 0; i < mask.length; i++) {
if (!mask[i]) {
canvases[i].classList.add('hidden')
placeholderElements[i].classList.remove('hidden')
} else {
canvases[i].classList.remove('hidden')
placeholderElements[i].classList.add('hidden')
}
}
}
function getPresentDataMask() {
return data.map(list => list.reduce((acc, e) => acc + e.total, 0) > 0)
}
function getContainer(chart) { function getContainer(chart) {
return chart.canvas.parentNode return chart.canvas.parentNode
} }
@ -257,7 +289,7 @@ if (favicon) {
} }
// Click outside // Click outside
window.addEventListener('click', function(event) { window.addEventListener('click', function (event) {
if (event.target.classList.contains('popup')) { if (event.target.classList.contains('popup')) {
return return
} }
@ -268,5 +300,7 @@ window.addEventListener('click', function(event) {
}) })
window.addEventListener('load', function () { window.addEventListener('load', function () {
setTopLabels()
togglePlaceholders(getPresentDataMask())
draw() draw()
}) })

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -1 +1 @@
1.8.3 1.8.4

View File

@ -59,28 +59,68 @@
</div> </div>
<div class="flex flex-wrap justify-center"> <div class="flex flex-wrap justify-center">
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="projects-container" style="height: 300px"> <div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="project-container" style="height: 300px">
<div class="self-center flex">
<span class="font-semibold mr-1">Projects</span>
<span id="project-top-label" class="top-label"></span>
</div>
<canvas id="chart-projects"></canvas> <canvas id="chart-projects"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="os-container" style="height: 300px"> <div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="os-container" style="height: 300px">
<div class="self-center flex">
<span class="font-semibold mr-1">Operating Systems</span>
<span id="os-top-label" class="top-label"></span>
</div>
<canvas id="chart-os"></canvas> <canvas id="chart-os"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2 relative" id="language-container" style="height: 300px"> <div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col relative" id="language-container" style="height: 300px">
<div class="self-center flex">
<span class="font-semibold mr-1">Languages</span>
<span id="language-top-label" class="top-label"></span>
</div>
<canvas id="chart-language"></canvas> <canvas id="chart-language"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="editor-container" style="height: 300px"> <div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="editor-container" style="height: 300px">
<div class="self-center flex">
<span class="font-semibold mr-1">Editors</span>
<span id="editor-top-label" class="top-label"></span>
</div>
<canvas id="chart-editor"></canvas> <canvas id="chart-editor"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="machine-container" style="height: 300px"> <div class="p-4 pb-10 bg-white rounded shadow m-2 flex flex-col" id="machine-container" style="height: 300px">
<div class="self-center flex">
<span class="font-semibold mr-1">Machines</span>
<span id="machine-top-label" class="top-label"></span>
</div>
<canvas id="chart-machine"></canvas> <canvas id="chart-machine"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div> </div>
</div> </div>
</div> </div>