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:
parent
cecb5e113c
commit
97cb29ee4d
@ -11,4 +11,5 @@ cleanup = false
|
||||
max_connections = 2
|
||||
|
||||
[languages]
|
||||
vue = Vue
|
||||
vue = Vue
|
||||
jsx = JSX
|
@ -1,5 +1,5 @@
|
||||
const SHOW_TOP_N = 10
|
||||
const CHART_TARGET_SIZE = 170
|
||||
const CHART_TARGET_SIZE = 200
|
||||
|
||||
const projectsCanvas = document.getElementById('chart-projects')
|
||||
const osCanvas = document.getElementById('chart-os')
|
||||
@ -7,6 +7,16 @@ const editorsCanvas = document.getElementById('chart-editor')
|
||||
const languagesCanvas = document.getElementById('chart-language')
|
||||
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 resizeCount = 0
|
||||
|
||||
@ -29,11 +39,6 @@ String.prototype.toHHMMSS = function () {
|
||||
}
|
||||
|
||||
function draw() {
|
||||
let titleOptions = {
|
||||
display: true,
|
||||
fontSize: 16
|
||||
}
|
||||
|
||||
function getTooltipOptions(key, type) {
|
||||
return {
|
||||
mode: 'single',
|
||||
@ -49,131 +54,158 @@ function draw() {
|
||||
|
||||
charts.forEach(c => c.destroy())
|
||||
|
||||
let projectChart = new Chart(projectsCanvas.getContext('2d'), {
|
||||
type: 'horizontalBar',
|
||||
data: {
|
||||
datasets: wakapiData.projects
|
||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.projects.length))
|
||||
.map(p => {
|
||||
return {
|
||||
label: 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
|
||||
let projectChart = !projectsCanvas.classList.contains('hidden')
|
||||
? new Chart(projectsCanvas.getContext('2d'), {
|
||||
type: 'horizontalBar',
|
||||
data: {
|
||||
datasets: wakapiData.projects
|
||||
.slice(0, Math.min(SHOW_TOP_N, wakapiData.projects.length))
|
||||
.map(p => {
|
||||
return {
|
||||
label: p.key,
|
||||
data: [parseInt(p.total) / 60],
|
||||
backgroundColor: getRandomColor(p.key)
|
||||
}
|
||||
})
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Minutes'
|
||||
}
|
||||
}]
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
options: {
|
||||
tooltips: getTooltipOptions('projects', 'bar'),
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
labelString: 'Minutes'
|
||||
}
|
||||
}]
|
||||
},
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
let osChart = new Chart(osCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: wakapiData.operatingSystems
|
||||
let osChart = !osCanvas.classList.contains('hidden')
|
||||
? new Chart(osCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
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))
|
||||
.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))
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
title: Object.assign(titleOptions, {text: `Operating Systems (top ${SHOW_TOP_N})`}),
|
||||
tooltips: getTooltipOptions('operatingSystems', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
tooltips: getTooltipOptions('operatingSystems', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
let editorChart = new Chart(editorsCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: wakapiData.editors
|
||||
let editorChart = !editorsCanvas.classList.contains('hidden')
|
||||
? new Chart(editorsCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
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))
|
||||
.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))
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
title: Object.assign(titleOptions, {text: `Editors (top ${SHOW_TOP_N})`}),
|
||||
tooltips: getTooltipOptions('editors', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
tooltips: getTooltipOptions('editors', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
let languageChart = new Chart(languagesCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: wakapiData.languages
|
||||
let languageChart = !languagesCanvas.classList.contains('hidden')
|
||||
? new Chart(languagesCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
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))
|
||||
.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))
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
title: Object.assign(titleOptions, {text: `Languages (top ${SHOW_TOP_N})`}),
|
||||
tooltips: getTooltipOptions('languages', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
tooltips: getTooltipOptions('languages', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
let machineChart = new Chart(machinesCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: wakapiData.machines
|
||||
let machineChart = !machinesCanvas.classList.contains('hidden')
|
||||
? new Chart(machinesCanvas.getContext('2d'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
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))
|
||||
.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))
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
title: Object.assign(titleOptions, {text: `Machines (top ${SHOW_TOP_N})`}),
|
||||
tooltips: getTooltipOptions('machines', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
.map(p => p.key)
|
||||
},
|
||||
options: {
|
||||
tooltips: getTooltipOptions('machines', 'pie'),
|
||||
maintainAspectRatio: false,
|
||||
onResize: onChartResize
|
||||
}
|
||||
})
|
||||
: null
|
||||
|
||||
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))
|
||||
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) {
|
||||
return chart.canvas.parentNode
|
||||
}
|
||||
@ -257,7 +289,7 @@ if (favicon) {
|
||||
}
|
||||
|
||||
// Click outside
|
||||
window.addEventListener('click', function(event) {
|
||||
window.addEventListener('click', function (event) {
|
||||
if (event.target.classList.contains('popup')) {
|
||||
return
|
||||
}
|
||||
@ -268,5 +300,7 @@ window.addEventListener('click', function(event) {
|
||||
})
|
||||
|
||||
window.addEventListener('load', function () {
|
||||
setTopLabels()
|
||||
togglePlaceholders(getPresentDataMask())
|
||||
draw()
|
||||
})
|
1
static/assets/images/no_data.svg
Normal file
1
static/assets/images/no_data.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 5.9 KiB |
@ -1 +1 @@
|
||||
1.8.3
|
||||
1.8.4
|
@ -59,28 +59,68 @@
|
||||
</div>
|
||||
<div class="flex flex-wrap justify-center">
|
||||
<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>
|
||||
<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 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>
|
||||
<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 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>
|
||||
<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 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>
|
||||
<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 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>
|
||||
<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>
|
||||
|
Loading…
Reference in New Issue
Block a user