You've already forked AstralRinth
forked from didirus/AstralRinth
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
This commit is contained in:
@@ -2,136 +2,168 @@
|
|||||||
|
|
||||||
<DemoContainer>
|
<DemoContainer>
|
||||||
<client-only>
|
<client-only>
|
||||||
<LineChart
|
<Chart
|
||||||
:data="{
|
name="Chart"
|
||||||
labels: [
|
type="bar"
|
||||||
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
:stacked="true"
|
||||||
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
:labels="[
|
||||||
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
||||||
'2021-01-16', '2021-01-17'
|
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
||||||
],
|
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
||||||
data: [
|
'2021-01-16', '2021-01-17'
|
||||||
{
|
]"
|
||||||
title: 'Spirit',
|
:data="[
|
||||||
color: 16711680,
|
{
|
||||||
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
name: 'Spirit',
|
||||||
},
|
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
||||||
{
|
},
|
||||||
title: 'Ad Astra',
|
{
|
||||||
color: 65280,
|
name: 'Ad Astra',
|
||||||
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Tempad',
|
name: 'Tempad',
|
||||||
color: 255,
|
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
||||||
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
},
|
||||||
},
|
]"
|
||||||
]
|
:colors="['#FF0000', '#00FF00', '#0000FF']"
|
||||||
}"
|
suffix="<svg xmlns='http://www.w3.org/2000/svg' class='h-6 w-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2'><path stroke-linecap='round' stroke-linejoin='round' d='M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4' /></svg>"
|
||||||
/>
|
/>
|
||||||
<BarChart
|
</client-only>
|
||||||
:data="{
|
</DemoContainer>
|
||||||
labels: [
|
<DemoContainer>
|
||||||
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
<client-only>
|
||||||
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
<Chart
|
||||||
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
name="Chart"
|
||||||
'2021-01-16', '2021-01-17'
|
type="line"
|
||||||
],
|
:labels="[
|
||||||
data: [
|
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
||||||
{
|
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
||||||
title: 'Spirit',
|
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
||||||
color: 16711680,
|
'2021-01-16', '2021-01-17'
|
||||||
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
]"
|
||||||
},
|
:data="[
|
||||||
{
|
{
|
||||||
title: 'Ad Astra',
|
name: 'Spirit',
|
||||||
color: 65280,
|
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 1280],
|
||||||
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'Ad Astra',
|
||||||
title: 'Tempad',
|
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 1230],
|
||||||
color: 255,
|
},
|
||||||
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
{
|
||||||
},
|
name: 'Tempad',
|
||||||
]
|
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
||||||
}"
|
},
|
||||||
/>
|
]"
|
||||||
<PieChart
|
:colors="['#FF0000', '#00FF00', '#0000FF']"
|
||||||
:data="{
|
suffix="<svg xmlns='http://www.w3.org/2000/svg' class='h-6 w-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2'><path stroke-linecap='round' stroke-linejoin='round' d='M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4' /></svg>"
|
||||||
title: 'Downloads',
|
/>
|
||||||
data: [
|
</client-only>
|
||||||
{
|
</DemoContainer>
|
||||||
title: 'Spirit',
|
<DemoContainer>
|
||||||
color: 16711680, // Red in decimal (equivalent to #FF0000 in hexadecimal)
|
<client-only>
|
||||||
data: 120, // Example download numbers for the three dates
|
<Chart
|
||||||
},
|
name="Chart"
|
||||||
{
|
:labels="[
|
||||||
title: 'Ad Astra',
|
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
||||||
color: 65280, // Green in decimal (equivalent to #00FF00 in hexadecimal)
|
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
||||||
data: 150, // Example download numbers for the three dates
|
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
||||||
},
|
'2021-01-16', '2021-01-17'
|
||||||
{
|
]"
|
||||||
title: 'Tempad',
|
:data="[
|
||||||
color: 255, // Blue in decimal (equivalent to #0000FF in hexadecimal)
|
{
|
||||||
data: 180, // Example download numbers for the three dates
|
name: 'Downloads',
|
||||||
},
|
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
||||||
],
|
},
|
||||||
}"
|
{
|
||||||
/>
|
name: 'Revenue',
|
||||||
|
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Page views',
|
||||||
|
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
hide-total
|
||||||
|
suffix="<svg xmlns='http://www.w3.org/2000/svg' class='h-6 w-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2'><path stroke-linecap='round' stroke-linejoin='round' d='M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4' /></svg>"
|
||||||
|
>
|
||||||
|
Slot for title stuff
|
||||||
|
<Chips :items="['option 1', 'option 3']" />
|
||||||
|
<template #toolbar>
|
||||||
|
<Button>
|
||||||
|
<PlusIcon />
|
||||||
|
Slot for toolbar stuff
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</Chart>
|
||||||
|
</client-only>
|
||||||
|
</DemoContainer>
|
||||||
|
<DemoContainer>
|
||||||
|
<client-only>
|
||||||
|
<div style="display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--gap-md);">
|
||||||
|
<CompactChart
|
||||||
|
v-for="i in 4"
|
||||||
|
title="Downloads"
|
||||||
|
value="10,230"
|
||||||
|
:labels="[
|
||||||
|
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
||||||
|
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
||||||
|
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
||||||
|
'2021-01-16', '2021-01-17'
|
||||||
|
]"
|
||||||
|
:data="[
|
||||||
|
{
|
||||||
|
name: 'Downloads',
|
||||||
|
data: [240, 180, 210, 160, 250, 130, 220, 270, 120, 260, 200, 230, 140, 280, 190, 150, 170],
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
suffix="<svg xmlns='http://www.w3.org/2000/svg' class='h-6 w-6' fill='none' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2'><path stroke-linecap='round' stroke-linejoin='round' d='M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4' /></svg>"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</client-only>
|
</client-only>
|
||||||
</DemoContainer>
|
</DemoContainer>
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<LineChart
|
<Chart
|
||||||
:formatLabel="(label) => doFormattingThings(label)"
|
name="Chart name"
|
||||||
:data="{
|
:labels="['array', 'of', 'labels', 'for', 'x-axis', 'typically', 'dates']"
|
||||||
labels: [
|
:data="[
|
||||||
'2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05',
|
{
|
||||||
'2021-01-06', '2021-01-07', '2021-01-08', '2021-01-09', '2021-01-10',
|
name: 'Spirit',
|
||||||
'2021-01-11', '2021-01-12', '2021-01-13', '2021-01-14', '2021-01-15',
|
data: ['array', 'of', 'data', 'equal', 'length', 'to', 'x-axis'],
|
||||||
'2021-01-16', '2021-01-17'
|
},
|
||||||
],
|
...
|
||||||
data: [
|
]"
|
||||||
{
|
:colors="['array', 'of', 'colors', 'for', 'each', 'series/dataset']"
|
||||||
title: 'Spirit',
|
prefix="string or svg icon to append to each data point"
|
||||||
color: 16711680,
|
suffix="string or svg icon to append to each data point"
|
||||||
data: [120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 280],
|
type="bar|line"
|
||||||
},
|
:stacked="true|false (default: false) (determines whether or not values overlap/sidebyside instead of stacked)"
|
||||||
{
|
:hideTotal="true|false (default: false) (hide total value in tooltip)"
|
||||||
title: 'Ad Astra',
|
:hideToolbar="true|false (default: false) (hide toolbar)"
|
||||||
color: 65280,
|
:hideLegend="true|false (default: false) (hide legend)"
|
||||||
data: [150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230],
|
>
|
||||||
},
|
... slot for title stuff
|
||||||
{
|
<template #toolbar>
|
||||||
title: 'Tempad',
|
... slot for toolbar stuff
|
||||||
color: 255,
|
</template>
|
||||||
data: [180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212],
|
</Chart>
|
||||||
},
|
|
||||||
]
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<PieChart
|
<CompactChart
|
||||||
:data="{
|
title="Chart title"
|
||||||
title: 'Downloads',
|
value="Chart value"
|
||||||
data: [
|
:labels="['array', 'of', 'labels', 'for', 'x-axis', 'typically', 'dates']"
|
||||||
{
|
:data="[
|
||||||
title: 'Spirit',
|
{
|
||||||
color: 16711680, // Red in decimal (equivalent to #FF0000 in hexadecimal)
|
name: 'Spirit',
|
||||||
data: 120, // Example download numbers for the three dates
|
data: ['array', 'of', 'data', 'equal', 'length', 'to', 'x-axis'],
|
||||||
},
|
},
|
||||||
{
|
...
|
||||||
title: 'Ad Astra',
|
]"
|
||||||
color: 65280, // Green in decimal (equivalent to #00FF00 in hexadecimal)
|
prefix="string or svg icon to append to each data point"
|
||||||
data: 150, // Example download numbers for the three dates
|
suffix="string or svg icon to append to each data point"
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Tempad',
|
|
||||||
color: 255, // Blue in decimal (equivalent to #0000FF in hexadecimal)
|
|
||||||
data: 180, // Example download numbers for the three dates
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}"
|
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|||||||
1
lib/assets/icons/zoom-in.svg
Normal file
1
lib/assets/icons/zoom-in.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zoom-in"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="11" x2="11" y1="8" y2="14"/><line x1="8" x2="14" y1="11" y2="11"/></svg>
|
||||||
|
After Width: | Height: | Size: 369 B |
1
lib/assets/icons/zoom-out.svg
Normal file
1
lib/assets/icons/zoom-out.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-zoom-out"><circle cx="11" cy="11" r="8"/><line x1="21" x2="16.65" y1="21" y2="16.65"/><line x1="8" x2="14" y1="11" y2="11"/></svg>
|
||||||
|
After Width: | Height: | Size: 332 B |
@@ -165,6 +165,13 @@ svg {
|
|||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
svg {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.button-animation {
|
.button-animation {
|
||||||
transition: opacity 0.5s ease-in-out, filter 0.2s ease-in-out, transform 0.05s ease-in-out,
|
transition: opacity 0.5s ease-in-out, filter 0.2s ease-in-out, transform 0.05s ease-in-out,
|
||||||
outline 0.2s ease-in-out;
|
outline 0.2s ease-in-out;
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { Bar } from 'vue-chartjs'
|
|
||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
BarElement,
|
|
||||||
CategoryScale,
|
|
||||||
LinearScale,
|
|
||||||
} from 'chart.js'
|
|
||||||
import dayjs from 'dayjs'
|
|
||||||
|
|
||||||
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
formatLabels: {
|
|
||||||
type: Function,
|
|
||||||
default: (label) => dayjs(label).format('MMM D'),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const decimalToRgba = (decimalColor, alpha = 0.75) => {
|
|
||||||
const red = (decimalColor >> 16) & 255
|
|
||||||
const green = (decimalColor >> 8) & 255
|
|
||||||
const blue = decimalColor & 255
|
|
||||||
|
|
||||||
return `rgba(${red}, ${green}, ${blue}, ${alpha})`
|
|
||||||
}
|
|
||||||
|
|
||||||
const chartData = ref({
|
|
||||||
labels: props.data.labels.map((date) => props.formatLabels(date)),
|
|
||||||
datasets: props.data.data.map((project) => ({
|
|
||||||
label: project.title,
|
|
||||||
borderColor: decimalToRgba(project.color, 1),
|
|
||||||
borderWidth: 2,
|
|
||||||
borderSkipped: 'bottom',
|
|
||||||
backgroundColor: decimalToRgba(project.color, 0.5),
|
|
||||||
data: project.data,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
|
|
||||||
const chartOptions = ref({
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
stacked: true,
|
|
||||||
grid: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
},
|
|
||||||
ticks: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
stacked: true,
|
|
||||||
grid: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
},
|
|
||||||
ticks: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
interaction: {
|
|
||||||
mode: 'index',
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'right',
|
|
||||||
align: 'start',
|
|
||||||
labels: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
font: {
|
|
||||||
size: 12,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
position: 'nearest',
|
|
||||||
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue(
|
|
||||||
'--color-raised-bg'
|
|
||||||
),
|
|
||||||
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
borderWidth: 1,
|
|
||||||
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--color-contrast'),
|
|
||||||
titleFont: {
|
|
||||||
size: 16,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
bodyFont: {
|
|
||||||
size: 12,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
boxPadding: 8,
|
|
||||||
intersect: false,
|
|
||||||
padding: 12,
|
|
||||||
displayColors: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Bar id="my-chart-id" :options="chartOptions" :data="chartData" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
417
lib/components/chart/Chart.vue
Normal file
417
lib/components/chart/Chart.vue
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
<script setup>
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { Button, DownloadIcon, UpdatedIcon, Checkbox, formatNumber } from '@'
|
||||||
|
import { defineAsyncComponent, ref } from 'vue'
|
||||||
|
|
||||||
|
const VueApexCharts = defineAsyncComponent(() => import('vue3-apexcharts'))
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
labels: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
formatLabels: {
|
||||||
|
type: Function,
|
||||||
|
default: (label) => dayjs(label).format('MMM D'),
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
'var(--color-brand)',
|
||||||
|
'var(--color-blue)',
|
||||||
|
'var(--color-purple)',
|
||||||
|
'var(--color-red)',
|
||||||
|
'var(--color-orange)',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
prefix: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
suffix: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
hideToolbar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
hideLegend: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
stacked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'bar',
|
||||||
|
},
|
||||||
|
hideTotal: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const chartOptions = ref({
|
||||||
|
chart: {
|
||||||
|
id: props.name,
|
||||||
|
fontFamily:
|
||||||
|
'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif',
|
||||||
|
foreColor: 'var(--color-base)',
|
||||||
|
selection: {
|
||||||
|
enabled: true,
|
||||||
|
fill: {
|
||||||
|
color: 'var(--color-brand)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
stacked: props.stacked,
|
||||||
|
},
|
||||||
|
xaxis: {
|
||||||
|
type: 'datetime',
|
||||||
|
categories: props.labels,
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
borderRadius: 'var(--radius-sm)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisTicks: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
tooltip: {
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
colors: props.colors,
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false,
|
||||||
|
background: {
|
||||||
|
enabled: true,
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
borderColor: 'var(--color-button-bg)',
|
||||||
|
tickColor: 'var(--color-button-bg)',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
markers: {
|
||||||
|
size: 0,
|
||||||
|
strokeColor: 'var(--color-contrast)',
|
||||||
|
strokeWidth: 3,
|
||||||
|
strokeOpacity: 1,
|
||||||
|
fillOpacity: 1,
|
||||||
|
hover: {
|
||||||
|
size: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
bar: {
|
||||||
|
columnWidth: '80%',
|
||||||
|
endingShape: 'rounded',
|
||||||
|
borderRadius: 5,
|
||||||
|
borderRadiusApplication: 'end',
|
||||||
|
borderRadiusWhenStacked: 'last',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
|
||||||
|
console.log(seriesIndex, w)
|
||||||
|
return (
|
||||||
|
'<div class="bar-tooltip">' +
|
||||||
|
'<div class="seperated-entry title">' +
|
||||||
|
'<div class="label">' +
|
||||||
|
props.formatLabels(w.globals.lastXAxis.categories[dataPointIndex]) +
|
||||||
|
'</div>' +
|
||||||
|
(!props.hideTotal
|
||||||
|
? `<div class="value">
|
||||||
|
${props.prefix}
|
||||||
|
${formatNumber(series.reduce((a, b) => a + b[dataPointIndex], 0).toString(), false)}
|
||||||
|
${props.suffix}
|
||||||
|
</div>`
|
||||||
|
: ``) +
|
||||||
|
'</div><hr class="card-divider" />' +
|
||||||
|
series
|
||||||
|
.map((value, index) =>
|
||||||
|
value[dataPointIndex] > 0
|
||||||
|
? `<div class="list-entry">
|
||||||
|
<span class="circle" style="background-color: ${w.globals.colors[index]}"> </span>
|
||||||
|
<div class="label">
|
||||||
|
${w.globals.seriesNames[index]}
|
||||||
|
</div>
|
||||||
|
<div class="value">
|
||||||
|
${props.prefix}
|
||||||
|
${formatNumber(value[dataPointIndex], false)}
|
||||||
|
${props.suffix}
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
: ''
|
||||||
|
)
|
||||||
|
.reverse()
|
||||||
|
.reduce((a, b) => a + b) +
|
||||||
|
'</div>'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const chart = ref(null)
|
||||||
|
|
||||||
|
const legendValues = ref(
|
||||||
|
[...props.data].map((project, index) => {
|
||||||
|
return { name: project.name, visible: true, color: props.colors[index] }
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const flipLegend = (legend, newVal) => {
|
||||||
|
legend.visible = newVal
|
||||||
|
chart.value.toggleSeries(legend.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadCSV = () => {
|
||||||
|
const csvContent =
|
||||||
|
'data:text/csv;charset=utf-8,' +
|
||||||
|
props.labels.join(',') +
|
||||||
|
'\n' +
|
||||||
|
props.data.map((project) => project.data.join(',')).reduce((a, b) => a + '\n' + b)
|
||||||
|
|
||||||
|
const encodedUri = encodeURI(csvContent)
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.setAttribute('href', encodedUri)
|
||||||
|
link.setAttribute('download', `${props.name}.csv`)
|
||||||
|
document.body.appendChild(link) // Required for FF
|
||||||
|
|
||||||
|
link.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetChart = () => {
|
||||||
|
chart.value.resetSeries()
|
||||||
|
legendValues.value.forEach((legend) => {
|
||||||
|
legend.visible = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
resetChart,
|
||||||
|
downloadCSV,
|
||||||
|
flipLegend,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="bar-chart">
|
||||||
|
<div class="title-bar">
|
||||||
|
<slot />
|
||||||
|
<div v-if="!hideToolbar" class="toolbar">
|
||||||
|
<Button v-tooltip="'Download data as CSV'" icon-only @click="downloadCSV">
|
||||||
|
<DownloadIcon />
|
||||||
|
</Button>
|
||||||
|
<Button v-tooltip="'Reset chart'" icon-only @click="resetChart">
|
||||||
|
<UpdatedIcon />
|
||||||
|
</Button>
|
||||||
|
<slot name="toolbar" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<VueApexCharts ref="chart" :type="type" :options="chartOptions" :series="data" class="chart" />
|
||||||
|
<div v-if="!hideLegend" class="legend">
|
||||||
|
<Checkbox
|
||||||
|
v-for="legend in legendValues"
|
||||||
|
:key="legend.name"
|
||||||
|
class="legend-checkbox"
|
||||||
|
:style="`--color: ${legend.color};`"
|
||||||
|
:model-value="legend.visible"
|
||||||
|
@update:model-value="(newVal) => flipLegend(legend, newVal)"
|
||||||
|
>
|
||||||
|
{{ legend.name }}
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-chart {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-bar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--gap-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--gap-xs);
|
||||||
|
z-index: 1;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
: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-grid-borders) {
|
||||||
|
line {
|
||||||
|
stroke: var(--color-button-bg) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-yaxistooltip),
|
||||||
|
:deep(.apexcharts-xaxistooltip) {
|
||||||
|
background: var(--color-raised-bg) !important;
|
||||||
|
border-radius: var(--radius-sm) !important;
|
||||||
|
border: 1px solid var(--color-button-bg) !important;
|
||||||
|
font-size: var(--font-size-nm) !important;
|
||||||
|
color: var(--color-base) !important;
|
||||||
|
|
||||||
|
.apexcharts-xaxistooltip-text {
|
||||||
|
font-size: var(--font-size-nm) !important;
|
||||||
|
color: var(--color-base) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-yaxistooltip-left:after) {
|
||||||
|
border-left-color: var(--color-raised-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-yaxistooltip-left:before) {
|
||||||
|
border-left-color: var(--color-button-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-xaxistooltip-bottom:after) {
|
||||||
|
border-bottom-color: var(--color-raised-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-xaxistooltip-bottom:before) {
|
||||||
|
border-bottom-color: var(--color-button-bg) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-menu-item) {
|
||||||
|
border-radius: var(--radius-sm) !important;
|
||||||
|
padding: var(--gap-xs) var(--gap-sm) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transition: all 0.3s !important;
|
||||||
|
color: var(--color-accent-contrast) !important;
|
||||||
|
background: var(--color-brand) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.apexcharts-tooltip) {
|
||||||
|
.bar-tooltip {
|
||||||
|
min-width: 10rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--gap-xs);
|
||||||
|
padding: var(--gap-sm);
|
||||||
|
|
||||||
|
.card-divider {
|
||||||
|
margin: var(--gap-xs) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seperated-entry {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: var(--color-contrast);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
|
||||||
|
.value {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-right: var(--gap-xl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle {
|
||||||
|
width: 0.5rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: var(--gap-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--gap-md);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-checkbox :deep(.checkbox.checked) {
|
||||||
|
background-color: var(--color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
278
lib/components/chart/CompactChart.vue
Normal file
278
lib/components/chart/CompactChart.vue
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
<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>
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Line :options="chartOptions" :data="chartData" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { Line } from 'vue-chartjs'
|
|
||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
PointElement,
|
|
||||||
LineElement,
|
|
||||||
CategoryScale,
|
|
||||||
LinearScale,
|
|
||||||
Filler,
|
|
||||||
} from 'chart.js'
|
|
||||||
import dayjs from 'dayjs'
|
|
||||||
|
|
||||||
ChartJS.register(Title, Tooltip, PointElement, LineElement, CategoryScale, LinearScale, Filler)
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
formatLabels: {
|
|
||||||
type: Function,
|
|
||||||
default: (label) => dayjs(label).format('MMM D'),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const decimalToRgba = (decimalColor, alpha = 0.75) => {
|
|
||||||
const red = (decimalColor >> 16) & 255
|
|
||||||
const green = (decimalColor >> 8) & 255
|
|
||||||
const blue = decimalColor & 255
|
|
||||||
|
|
||||||
return `rgba(${red}, ${green}, ${blue}, ${alpha})`
|
|
||||||
}
|
|
||||||
|
|
||||||
const chartData = ref({
|
|
||||||
labels: props.data.labels.map((date) => props.formatLabels(date)),
|
|
||||||
datasets: props.data.data.map((project) => ({
|
|
||||||
label: project.title,
|
|
||||||
backgroundColor: decimalToRgba(project.color, 0.5),
|
|
||||||
borderColor: decimalToRgba(project.color),
|
|
||||||
data: project.data,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
|
|
||||||
const chartOptions = ref({
|
|
||||||
responsive: true,
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
grid: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
},
|
|
||||||
ticks: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
grid: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
},
|
|
||||||
ticks: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
interaction: {
|
|
||||||
mode: 'index',
|
|
||||||
intersect: false,
|
|
||||||
axis: 'xy',
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'right',
|
|
||||||
align: 'start',
|
|
||||||
labels: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
font: {
|
|
||||||
size: 12,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
position: 'nearest',
|
|
||||||
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue(
|
|
||||||
'--color-raised-bg'
|
|
||||||
),
|
|
||||||
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
borderWidth: 1,
|
|
||||||
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--color-contrast'),
|
|
||||||
titleFont: {
|
|
||||||
size: 14,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
bodyFont: {
|
|
||||||
size: 12,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
boxPadding: 8,
|
|
||||||
intersect: false,
|
|
||||||
padding: 12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
/*
|
|
||||||
The data for the graph should look like this
|
|
||||||
|
|
||||||
downloads, views, likes = {
|
|
||||||
dates: [ '2021-01-01', '2021-01-02', '2021-01-03' ], // Last 2 weeks
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
title: projectName,
|
|
||||||
color: projectColor,
|
|
||||||
data: [ ... ],
|
|
||||||
},
|
|
||||||
...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
</script>
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { Pie } from 'vue-chartjs'
|
|
||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
PieController,
|
|
||||||
ArcElement,
|
|
||||||
Legend,
|
|
||||||
CategoryScale,
|
|
||||||
LinearScale,
|
|
||||||
} from 'chart.js'
|
|
||||||
|
|
||||||
ChartJS.register(Title, Tooltip, PieController, ArcElement, Legend, CategoryScale, LinearScale)
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
data: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const decimalToRgba = (decimalColor, alpha = 1) => {
|
|
||||||
const red = (decimalColor >> 16) & 255
|
|
||||||
const green = (decimalColor >> 8) & 255
|
|
||||||
const blue = decimalColor & 255
|
|
||||||
|
|
||||||
return `rgba(${red}, ${green}, ${blue}, ${alpha})`
|
|
||||||
}
|
|
||||||
|
|
||||||
const chartData = ref({
|
|
||||||
labels: props.data.data.map((project) => project.title),
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: props.data.title,
|
|
||||||
backgroundColor: props.data.data.map((project) => decimalToRgba(project.color, 0.5)),
|
|
||||||
borderColor: props.data.data.map((project) => decimalToRgba(project.color)),
|
|
||||||
data: props.data.data.map((project) => project.data),
|
|
||||||
fill: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
const chartOptions = ref({
|
|
||||||
responsive: true,
|
|
||||||
elements: {
|
|
||||||
point: {
|
|
||||||
radius: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'right',
|
|
||||||
labels: {
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
font: {
|
|
||||||
size: 12,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
position: 'nearest',
|
|
||||||
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue(
|
|
||||||
'--color-raised-bg'
|
|
||||||
),
|
|
||||||
borderColor: getComputedStyle(document.documentElement).getPropertyValue('--color-button-bg'),
|
|
||||||
borderWidth: 1,
|
|
||||||
titleColor: getComputedStyle(document.documentElement).getPropertyValue('--color-contrast'),
|
|
||||||
titleFont: {
|
|
||||||
size: 16,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
bodyColor: getComputedStyle(document.documentElement).getPropertyValue('--color-base'),
|
|
||||||
bodyFont: {
|
|
||||||
size: 12,
|
|
||||||
family: 'Inter',
|
|
||||||
},
|
|
||||||
boxPadding: 8,
|
|
||||||
intersect: false,
|
|
||||||
padding: 12,
|
|
||||||
displayColors: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Pie :options="chartOptions" :data="chartData" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
@@ -30,9 +30,8 @@ export { default as TextLogo } from './brand/TextLogo.vue'
|
|||||||
export { default as FourOhFourNotFound } from '@/assets/branding/404.svg?component'
|
export { default as FourOhFourNotFound } from '@/assets/branding/404.svg?component'
|
||||||
|
|
||||||
// Charts
|
// Charts
|
||||||
export { default as BarChart } from './chart/BarChart.vue'
|
export { default as Chart } from './chart/Chart.vue'
|
||||||
export { default as LineChart } from './chart/LineChart.vue'
|
export { default as CompactChart } from './chart/CompactChart.vue'
|
||||||
export { default as PieChart } from './chart/PieChart.vue'
|
|
||||||
|
|
||||||
// Modals
|
// Modals
|
||||||
export { default as Modal } from './modal/Modal.vue'
|
export { default as Modal } from './modal/Modal.vue'
|
||||||
@@ -185,6 +184,8 @@ export { default as VersionIcon } from '@/assets/icons/version.svg?component'
|
|||||||
export { default as WikiIcon } from '@/assets/icons/wiki.svg?component'
|
export { default as WikiIcon } from '@/assets/icons/wiki.svg?component'
|
||||||
export { default as XIcon } from '@/assets/icons/x.svg?component'
|
export { default as XIcon } from '@/assets/icons/x.svg?component'
|
||||||
export { default as XCircleIcon } from '@/assets/icons/x-circle.svg?component'
|
export { default as XCircleIcon } from '@/assets/icons/x-circle.svg?component'
|
||||||
|
export { default as ZoomInIcon } from '@/assets/icons/zoom-in.svg?component'
|
||||||
|
export { default as ZoomOutIcon } from '@/assets/icons/zoom-out.svg?component'
|
||||||
|
|
||||||
// Editor Icons
|
// Editor Icons
|
||||||
export { default as BoldIcon } from '@/assets/icons/bold.svg?component'
|
export { default as BoldIcon } from '@/assets/icons/bold.svg?component'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "omorphia",
|
"name": "omorphia",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.6.2",
|
"version": "0.6.3",
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
@@ -30,15 +30,15 @@
|
|||||||
"@codemirror/language": "^6.9.1",
|
"@codemirror/language": "^6.9.1",
|
||||||
"@codemirror/state": "^6.3.0",
|
"@codemirror/state": "^6.3.0",
|
||||||
"@codemirror/view": "^6.21.3",
|
"@codemirror/view": "^6.21.3",
|
||||||
"chart.js": "^4.3.3",
|
"apexcharts": "^3.44.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"floating-vue": "^2.0.0-beta.20",
|
"floating-vue": "^2.0.0-beta.20",
|
||||||
"highlight.js": "^11.8.0",
|
"highlight.js": "^11.8.0",
|
||||||
"markdown-it": "^13.0.1",
|
"markdown-it": "^13.0.1",
|
||||||
"qrcode.vue": "^3.4.0",
|
"qrcode.vue": "^3.4.0",
|
||||||
"vue-chartjs": "^5.2.0",
|
|
||||||
"vue-router": "^4.2.1",
|
"vue-router": "^4.2.1",
|
||||||
"vue-select": "^4.0.0-beta.6",
|
"vue-select": "^4.0.0-beta.6",
|
||||||
|
"vue3-apexcharts": "^1.4.4",
|
||||||
"xss": "^1.0.14"
|
"xss": "^1.0.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
113
pnpm-lock.yaml
generated
113
pnpm-lock.yaml
generated
@@ -20,9 +20,9 @@ dependencies:
|
|||||||
'@codemirror/view':
|
'@codemirror/view':
|
||||||
specifier: ^6.21.3
|
specifier: ^6.21.3
|
||||||
version: 6.21.3
|
version: 6.21.3
|
||||||
chart.js:
|
apexcharts:
|
||||||
specifier: ^4.3.3
|
specifier: ^3.44.0
|
||||||
version: 4.3.3
|
version: 3.44.0
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.7
|
specifier: ^1.11.7
|
||||||
version: 1.11.7
|
version: 1.11.7
|
||||||
@@ -41,15 +41,15 @@ dependencies:
|
|||||||
vue:
|
vue:
|
||||||
specifier: ^3.3.4
|
specifier: ^3.3.4
|
||||||
version: 3.3.4
|
version: 3.3.4
|
||||||
vue-chartjs:
|
|
||||||
specifier: ^5.2.0
|
|
||||||
version: 5.2.0(chart.js@4.3.3)(vue@3.3.4)
|
|
||||||
vue-router:
|
vue-router:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(vue@3.3.4)
|
version: 4.2.1(vue@3.3.4)
|
||||||
vue-select:
|
vue-select:
|
||||||
specifier: ^4.0.0-beta.6
|
specifier: ^4.0.0-beta.6
|
||||||
version: 4.0.0-beta.6(vue@3.3.4)
|
version: 4.0.0-beta.6(vue@3.3.4)
|
||||||
|
vue3-apexcharts:
|
||||||
|
specifier: ^1.4.4
|
||||||
|
version: 1.4.4(apexcharts@3.44.0)(vue@3.3.4)
|
||||||
xss:
|
xss:
|
||||||
specifier: ^1.0.14
|
specifier: ^1.0.14
|
||||||
version: 1.0.14
|
version: 1.0.14
|
||||||
@@ -699,10 +699,6 @@ packages:
|
|||||||
'@jridgewell/sourcemap-codec': 1.4.14
|
'@jridgewell/sourcemap-codec': 1.4.14
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@kurkle/color@0.3.2:
|
|
||||||
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@lezer/common@1.1.0:
|
/@lezer/common@1.1.0:
|
||||||
resolution: {integrity: sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==}
|
resolution: {integrity: sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -1364,6 +1360,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
|
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@yr/monotone-cubic-spline@1.0.3:
|
||||||
|
resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/acorn-import-assertions@1.9.0(acorn@8.8.2):
|
/acorn-import-assertions@1.9.0(acorn@8.8.2):
|
||||||
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
|
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1446,6 +1446,18 @@ packages:
|
|||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/apexcharts@3.44.0:
|
||||||
|
resolution: {integrity: sha512-u7Xzrbcxc2yWznN78Jh5NMCYVAsWDfBjRl5ea++rVzFAqjU2hLz4RgKIFwYOBDRQtW1e/Qz8azJTqIJ1+Vu9Qg==}
|
||||||
|
dependencies:
|
||||||
|
'@yr/monotone-cubic-spline': 1.0.3
|
||||||
|
svg.draggable.js: 2.2.2
|
||||||
|
svg.easing.js: 2.0.0
|
||||||
|
svg.filter.js: 2.0.2
|
||||||
|
svg.pathmorphing.js: 0.1.3
|
||||||
|
svg.resize.js: 1.4.3
|
||||||
|
svg.select.js: 3.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/argparse@1.0.10:
|
/argparse@1.0.10:
|
||||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1529,13 +1541,6 @@ packages:
|
|||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/chart.js@4.3.3:
|
|
||||||
resolution: {integrity: sha512-aTk7pBw+x6sQYhon/NR3ikfUJuym/LdgpTlgZRe2PaEhjUMKBKyNaFCMVRAyTEWYFNO7qRu7iQVqOw/OqzxZxQ==}
|
|
||||||
engines: {pnpm: '>=7'}
|
|
||||||
dependencies:
|
|
||||||
'@kurkle/color': 0.3.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/chokidar@3.5.3:
|
/chokidar@3.5.3:
|
||||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||||
engines: {node: '>= 8.10.0'}
|
engines: {node: '>= 8.10.0'}
|
||||||
@@ -2784,6 +2789,60 @@ packages:
|
|||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/svg.draggable.js@2.2.2:
|
||||||
|
resolution: {integrity: sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.easing.js@2.0.0:
|
||||||
|
resolution: {integrity: sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.filter.js@2.0.2:
|
||||||
|
resolution: {integrity: sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.js@2.7.1:
|
||||||
|
resolution: {integrity: sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.pathmorphing.js@0.1.3:
|
||||||
|
resolution: {integrity: sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.resize.js@1.4.3:
|
||||||
|
resolution: {integrity: sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
svg.select.js: 2.1.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.select.js@2.1.2:
|
||||||
|
resolution: {integrity: sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/svg.select.js@3.0.1:
|
||||||
|
resolution: {integrity: sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
dependencies:
|
||||||
|
svg.js: 2.7.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/svgo@3.0.2:
|
/svgo@3.0.2:
|
||||||
resolution: {integrity: sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==}
|
resolution: {integrity: sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
@@ -3051,16 +3110,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vue-chartjs@5.2.0(chart.js@4.3.3)(vue@3.3.4):
|
|
||||||
resolution: {integrity: sha512-d3zpKmGZr2OWHQ1xmxBcAn5ShTG917+/UCLaSpaCDDqT0U7DBsvFzTs69ZnHCgKoXT55GZDW8YEj9Av+dlONLA==}
|
|
||||||
peerDependencies:
|
|
||||||
chart.js: ^4.1.1
|
|
||||||
vue: ^3.0.0-0 || ^2.7.0
|
|
||||||
dependencies:
|
|
||||||
chart.js: 4.3.3
|
|
||||||
vue: 3.3.4
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/vue-demi@0.14.5(vue@3.3.4):
|
/vue-demi@0.14.5(vue@3.3.4):
|
||||||
resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
|
resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -3138,6 +3187,16 @@ packages:
|
|||||||
typescript: 5.2.2
|
typescript: 5.2.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/vue3-apexcharts@1.4.4(apexcharts@3.44.0)(vue@3.3.4):
|
||||||
|
resolution: {integrity: sha512-TH89uZrxGjaDvkaYAISvj8+k6Bf1rUKFillc8oJirs5XZEPiwM1ELKZQ786wz0rfPqkSHHny2lqqUCK7Rw+LcQ==}
|
||||||
|
peerDependencies:
|
||||||
|
apexcharts: '> 3.0.0'
|
||||||
|
vue: '> 3.0.0'
|
||||||
|
dependencies:
|
||||||
|
apexcharts: 3.44.0
|
||||||
|
vue: 3.3.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/vue@3.3.4:
|
/vue@3.3.4:
|
||||||
resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
|
resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user