Modrinth/lib/components/chart/CompactChart.vue
Adrian O.V c056c4e79e
Improved graphs (#120)
* Complete chart overhaul

* Update package.json

* Update pnpm-lock.yaml

* run lint

* whoops

* Update pnpm-lock.yaml

* Update analytics.md

* Try again?

* Update Chart.vue

* Added Compact/Spark charts

* Added number formatting and cleanup

* Touch ups

* improve default colors

* removed unnecessary tooltip
2023-10-26 11:39:26 -07:00

279 lines
5.3 KiB
Vue

<script setup>
import { Card, formatNumber } from '@'
import { defineAsyncComponent, ref } from 'vue'
import dayjs from 'dayjs'
const VueApexCharts = defineAsyncComponent(() => import('vue3-apexcharts'))
const props = defineProps({
value: {
type: String,
default: '',
},
title: {
type: String,
default: '',
},
data: {
type: Array,
default: () => [],
},
labels: {
type: Array,
default: () => [],
},
prefix: {
type: String,
default: '',
},
suffix: {
type: String,
default: '',
},
})
//no grid lines, no toolbar, no legend, no data labels
const chartOptions = ref({
chart: {
id: props.title,
fontFamily:
'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif',
foreColor: 'var(--color-base)',
toolbar: {
show: false,
},
zoom: {
enabled: false,
},
sparkline: {
enabled: true,
},
},
stroke: {
curve: 'straight',
},
fill: {
colors: ['var(--color-brand)'],
type: 'gradient',
opacity: 1,
gradient: {
shade: 'light',
type: 'vertical',
shadeIntensity: 0,
gradientToColors: ['var(--color-brand)'],
inverseColors: true,
opacityFrom: 0.5,
opacityTo: 0,
stops: [0, 100],
colorStops: [],
},
},
grid: {
show: false,
},
legend: {
show: false,
},
colors: ['var(--color-brand)'],
dataLabels: {
enabled: false,
},
xaxis: {
type: 'datetime',
categories: props.labels,
labels: {
show: false,
},
axisTicks: {
show: false,
},
tooltip: {
enabled: false,
},
},
yaxis: {
labels: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
tooltip: {
enabled: false,
},
},
tooltip: {
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
console.log(seriesIndex, w)
return (
'<div class="bar-tooltip">' +
series
.map((value) =>
value[dataPointIndex] > 0
? `<div class="list-entry">
<div class="label">
<span class="circle" style="background-color: ${w.globals.colors[0]}"> </span>
${dayjs(w.globals.lastXAxis.categories[dataPointIndex]).format('MMM D')}
</div>
<div class="divider">
|
</div>
<div class="value">
${props.prefix}
${formatNumber(value[dataPointIndex], false)}
${props.suffix}
</div>
</div>`
: ''
)
.reverse()
.reduce((a, b) => a + b) +
'</div>'
)
},
},
})
</script>
<template>
<Card class="compact-chart">
<h1 class="value">
{{ value }}
</h1>
<div class="subtitle">
{{ title }}
</div>
<VueApexCharts
ref="chart"
type="area"
height="120"
:options="chartOptions"
:series="data"
class="chart"
/>
</Card>
</template>
<style scoped lang="scss">
.compact-chart {
display: flex;
flex-direction: column;
gap: var(--gap-xs);
border: 1px solid var(--color-button-bg);
border-radius: var(--radius-md);
background-color: var(--color-raised-bg);
box-shadow: var(--shadow-floating);
color: var(--color-base);
font-size: var(--font-size-nm);
width: 100%;
padding-bottom: 0;
.value {
margin: 0;
}
}
.chart {
width: calc(100% + 3rem);
margin: 0 -1.5rem 0.25rem -1.5rem;
}
svg {
width: 100%;
height: 100%;
}
:deep(.apexcharts-menu),
:deep(.apexcharts-tooltip),
:deep(.apexcharts-yaxistooltip) {
background: var(--color-raised-bg) !important;
border-radius: var(--radius-sm) !important;
border: 1px solid var(--color-button-bg) !important;
box-shadow: var(--shadow-floating) !important;
font-size: var(--font-size-nm) !important;
}
:deep(.apexcharts-graphical) {
width: 100%;
}
:deep(.apexcharts-tooltip) {
.bar-tooltip {
display: flex;
flex-direction: column;
gap: var(--gap-xs);
padding: var(--gap-sm);
.card-divider {
margin: var(--gap-xs) 0;
}
.label {
display: flex;
flex-direction: row;
align-items: center;
}
.value {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--gap-xs);
color: var(--color-base);
}
.list-entry {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: var(--gap-md);
}
.circle {
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
display: inline-block;
margin-right: var(--gap-sm);
}
svg {
height: 1em;
width: 1em;
}
.divider {
font-size: var(--font-size-lg);
font-weight: 400;
}
}
}
.legend {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--gap-md);
justify-content: center;
}
:deep(.apexcharts-grid-borders) {
line {
stroke: var(--color-button-bg) !important;
}
}
:deep(.apexcharts-xaxis) {
line {
stroke: none;
}
}
.legend-checkbox :deep(.checkbox.checked) {
background-color: var(--color);
}
</style>