diff --git a/.build/css-var-prefix.ts b/.build/css-var-prefix.ts index b7db896fa..85020287a 100644 --- a/.build/css-var-prefix.ts +++ b/.build/css-var-prefix.ts @@ -17,6 +17,7 @@ export const cssVarPrefix = 'tblr-' // foreign name. export const cssVarIgnore = [ /^--tblr-/, // already prefixed, e.g. names that cannot round-trip postcss (see $navbar-light-icon-color) + /^--apx-/, // apexcharts /^--bs-/, // bootstrap /^--fc-/, // fullcalendar /^--gl-/, // star-rating.js diff --git a/.changeset/advanced-charts-page.md b/.changeset/advanced-charts-page.md new file mode 100644 index 000000000..1fada1a3b --- /dev/null +++ b/.changeset/advanced-charts-page.md @@ -0,0 +1,6 @@ +--- +"@tabler/preview": minor +"@tabler/docs": minor +--- + +Added a `charts-advanced` page and docs for two y-axes, chart annotations, a zoom brush and synced chart groups. diff --git a/.changeset/apexcharts-license-note.md b/.changeset/apexcharts-license-note.md new file mode 100644 index 000000000..8103583f0 --- /dev/null +++ b/.changeset/apexcharts-license-note.md @@ -0,0 +1,6 @@ +--- +"@tabler/core": patch +"@tabler/docs": patch +--- + +Documented the ApexCharts dual license, which applies to the copy shipped in `dist/libs`, in the readme and chart docs. diff --git a/.changeset/chart-palette-and-tokens.md b/.changeset/chart-palette-and-tokens.md new file mode 100644 index 000000000..52380596b --- /dev/null +++ b/.changeset/chart-palette-and-tokens.md @@ -0,0 +1,7 @@ +--- +"@tabler/core": minor +"@tabler/preview": patch +"@tabler/docs": patch +--- + +Added a `--tblr-chart-1` … `--tblr-chart-5` palette and wired ApexCharts theme tokens, so every chart follows the color mode. diff --git a/.changeset/clean-dead-chart-keys.md b/.changeset/clean-dead-chart-keys.md new file mode 100644 index 000000000..f42c5a1ce --- /dev/null +++ b/.changeset/clean-dead-chart-keys.md @@ -0,0 +1,5 @@ +--- +"@tabler/preview": patch +--- + +Removed dead chart options (`groups`, `spline`, `fill`, `debug`, `remove-padding`, `show-labels`) from `charts.json`. diff --git a/.changeset/fix-combination-chart.md b/.changeset/fix-combination-chart.md new file mode 100644 index 000000000..b94d96652 --- /dev/null +++ b/.changeset/fix-combination-chart.md @@ -0,0 +1,5 @@ +--- +"@tabler/preview": patch +--- + +Fixed the combination chart demo so it mixes columns and lines instead of drawing plain bars. diff --git a/.changeset/fix-dark-mode-chart-colors.md b/.changeset/fix-dark-mode-chart-colors.md new file mode 100644 index 000000000..1cdd0e244 --- /dev/null +++ b/.changeset/fix-dark-mode-chart-colors.md @@ -0,0 +1,7 @@ +--- +"@tabler/core": patch +"@tabler/preview": patch +"@tabler/docs": patch +--- + +Fixed chart colors in dark mode: axis lines and ticks, marker and treemap outlines, and the tooltip title. diff --git a/.changeset/fix-docs-chart-id-collision.md b/.changeset/fix-docs-chart-id-collision.md new file mode 100644 index 000000000..7ec662876 --- /dev/null +++ b/.changeset/fix-docs-chart-id-collision.md @@ -0,0 +1,5 @@ +--- +"@tabler/docs": patch +--- + +Fixed the small chart example on the chart docs page, which shared an element id with the line chart example and stayed empty. diff --git a/.changeset/new-chart-types.md b/.changeset/new-chart-types.md new file mode 100644 index 000000000..523665280 --- /dev/null +++ b/.changeset/new-chart-types.md @@ -0,0 +1,6 @@ +--- +"@tabler/preview": minor +"@tabler/docs": minor +--- + +Added radar, polar area, treemap, timeline, box plot, bubble and funnel chart types to the charts preview and docs. diff --git a/.changeset/realistic-chart-demo-data.md b/.changeset/realistic-chart-demo-data.md new file mode 100644 index 000000000..f5e1a6bd8 --- /dev/null +++ b/.changeset/realistic-chart-demo-data.md @@ -0,0 +1,6 @@ +--- +"@tabler/preview": patch +"@tabler/docs": patch +--- + +Replaced the placeholder chart data on the charts page and in the chart docs with realistic series, and titled every demo card. diff --git a/.changeset/straight-line-chart-demos.md b/.changeset/straight-line-chart-demos.md new file mode 100644 index 000000000..db217d2ea --- /dev/null +++ b/.changeset/straight-line-chart-demos.md @@ -0,0 +1,5 @@ +--- +"@tabler/preview": minor +--- + +Added a straight `line` chart demo and set `stroke-curve` to straight on the line and area demos, so the spline ones differ. diff --git a/README.md b/README.md index 6ae4f3174..e94d32d5c 100644 --- a/README.md +++ b/README.md @@ -208,3 +208,10 @@ Stay up to date by joining our community on [X](https://x.com/tabler_io) and [Fa ## 📄 License Tabler is licensed under the [MIT License](LICENSE). + +Third-party libraries shipped in `dist/libs` keep their own licenses. One of them needs +attention: **ApexCharts is not MIT from version 5 on**. It is dual-licensed - free under +its Community license for organizations under $2M in annual revenue, and paid above that +threshold, with a separate OEM license for redistribution. Check the +[ApexCharts license options](https://apexcharts.com/license/) before you ship charts in a +commercial product. diff --git a/core/README.md b/core/README.md index 8e4501ac4..f48ebaf5a 100644 --- a/core/README.md +++ b/core/README.md @@ -94,3 +94,10 @@ We welcome contributions of all kinds! See the [contributing guide](https://gith ## 📄 License Tabler is licensed under the [MIT License](https://github.com/tabler/tabler/blob/dev/LICENSE). + +Third-party libraries shipped in `dist/libs` keep their own licenses. One of them needs +attention: **ApexCharts is not MIT from version 5 on**. It is dual-licensed - free under +its Community license for organizations under $2M in annual revenue, and paid above that +threshold, with a separate OEM license for redistribution. Check the +[ApexCharts license options](https://apexcharts.com/license/) before you ship charts in a +commercial product. diff --git a/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap b/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap index a6e852438..b760fdf5f 100644 --- a/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap +++ b/core/scss/tests/__snapshots__/css-var-prefix.test.mjs.snap @@ -2,6 +2,15 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and prefixes everything else 1`] = ` [ + "--apx-accent", + "--apx-fore", + "--apx-grid", + "--apx-series-1", + "--apx-series-2", + "--apx-series-3", + "--apx-series-4", + "--apx-series-5", + "--apx-tt-color-muted", "--fc-border-color", "--fc-daygrid-event-dot-width", "--fc-event-bg-color", @@ -25,6 +34,7 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre "--litepicker-month-weekday-color", "--plyr-color-main", "--tblr-active-bg", + "--tblr-azure", "--tblr-backdrop-bg", "--tblr-bg-forms", "--tblr-bg-surface", @@ -38,6 +48,11 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre "--tblr-border-style", "--tblr-border-width", "--tblr-card-bg", + "--tblr-chart-1", + "--tblr-chart-2", + "--tblr-chart-3", + "--tblr-chart-4", + "--tblr-chart-5", "--tblr-font-sans-serif", "--tblr-font-size-h3", "--tblr-font-size-h5", @@ -46,12 +61,15 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre "--tblr-form-select-bg-icon", "--tblr-form-select-bg-img", "--tblr-gray-500", + "--tblr-green", "--tblr-icon-size", "--tblr-info", "--tblr-light", + "--tblr-orange", "--tblr-primary", "--tblr-primary-200", "--tblr-primary-lt", + "--tblr-purple", "--tblr-secondary", "--tblr-secondary-bg", "--tblr-shadow-card", diff --git a/core/scss/vendor/_apexcharts.scss b/core/scss/vendor/_apexcharts.scss index 899de4650..1e9fcd990 100644 --- a/core/scss/vendor/_apexcharts.scss +++ b/core/scss/vendor/_apexcharts.scss @@ -1,10 +1,41 @@ @use '../config' as *; +// ApexCharts reads these tokens from the chart element's computed style (theme.tokens, +// on by default since v6), so the library themes itself — including charts an app builds +// on its own, without going through Tabler's chart helpers. +// +// The palette is the public part: override --tblr-chart-1 … --tblr-chart-5 to recolor +// every chart at once, the same way --tblr-primary recolors the rest of the interface. +:root { + --chart-1: var(--primary); + --chart-2: var(--green); + --chart-3: var(--azure); + --chart-4: var(--purple); + --chart-5: var(--orange); + --apx-accent: var(--chart-1); + --apx-fore: var(--secondary); + --apx-grid: var(--border-color); + // No --apx-surface on purpose: it makes ApexCharts paint a solid background behind the + // plot, which would cover the card underneath — tinted and gradient cards included. + --apx-series-1: var(--chart-1); + --apx-series-2: var(--chart-2); + --apx-series-3: var(--chart-3); + --apx-series-4: var(--chart-4); + --apx-series-5: var(--chart-5); +} + .apexcharts-tooltip { + // ApexCharts paints the tooltip title and other muted text from this variable, and its + // default is a dark gray that disappears on the inverted Tabler tooltip surface. + // !important because ApexCharts injects its own stylesheet at runtime, after this one, + // and its default lands on the same selector. + --apx-tt-color-muted: #{$tooltip-color} !important; + padding: 0.25rem !important; font-size: $tooltip-font-size !important; color: $tooltip-color !important; background: $tooltip-bg !important; + border: 0 !important; box-shadow: none !important; } @@ -14,6 +45,7 @@ font-weight: var(--font-weight-semibold); background: transparent !important; border: 0 !important; + opacity: 0.7; } .apexcharts-tooltip-y-group { @@ -28,10 +60,21 @@ font-size: 16px !important; } -.apexcharts-gridline { +.apexcharts-gridline, +.apexcharts-grid-borders line, +.apexcharts-xaxis-tick, +.apexcharts-yaxis-tick { stroke: var(--border-color) !important; } +// ApexCharts outlines markers, treemap cells and data label pills in white, so they +// separate from the plot. On a dark background that outline is the thing that stands out. +.apexcharts-marker, +.apexcharts-treemap-rect, +.apexcharts-data-labels rect { + stroke: var(--bg-surface) !important; +} + .apexcharts-legend-text { color: inherit !important; } diff --git a/docs/content/ui/plugins/chart.mdx b/docs/content/ui/plugins/chart.mdx index f5a221b9c..f66263ed6 100644 --- a/docs/content/ui/plugins/chart.mdx +++ b/docs/content/ui/plugins/chart.mdx @@ -35,6 +35,12 @@ ApexCharts draws with its own default colors, grid and tooltip. Tabler restyles +### License + +Tabler is MIT licensed, but ApexCharts is not. From version 5 on it is dual-licensed: free under its Community license for organizations under $2 million in annual revenue, paid above that, with a separate OEM license for redistributing it inside a product you ship to others. + +Tabler bundles the built file in `dist/libs` so the examples work out of the box, but the license stays with ApexCharts. Read the [ApexCharts license options](https://apexcharts.com/license/) before you use charts in a commercial product. + ## Usage Add an empty element with the `chart` class, then pass it to ApexCharts. The class reserves a minimum height, so the card does not jump while the chart is loading. @@ -75,7 +81,7 @@ The size classes below reserve space before the chart renders, so the layout doe
- +
@@ -92,6 +98,56 @@ A sparkline is a small chart with no axes, grid or tooltip, meant to sit inline Add `chart-sparkline-sm` for a shorter sparkline, `chart-sparkline-square` for a pie or radial one, and `chart-sparkline-wide` when the default width is too narrow. +### Colors + +Tabler ships a five-color chart palette. Charts pick colors from it in order, so a chart with three series is colored without naming a single color. + +| Variable | Default | +| --- | --- | +| `--tblr-chart-1` | `--tblr-primary` | +| `--tblr-chart-2` | `--tblr-green` | +| `--tblr-chart-3` | `--tblr-azure` | +| `--tblr-chart-4` | `--tblr-purple` | +| `--tblr-chart-5` | `--tblr-orange` | + +Override them to recolor every chart at once, the same way `--tblr-primary` recolors the rest of the interface: + +```css +:root { + --tblr-chart-1: #7048e8; + --tblr-chart-2: #f76707; +} +``` + +To color one series, pass the color in the ApexCharts config as usual: + +```js +new ApexCharts(element, { + colors: ['var(--tblr-chart-2)'], + // ... +}).render(); +``` + +### Theme tokens + +ApexCharts reads its own design tokens from the chart element, and Tabler sets them to its theme colors. Text, gridlines and the chart surface follow the color mode on their own - including charts you build yourself, without any Tabler helper. + +| Token | Used for | Tabler value | +| --- | --- | --- | +| `--apx-fore` | labels, axis titles, legend | `--tblr-secondary` | +| `--apx-grid` | gridlines and axis lines | `--tblr-border-color` | +| `--apx-surface` | chart background | `--tblr-bg-surface` | +| `--apx-accent` | single-series color | `--tblr-chart-1` | +| `--apx-series-1` … `--apx-series-5` | multi-series palette | `--tblr-chart-1` … `--tblr-chart-5` | + +Set a token on a single card to change only that chart: + +```css +.card-dark-chart { + --apx-grid: rgba(255, 255, 255, 0.1); +} +``` + ## Chart types See the [ApexCharts documentation](https://apexcharts.com/docs/) for the full list of options behind each of these. @@ -151,7 +207,91 @@ Heatmaps provide a graphical representation of data where individual values are
- + +
+
+
+ +### Radar chart + +Radar charts compare a few series across the same set of categories. They work best for scores and ratings, where every axis uses the same scale. Set `chart.type` to `radar` and pass the axis names in `xaxis.categories`: + + +
+
+ +
+
+
+ +### Polar area chart + +A polar area chart is a pie chart where each slice keeps the same angle and grows outwards with its value. Use it when the parts of a whole differ a lot in size. Set `chart.type` to `polarArea` and pass plain numbers in `series`: + + +
+
+ +
+
+
+ +### Treemap chart + +Treemaps show parts of a whole as blocks. The bigger the value, the bigger the block, so they fit storage, budgets and other breakdowns with many entries. Set `chart.type` to `treemap` and pass `{ x, y }` points, where `x` is the label: + + +
+
+ +
+
+
+ +### Timeline chart + +A timeline puts one bar per row between a start and an end date. Use it for roadmaps, releases and schedules. Set `chart.type` to `rangeBar`, turn on `plotOptions.bar.horizontal`, set `xaxis.type` to `datetime` and pass `y` as a `[start, end]` pair of timestamps: + + +
+
+ +
+
+
+ +### Box plot chart + +Box plots show how values spread out, not just their average. Each box covers the middle half of the data, the line inside it is the median, and the whiskers reach the lowest and highest values. Set `chart.type` to `boxPlot` and pass `y` as `[min, q1, median, q3, max]`: + + +
+
+ +
+
+
+ +### Bubble chart + +Bubble charts add a third value to a scatter plot: the size of the point. Set `chart.type` to `bubble` and pass `{ x, y, z }` points, where `z` is the bubble size: + + +
+
+ +
+
+
+ +### Funnel chart + +A funnel shows how many items are left at each step of a process. It is a horizontal bar chart with `plotOptions.bar.isFunnel` turned on. Turn on `distributed` as well, so every stage gets its own color, and keep the legend on, because a funnel hides the y-axis labels: + + +
+
+
@@ -168,6 +308,71 @@ For more complex data visualizations, you can create advanced charts with multip +## Axes, annotations and zoom + +### Two y-axes + +Series with different units need their own scale. Pass an array to `yaxis`, bind each entry to a serie with `seriesName`, and set `opposite` on the second one to move it to the right side. + + +
+
+ +
+
+
+ +Mixing shapes works the same way: give a serie its own `type` (`column`, `line`, `area`) and ApexCharts draws that serie differently from the rest. + +### Annotations + +Annotations draw a line across the plot. Use `annotations.yaxis` for a target or a limit, and `annotations.xaxis` for a moment in time, like a release or a campaign. + + +
+
+ +
+
+
+ +Each annotation takes a value, a `borderColor` and an optional `label`. On a category axis the value is the category name, on a datetime axis it is a timestamp. + + +
+
+ +
+
+
+ +### Brush and zoom + +A brush is a small chart that picks the range of a bigger one. Give the main chart an `id`, then point the small one at it with `chart.brush`, and set the starting range in `chart.selection`. Render the main chart first - the brush looks its target up by id. + + +
+
+ + +
+
+
+ +### Synced charts + +Charts that share a `chart.group` name move together. Hover one and the others show the same point, zoom one and the others follow. Every chart in the group needs its own `chart.id` and the same x values. + + +
+
+ + + +
+
+
+ ## Legend key ApexCharts draws its own legend, but you can also build a plain-HTML legend next to a chart's title — for example to label the series above the chart instead of below it. Add a `legend` span before each label and color it with a `bg-*` utility class. diff --git a/preview/pages/charts-advanced.astro b/preview/pages/charts-advanced.astro new file mode 100644 index 000000000..a4a2aa83d --- /dev/null +++ b/preview/pages/charts-advanced.astro @@ -0,0 +1,68 @@ +--- +import DefaultLayout from '@shared/layouts/DefaultLayout.astro' +import Chart from '@components/demo/Chart.astro' +import Card from '@ui/Card.astro' +import CardBody from '@ui/CardBody.astro' +import CardTitle from '@ui/CardTitle.astro' +import CardSubtitle from '@ui/CardSubtitle.astro' +import DocsLink from '@ui/DocsLink.astro' +--- + + + + +
+
+ + + Two y-axes + Plot values with different units together. Bind each axis to a serie with seriesName and move the second one to the right with opposite. + + + +
+ +
+ + + Threshold line + Draw a target or a limit across the plot with annotations.yaxis, so a reader sees at a glance which points miss it. + + + +
+ +
+ + + Marker lines + Mark the moment something happened with annotations.xaxis — a release, a campaign, an incident. + + + +
+ +
+ + + Brush and zoom + The small chart below picks the range shown above. Point it at the main chart id with chart.brush and render the main chart first. + + + + +
+ +
+ + + Synced charts + Charts that share a chart.group name follow one another — hover or zoom on one and the rest do the same. + + + + + +
+
+
diff --git a/preview/pages/charts.astro b/preview/pages/charts.astro index 319726f85..6a90dcebf 100644 --- a/preview/pages/charts.astro +++ b/preview/pages/charts.astro @@ -26,8 +26,9 @@ const demoCharts = Object.entries(chartsData as Record + - + diff --git a/shared/components/demo/Chart.astro b/shared/components/demo/Chart.astro index c9086c724..6a096d11d 100644 --- a/shared/components/demo/Chart.astro +++ b/shared/components/demo/Chart.astro @@ -51,7 +51,7 @@ const elementId = `chart-${id}`;