Skip to content

Commit

Permalink
feat: Add custom date picker to charts 2 (#611)
Browse files Browse the repository at this point in the history
  • Loading branch information
janmichek committed Jan 3, 2024
1 parent 8f94d04 commit 25f1b15
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 266 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"dependencies": {
"@aeternity/aepp-sdk": "^13.2.2",
"@download/blockies": "^1.0.3",
"@vuepic/vue-datepicker": "^7.1.0",
"@sentry/tracing": "^7.88.0",
"@sentry/vue": "^7.88.0",
"@vueuse/core": "^10.7.0",
Expand Down
62 changes: 45 additions & 17 deletions src/components/ChartControls.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
<template>
<div class="chart-controls">
<app-chip
v-for="(button, index) in buttons"
:key="index"
class="chart-controls__button"
:variant="selectedIndex === index ? 'error' : 'secondary'"
@click="select(index)">
{{ button.label }}
</app-chip>
<div>
<div class="chart-controls__container">
<app-chip
v-for="(button, index) in buttons"
:key="index"
class="chart-controls__button"
:variant="selectedIndex === index ? 'error' : 'secondary'"
@click="selectInterval(index)">
{{ button.label }}
</app-chip>
<range-picker
:is-active="selectedIndex === 'custom'"
:is-range-set="hasCustomDate"
@updated="selectRange"/>
</div>
</div>
</template>

<script setup>
import RangePicker from '@/components/RangePicker'
const buttons = [
{ interval: 'day', limit: '7', label: '1W' },
Expand All @@ -23,22 +30,43 @@ const buttons = [
const selectedIndex = ref(0)
function select(value) {
selectedIndex.value = value
emit('selected', buttons[value])
const hasCustomDate = computed(() => {
return selectedIndex.value === 'custom'
})
function selectInterval(index) {
selectedIndex.value = index
emit('selected', buttons[index])
}
function selectRange(dateRange) {
selectedIndex.value = 'custom'
const range = {
range: {
minStart: dateRange[0].toISOString().split('T')[0],
maxStart: dateRange[1].toISOString().split('T')[0],
},
}
emit('selected', range)
}
const emit = defineEmits(['selected'])
</script>

<style scoped>
.chart-controls {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
column-gap: 8px;
@media (--desktop) {
&__container {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
column-gap: 8px;
row-gap: 8px;
@media (--desktop) {
display: flex;
gap: 8px;
flex-grow: 1;
flex-wrap: nowrap;
}
}
&__button {
Expand Down
133 changes: 12 additions & 121 deletions src/components/ContractsChartPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,138 +5,42 @@
</template>
<template #header>
<chart-controls
class="contracts-chart-panel__chart-controls"
class="u-hidden-mobile"
@selected="loadContractsStatistics"/>
</template>

<div class="contracts-chart-panel__container">
<Line
:options="chartOptions"
:data="chartData"/>
<line-chart
v-if="contractsStatistics"
:statistics="contractsStatistics"
:selected-interval="selectedInterval"/>
</div>

<chart-controls
class="contracts-chart-panel__chart-controls--condensed"
class="contracts-chart-panel__controls u-hidden-desktop"
@selected="loadContractsStatistics"/>
</app-panel>
</template>

<script setup>
import { Line } from 'vue-chartjs'
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip,
} from 'chart.js'
import { storeToRefs } from 'pinia'
import { DateTime } from 'luxon'
import { useContractsStore } from '@/stores/contracts'
import LineChart from '@/components/LineChart'
const contractsStore = useContractsStore()
const {
contractsStatistics,
} = storeToRefs(contractsStore)
const { contractsStatistics } = storeToRefs(contractsStore)
const { fetchContractsStatistics } = contractsStore
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
)
ChartJS.defaults.font.family = 'Roboto Mono'
const chartData = computed(() => {
return {
labels: labels.value,
datasets: [{
data: stats.value,
label: null,
cubicInterpolationMode: 'monotone',
tension: 0.4,
borderColor: '#f5274e',
backgroundColor: '#f5274e',
pointRadius: 3,
pointHitRadius: 20,
}],
}
})
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
tooltip: {
tooltip: {
position: 'top',
},
callbacks: {
title: function(context) {
return context.label
},
},
},
},
scales: {
y: {
border: {
display: false,
},
},
x: {
grid: {
color: function() {
return 'transparent'
},
},
},
},
}
const selectedInterval = ref('')
await useAsyncData(async() => {
await fetchContractsStatistics()
return true
})
const stats = computed(() => {
return contractsStatistics.value?.map(stat => {
return stat.count
})
})
const labels = computed(() => {
return contractsStatistics.value?.map(stat => {
return formatLabel(stat.startDate)
})
})
function formatLabel(label) {
const date = DateTime.fromISO(label)
if (selectedInterval.value === 'month') {
return date.toFormat('yyyy-MM')
}
return date.toFormat('MM-dd')
}
async function loadContractsStatistics({ interval, limit }) {
async function loadContractsStatistics({ interval, limit, range }) {
selectedInterval.value = interval
await fetchContractsStatistics(`&limit=${parseInt(limit) + 1}&interval_by=${interval}`)
await fetchContractsStatistics(interval, limit, range)
}
</script>
Expand All @@ -148,21 +52,8 @@ async function loadContractsStatistics({ interval, limit }) {
height: 250px;
}
&__chart-controls {
display: none;
@media (--desktop) {
display: grid;
}
&--condensed {
margin-top: var(--space-4);
@media (--desktop) {
display: none;
}
}
&__controls {
margin-top: var(--space-4);
}
}
</style>
129 changes: 129 additions & 0 deletions src/components/LineChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<template>
<Line
:options="chartOptions"
:data="chartData"/>
</template>

<script setup>
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
PointElement,
Title,
Tooltip,
} from 'chart.js'
import { DateTime } from 'luxon'
import { Line } from 'vue-chartjs'
const props = defineProps({
statistics: {
type: Array,
required: true,
},
selectedInterval: {
type: String,
required: true,
},
})
const stats = computed(() => {
return props.statistics.map(stat => {
return stat.count
})
})
const labels = computed(() => {
return props.statistics.map(stat => {
return formatDate(stat.startDate)
})
})
function formatDate(label) {
const date = DateTime.fromISO(label)
if (props.selectedInterval === 'month') {
return date.toFormat('yyyy-MM')
}
return date.toFormat('MM-dd')
}
function formatNumberFractions(number) {
return number.toLocaleString('en-US', {
maximumFractionDigits: 2,
notation: 'compact',
compactDisplay: 'short',
})
}
const chartData = computed(() => {
return {
labels: labels.value,
datasets: [{
data: stats.value,
label: null,
cubicInterpolationMode: 'monotone',
tension: 0.4,
borderColor: '#f5274e',
backgroundColor: '#f5274e',
pointRadius: 3,
pointHitRadius: 20,
}],
}
})
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
tooltip: {
tooltip: {
position: 'top',
},
callbacks: {
title: function(context) {
return context.label
},
},
},
},
scales: {
y: {
border: {
display: false,
},
ticks: {
callback: function(value) {
return formatNumberFractions(value)
},
},
},
x: {
grid: {
color: function() {
return 'transparent'
},
},
},
},
}
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
)
ChartJS.defaults.font.family = 'Roboto Mono'
</script>

0 comments on commit 25f1b15

Please sign in to comment.