Files
tabler/preview/pages/charts.astro

199 lines
8.4 KiB
Plaintext

---
import DefaultLayout from '@shared/layouts/DefaultLayout.astro'
import Activity from '@shared/components/parts/charts/Activity.astro'
import SocialReferrals from '@shared/components/cards/charts/SocialReferrals.astro'
import Chart from '@components/demo/Chart.astro'
import Card from '@ui/Card.astro'
import CardHeader from '@ui/CardHeader.astro'
import CardBody from '@ui/CardBody.astro'
import CardTitle from '@ui/CardTitle.astro'
import CardSubtitle from '@ui/CardSubtitle.astro'
import chartsData from '@data/charts.json'
import { capitalize } from '@shared/lib/string-format'
import DocsLink from '@ui/DocsLink.astro'
import CaptureScript from '@shared/components/CaptureScript.astro'
import LegendList from '@ui/LegendList.astro'
import Legend from '@ui/Legend.astro'
type DemoChart = { name?: string; extend?: string; type?: string; series?: { name?: string; color?: string }[] }
const charts = chartsData as Record<string, DemoChart>
// Legend rules: one serie needs no legend, two to four series get a <Legend> list above the
// chart, and only circular charts or charts with five and more series keep the legend below.
const circular = ['pie', 'donut', 'radialBar', 'polarArea', 'radar']
function topLegend(chartId: string) {
const own = charts[chartId]
const chart = own?.extend ? { ...charts[own.extend], ...own } : own
const series = chart?.series ?? []
if (circular.includes(chart?.type ?? 'bar') || series.length < 2 || series.length > 4) return undefined
return series.map((serie) => ({ text: serie.name ?? '', color: serie.color ?? 'primary' }))
}
const third = 'col-md-6 col-lg-4'
const half = 'col-lg-6'
const wide = 'col-lg-8'
// Every chart is placed by hand, section by section and row by row (each row adds up to
// 12 columns). Charts with many points, several series or long labels get a wider column.
const sections: { title: string; description: string; charts: [chartId: string, col: string, subtitle: string][] }[] = [
{
title: 'Line charts',
description: 'Trends over time, where the change between points matters more than single values.',
charts: [
['completion-tasks-2', third, 'Tickets solved per day with a smooth curve, the default.'],
['completion-tasks-4', third, 'The same tickets drawn with straight segments.'],
['completion-tasks-5', third, 'A stepped line for values that change in jumps.'],
['completion-tasks-7', third, 'Tickets solved per day, labeled with values.'],
['tasks', wide, 'Issues opened, closed and reopened per day over the last 17 days.'],
['line', third, 'Monthly revenue of each plan, January to June.'],
['line-stroke', third, 'Monthly signups, dashed for paid and referral.'],
['spline', third, 'CPU load of web servers and workers in one day.'],
['temperature', half, 'Monthly average temperature in Tokyo and London.'],
['stepline', half, 'Number of running instances during the day.'],
],
},
{
title: 'Area charts',
description: 'Lines with a filled area, to stress volume or to show how parts add up to a total.',
charts: [
['completion-tasks-3', third, 'Tickets solved per day as a filled area.'],
['completion-tasks-10', third, 'Solved and reopened tickets as two overlapping areas.'],
['completion-tasks-11', third, 'Solved and reopened tickets stacked on top of each other.'],
['area', third, 'Monthly sessions on mobile and desktop.'],
['area-spline', third, 'Monthly egress and ingress traffic.'],
['area-spline-stacked', third, 'Storage used by media and backups, stacked.'],
],
},
{
title: 'Bar charts',
description: 'Comparison of separate categories, side by side or stacked.',
charts: [
['completion-tasks', third, 'Tickets solved per day, last week.'],
['completion-tasks-6', third, 'The same tickets as horizontal bars.'],
['completion-tasks-8', third, 'Solved and reopened tickets side by side.'],
['completion-tasks-9', third, 'Solved and reopened tickets in one stacked bar per day.'],
['cache-status', third, 'Cache status of requests per day, colored by meaning.'],
['funnel', third, 'Visitors left at each step from first visit to customer.'],
],
},
{
title: 'Circular charts',
description: 'Parts of a whole and progress toward a goal, best with a few values.',
charts: [
['demo-pie', third, 'Share of visits by source.'],
['campaigns', third, 'Delivery, open and click rates of one campaign.'],
['polar-area', third, 'Sales volume of each region.'],
],
},
{
title: 'Other charts',
description: 'Mixed series, distributions, schedules and hierarchies.',
charts: [
['combination', wide, 'Monthly spend as columns with leads and trials as lines.'],
['radar', third, 'Pro and Enterprise plans rated in six areas.'],
['scatter', third, 'Page load time samples on desktop and mobile.'],
['timeline', wide, 'Planned duration of each release phase.'],
['bubble', third, 'Search and social campaigns on three metrics.'],
['treemap', third, 'Disk space taken by each folder.'],
['box-plot', third, 'Spread of API response times in each month.'],
],
},
]
---
<DefaultLayout title="Charts" pageMenu="plugins.charts" pageLibs={['apexcharts']}>
<DocsLink slot="page-header-actions" path="/ui/plugins/chart" />
<div class="row row-cards">
<div class="col-lg-12">
<Activity />
</div>
<div class="col-12">
<Card>
<CardHeader title="Chart with legend" />
<CardBody>
<LegendList divided class="mb-3" id="legend-demo-list">
<Legend button size="lg" color="yellow" text="Total visits" value="63.0k" data-series="Total visits" />
<Legend button size="lg" color="green" text="Unique visitors" value="43.0k" data-series="Unique visitors" />
<Legend button size="lg" color="primary" text="New users" value="13.5k" data-series="New users" />
</LegendList>
<Chart chartId="legend-demo" height={15} label="Site traffic" />
<CaptureScript>
<!-- BEGIN SCRIPT OF LEGEND -->
<script is:inline>
/*
Toggles a chart series when its legend item is clicked.
The chart is exposed by the demo Chart component as window.tabler_chart['chart-legend-demo'].
*/
document.querySelectorAll('#legend-demo-list .legend').forEach((item) => {
item.addEventListener('click', () => {
const chart = window.tabler_chart && window.tabler_chart['chart-legend-demo']
if (!chart) return
chart.toggleSeries(item.dataset.series)
item.classList.toggle('legend-off')
})
})
</script>
<!-- END SCRIPT OF LEGEND -->
</CaptureScript>
</CardBody>
</Card>
</div>
<div class="col-12">
<SocialReferrals />
</div>
<div class="col-12">
<Card>
<CardHeader title="Sprint velocity" />
<CardBody>
<Chart chartId="tasks-overview" height={20} label="Story points completed per sprint" />
</CardBody>
</Card>
</div>
{
sections.map((section) => (
<Fragment>
<div class="col-12">
<h2 class="page-section-title">{section.title}</h2>
<p class="page-section-description">{section.description}</p>
</div>
{section.charts.map(([chartId, col, subtitle]) => (
<div class={col}>
<Card class="h-100">
<CardHeader>
<div>
<CardTitle as="h3">{charts[chartId]?.name ?? capitalize(chartId.replace(/-/g, ' '))}</CardTitle>
<CardSubtitle>{subtitle}</CardSubtitle>
</div>
</CardHeader>
<CardBody>
{topLegend(chartId) && (
<LegendList class="justify-content-end mb-3">
{topLegend(chartId)?.map((item) => (
<Legend color={item.color} text={item.text} />
))}
</LegendList>
)}
<Chart chartId={chartId} height={15} label={charts[chartId]?.name ?? capitalize(chartId.replace(/-/g, ' '))} legend={topLegend(chartId) ? false : undefined} />
</CardBody>
</Card>
</div>
))}
</Fragment>
))
}
</div>
</DefaultLayout>