mirror of
https://github.com/hunvreus/basecoat.git
synced 2026-11-11 04:38:18 +00:00
Expand chart examples and derived surfaces
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
import ChartExample from "../site/ChartExample.astro"
|
||||
import ChartExamples from "../site/ChartExamples.astro"
|
||||
|
||||
# Chart
|
||||
|
||||
<Callout type="warning" title="Alpha API" icon="triangle-alert">
|
||||
Chart support is alpha. The JavaScript API, generated markup, and option names may change before the stable 1.0 release.
|
||||
</Callout>
|
||||
|
||||
Use Chart.js with Basecoat defaults for themed colors, external tooltips, and optional generated legends.
|
||||
|
||||
<ChartExample />
|
||||
@@ -9,7 +14,7 @@ Use Chart.js with Basecoat defaults for themed colors, external tooltips, and op
|
||||
Chart is an optional JavaScript helper. Load Chart.js first, then `basecoat.js`, then `chart.js`.
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0-beta.2/dist/js/basecoat.min.js" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1.0.0-beta.2/dist/js/chart.min.js" defer></script>
|
||||
```
|
||||
@@ -45,22 +50,6 @@ Chart is an optional JavaScript helper. Load Chart.js first, then `basecoat.js`,
|
||||
|
||||
Charts default to `aspect-video`. Use a height, `min-h-*`, or `aspect-*` utility on a parent element when you need a different measuring box.
|
||||
|
||||
## Card Composition
|
||||
|
||||
Chart does not own titles, descriptions, or framing. Compose those with Card or your own markup.
|
||||
|
||||
```html
|
||||
<div class="card">
|
||||
<header>
|
||||
<h2>Bar Chart - Multiple</h2>
|
||||
<p>Showing total visitors for the last 6 months</p>
|
||||
</header>
|
||||
<section>
|
||||
<canvas id="visitors-chart" aria-label="Monthly visitors"></canvas>
|
||||
</section>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Legend
|
||||
|
||||
Set `legend: true` to generate a Basecoat-styled legend after the canvas.
|
||||
@@ -90,7 +79,9 @@ window.basecoat.chart("#revenue-chart", {
|
||||
recurring: {
|
||||
label: "Recurring",
|
||||
color: "var(--chart-1)",
|
||||
surface: "gradient",
|
||||
dataset: {
|
||||
fill: true,
|
||||
tension: 0.35,
|
||||
},
|
||||
},
|
||||
@@ -155,6 +146,10 @@ window.basecoat.chart("#custom-chart", {
|
||||
|
||||
`basecoat.chart()` returns the Chart.js instance for single targets and an array of instances for multi-target selectors.
|
||||
|
||||
## Examples
|
||||
|
||||
<ChartExamples />
|
||||
|
||||
## API
|
||||
|
||||
| Option | Default | Description |
|
||||
@@ -168,3 +163,12 @@ window.basecoat.chart("#custom-chart", {
|
||||
| `options` | `{}` | Raw Chart.js options. |
|
||||
| `plugins` | `[]` | Raw Chart.js plugins. |
|
||||
| `chartData` | `undefined` | Complete Chart.js data object. Overrides the data mapper. |
|
||||
|
||||
### Series options
|
||||
|
||||
| Option | Description |
|
||||
| --- | --- |
|
||||
| `label` | Display label for legends and tooltips. |
|
||||
| `color` | Base color for the series stroke, fill, legend marker, and tooltip marker. |
|
||||
| `surface` | Derives a fill from `color`. Use `true` for a translucent fill, `"gradient"` for an upstream-style vertical fade, or `{ from, to }` for custom opacity stops. |
|
||||
| `dataset` | Raw Chart.js dataset options. |
|
||||
|
||||
@@ -1,65 +1,255 @@
|
||||
---
|
||||
import { Preview } from "reallysimpledocs/components";
|
||||
|
||||
const code = `<div class="card">
|
||||
<header>
|
||||
<h2>Bar Chart - Multiple</h2>
|
||||
<p>Showing total visitors for the last 6 months</p>
|
||||
</header>
|
||||
<section>
|
||||
<canvas id="chart-example-visitors" aria-label="Monthly visitors by device"></canvas>
|
||||
</section>
|
||||
const code = `<div>
|
||||
<h2>Area Chart - Interactive</h2>
|
||||
<p>Showing total visitors for the last 3 months</p>
|
||||
<div class="h-[250px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="visitors-chart" aria-label="Visitors by device"></canvas>
|
||||
</div>
|
||||
</div>`;
|
||||
---
|
||||
|
||||
<Preview class="w-full" code={code}>
|
||||
<div class="card w-full">
|
||||
<header>
|
||||
<h2>Bar Chart - Multiple</h2>
|
||||
<p>Showing total visitors for the last 6 months</p>
|
||||
</header>
|
||||
<section>
|
||||
<canvas id="chart-example-visitors" aria-label="Monthly visitors by device"></canvas>
|
||||
</section>
|
||||
<div class="w-full">
|
||||
<div class="mb-4">
|
||||
<h2 class="text-base font-medium">Area Chart - Interactive</h2>
|
||||
<p class="text-muted-foreground text-sm">Showing total visitors for the last 3 months</p>
|
||||
</div>
|
||||
<div class="h-[250px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-overview" aria-label="Visitors by device"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</Preview>
|
||||
|
||||
<script is:inline src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script is:inline src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.min.js"></script>
|
||||
<script>
|
||||
import "../../../src/js/basecoat.js";
|
||||
import "../../../src/js/chart.js";
|
||||
|
||||
const initChartExample = () => {
|
||||
const canvas = document.getElementById("chart-example-visitors");
|
||||
if (!canvas || !window.Chart || !window.basecoat?.chart || canvas.dataset.chartInitialized) return;
|
||||
const visitorsByDay = [
|
||||
{ date: "Apr 1", desktop: 222, mobile: 150 },
|
||||
{ date: "Apr 5", desktop: 373, mobile: 290 },
|
||||
{ date: "Apr 9", desktop: 59, mobile: 110 },
|
||||
{ date: "Apr 13", desktop: 342, mobile: 380 },
|
||||
{ date: "Apr 17", desktop: 446, mobile: 360 },
|
||||
{ date: "Apr 21", desktop: 137, mobile: 200 },
|
||||
{ date: "Apr 25", desktop: 215, mobile: 250 },
|
||||
{ date: "Apr 29", desktop: 315, mobile: 240 },
|
||||
{ date: "May 3", desktop: 247, mobile: 190 },
|
||||
{ date: "May 7", desktop: 388, mobile: 300 },
|
||||
{ date: "May 11", desktop: 335, mobile: 270 },
|
||||
{ date: "May 15", desktop: 473, mobile: 380 },
|
||||
{ date: "May 19", desktop: 235, mobile: 180 },
|
||||
{ date: "May 23", desktop: 252, mobile: 290 },
|
||||
{ date: "May 27", desktop: 420, mobile: 460 },
|
||||
{ date: "May 31", desktop: 178, mobile: 230 },
|
||||
{ date: "Jun 4", desktop: 439, mobile: 380 },
|
||||
{ date: "Jun 8", desktop: 385, mobile: 320 },
|
||||
{ date: "Jun 12", desktop: 492, mobile: 420 },
|
||||
{ date: "Jun 16", desktop: 371, mobile: 310 },
|
||||
{ date: "Jun 20", desktop: 408, mobile: 450 },
|
||||
{ date: "Jun 24", desktop: 132, mobile: 180 },
|
||||
{ date: "Jun 28", desktop: 149, mobile: 200 },
|
||||
];
|
||||
|
||||
window.basecoat.chart(canvas, {
|
||||
const monthlyVisitors = [
|
||||
{ month: "Jan", desktop: 186, mobile: 80 },
|
||||
{ month: "Feb", desktop: 305, mobile: 200 },
|
||||
{ month: "Mar", desktop: 237, mobile: 120 },
|
||||
{ month: "Apr", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "Jun", desktop: 214, mobile: 140 },
|
||||
];
|
||||
|
||||
const defaultScales = {
|
||||
y: { beginAtZero: true },
|
||||
x: { grid: { display: false } },
|
||||
};
|
||||
|
||||
const initChart = (id, config) => {
|
||||
const canvas = document.getElementById(id);
|
||||
if (!canvas || canvas.dataset.chartInitialized) return;
|
||||
window.basecoat.chart(canvas, config);
|
||||
};
|
||||
|
||||
const initChartExamples = () => {
|
||||
if (!window.Chart || !window.basecoat?.chart) return;
|
||||
|
||||
initChart("chart-example-overview", {
|
||||
type: "line",
|
||||
labelKey: "date",
|
||||
legend: true,
|
||||
data: visitorsByDay,
|
||||
series: {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-2)",
|
||||
surface: "gradient",
|
||||
dataset: {
|
||||
borderWidth: 1.5,
|
||||
fill: true,
|
||||
tension: 0.35,
|
||||
pointRadius: 0,
|
||||
},
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-1)",
|
||||
surface: "gradient",
|
||||
dataset: {
|
||||
borderWidth: 1.5,
|
||||
fill: true,
|
||||
tension: 0.35,
|
||||
pointRadius: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
options: {
|
||||
interaction: { mode: "index", intersect: false },
|
||||
scales: {
|
||||
x: { grid: { display: false }, ticks: { maxTicksLimit: 6 } },
|
||||
y: { beginAtZero: true, stacked: true, ticks: { display: false } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
initChart("chart-example-visitors", {
|
||||
type: "bar",
|
||||
labelKey: "month",
|
||||
legend: true,
|
||||
data: [
|
||||
{ month: "Jan", desktop: 186, mobile: 80 },
|
||||
{ month: "Feb", desktop: 305, mobile: 200 },
|
||||
{ month: "Mar", desktop: 237, mobile: 120 },
|
||||
{ month: "Apr", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "Jun", desktop: 214, mobile: 140 },
|
||||
],
|
||||
data: monthlyVisitors,
|
||||
series: {
|
||||
desktop: { label: "Desktop", color: "var(--chart-1)" },
|
||||
mobile: { label: "Mobile", color: "var(--chart-2)" },
|
||||
},
|
||||
options: { scales: defaultScales },
|
||||
});
|
||||
|
||||
initChart("chart-example-line", {
|
||||
type: "line",
|
||||
labelKey: "month",
|
||||
data: [
|
||||
{ month: "Jan", revenue: 42 },
|
||||
{ month: "Feb", revenue: 68 },
|
||||
{ month: "Mar", revenue: 61 },
|
||||
{ month: "Apr", revenue: 90 },
|
||||
{ month: "May", revenue: 112 },
|
||||
{ month: "Jun", revenue: 128 },
|
||||
],
|
||||
series: {
|
||||
revenue: {
|
||||
label: "Revenue",
|
||||
color: "var(--chart-1)",
|
||||
dataset: { tension: 0, pointRadius: 3, pointHoverRadius: 5 },
|
||||
},
|
||||
},
|
||||
options: { scales: defaultScales },
|
||||
});
|
||||
|
||||
initChart("chart-example-step", {
|
||||
type: "line",
|
||||
labelKey: "day",
|
||||
data: [
|
||||
{ day: "Mon", queued: 12 },
|
||||
{ day: "Tue", queued: 18 },
|
||||
{ day: "Wed", queued: 9 },
|
||||
{ day: "Thu", queued: 24 },
|
||||
{ day: "Fri", queued: 16 },
|
||||
{ day: "Sat", queued: 14 },
|
||||
],
|
||||
series: {
|
||||
queued: {
|
||||
label: "Queued",
|
||||
color: "var(--chart-3)",
|
||||
dataset: { stepped: true, pointRadius: 3 },
|
||||
},
|
||||
},
|
||||
options: { scales: defaultScales },
|
||||
});
|
||||
|
||||
initChart("chart-example-stacked", {
|
||||
type: "bar",
|
||||
labelKey: "quarter",
|
||||
legend: true,
|
||||
data: [
|
||||
{ quarter: "Q1", won: 32, open: 44, lost: 12 },
|
||||
{ quarter: "Q2", won: 48, open: 38, lost: 18 },
|
||||
{ quarter: "Q3", won: 52, open: 46, lost: 16 },
|
||||
{ quarter: "Q4", won: 61, open: 40, lost: 14 },
|
||||
],
|
||||
series: {
|
||||
won: { label: "Won", color: "var(--chart-1)" },
|
||||
open: { label: "Open", color: "var(--chart-2)" },
|
||||
lost: { label: "Lost", color: "var(--chart-5)" },
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: { beginAtZero: true },
|
||||
x: { grid: { display: false } },
|
||||
x: { stacked: true, grid: { display: false } },
|
||||
y: { stacked: true, beginAtZero: true, ticks: { display: false } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
initChart("chart-example-donut", {
|
||||
type: "doughnut",
|
||||
labelKey: "source",
|
||||
legend: true,
|
||||
data: [
|
||||
{ source: "Search", visitors: 275, color: "var(--chart-1)" },
|
||||
{ source: "Direct", visitors: 200, color: "var(--chart-2)" },
|
||||
{ source: "Social", visitors: 187, color: "var(--chart-3)" },
|
||||
{ source: "Referral", visitors: 173, color: "var(--chart-4)" },
|
||||
{ source: "Email", visitors: 90, color: "var(--chart-5)" },
|
||||
],
|
||||
series: {
|
||||
visitors: { label: "Visitors" },
|
||||
},
|
||||
options: {
|
||||
cutout: "62%",
|
||||
},
|
||||
});
|
||||
|
||||
initChart("chart-example-radar", {
|
||||
type: "radar",
|
||||
labelKey: "channel",
|
||||
legend: true,
|
||||
data: [
|
||||
{ channel: "Acquisition", current: 82, previous: 64 },
|
||||
{ channel: "Activation", current: 72, previous: 70 },
|
||||
{ channel: "Retention", current: 66, previous: 58 },
|
||||
{ channel: "Revenue", current: 88, previous: 75 },
|
||||
{ channel: "Referral", current: 61, previous: 52 },
|
||||
],
|
||||
series: {
|
||||
current: {
|
||||
label: "Current",
|
||||
color: "var(--chart-1)",
|
||||
surface: { from: 0.22 },
|
||||
},
|
||||
previous: {
|
||||
label: "Previous",
|
||||
color: "var(--chart-2)",
|
||||
surface: { from: 0.18 },
|
||||
},
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
r: {
|
||||
beginAtZero: true,
|
||||
grid: { color: "color-mix(in oklab, var(--border) 60%, transparent)" },
|
||||
angleLines: { color: "color-mix(in oklab, var(--border) 60%, transparent)" },
|
||||
pointLabels: { color: "var(--muted-foreground)" },
|
||||
ticks: { display: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initChartExample, { once: true });
|
||||
document.addEventListener("DOMContentLoaded", initChartExamples, { once: true });
|
||||
} else {
|
||||
initChartExample();
|
||||
initChartExamples();
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
---
|
||||
import { Preview } from "reallysimpledocs/components";
|
||||
|
||||
const barCode = `<div class="h-[220px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="visitors-chart" aria-label="Monthly visitors by device"></canvas>
|
||||
</div>`;
|
||||
|
||||
const lineCode = `<div class="h-[220px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="revenue-chart" aria-label="Revenue line chart"></canvas>
|
||||
</div>`;
|
||||
|
||||
const stepCode = `<div class="h-[220px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="queue-chart" aria-label="Support queue step chart"></canvas>
|
||||
</div>`;
|
||||
|
||||
const stackedCode = `<div class="h-[220px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="pipeline-chart" aria-label="Stacked pipeline bar chart"></canvas>
|
||||
</div>`;
|
||||
|
||||
const donutCode = `<div class="h-[220px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="traffic-chart" aria-label="Traffic source donut chart"></canvas>
|
||||
</div>`;
|
||||
|
||||
const radarCode = `<div class="h-[260px] [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="channel-chart" aria-label="Channel performance radar chart"></canvas>
|
||||
</div>`;
|
||||
---
|
||||
|
||||
<div class="grid gap-10">
|
||||
<section>
|
||||
<h3>Bar Chart - Multiple</h3>
|
||||
<Preview class="w-full" code={barCode}>
|
||||
<div class="h-[220px] w-full [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-visitors" aria-label="Monthly visitors by device"></canvas>
|
||||
</div>
|
||||
</Preview>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Line Chart - Linear</h3>
|
||||
<Preview class="w-full" code={lineCode}>
|
||||
<div class="h-[220px] w-full [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-line" aria-label="Revenue line chart"></canvas>
|
||||
</div>
|
||||
</Preview>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Line Chart - Step</h3>
|
||||
<Preview class="w-full" code={stepCode}>
|
||||
<div class="h-[220px] w-full [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-step" aria-label="Support queue step chart"></canvas>
|
||||
</div>
|
||||
</Preview>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Bar Chart - Stacked</h3>
|
||||
<Preview class="w-full" code={stackedCode}>
|
||||
<div class="h-[220px] w-full [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-stacked" aria-label="Stacked pipeline bar chart"></canvas>
|
||||
</div>
|
||||
</Preview>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Pie Chart - Donut</h3>
|
||||
<Preview class="w-full" code={donutCode}>
|
||||
<div class="h-[220px] w-full [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-donut" aria-label="Traffic source donut chart"></canvas>
|
||||
</div>
|
||||
</Preview>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Radar Chart</h3>
|
||||
<Preview class="w-full" code={radarCode}>
|
||||
<div class="h-[260px] w-full [&_.chart]:h-full [&_.chart]:aspect-auto">
|
||||
<canvas id="chart-example-radar" aria-label="Channel performance radar chart"></canvas>
|
||||
</div>
|
||||
</Preview>
|
||||
</section>
|
||||
</div>
|
||||
+102
-19
@@ -68,6 +68,35 @@
|
||||
return resolved || color;
|
||||
};
|
||||
|
||||
const colorWithAlpha = (color, alpha, element) => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
canvas.height = 1;
|
||||
const context = canvas.getContext('2d', { willReadFrequently: true });
|
||||
if (!context) return color;
|
||||
|
||||
context.clearRect(0, 0, 1, 1);
|
||||
context.fillStyle = '#000';
|
||||
context.fillStyle = resolveColor(color, element);
|
||||
context.fillRect(0, 0, 1, 1);
|
||||
|
||||
const [red, green, blue, sourceAlpha] = context.getImageData(0, 0, 1, 1).data;
|
||||
return `rgba(${red}, ${green}, ${blue}, ${(sourceAlpha / 255) * alpha})`;
|
||||
};
|
||||
|
||||
const surfaceColor = (color, element, { from = 0.4, to } = {}) => {
|
||||
if (to === undefined) return colorWithAlpha(color, from, element);
|
||||
|
||||
return ({ chart }) => {
|
||||
if (!chart.chartArea) return colorWithAlpha(color, from, element);
|
||||
|
||||
const gradient = chart.ctx.createLinearGradient(0, chart.chartArea.top, 0, chart.chartArea.bottom);
|
||||
gradient.addColorStop(0, colorWithAlpha(color, from, element));
|
||||
gradient.addColorStop(1, colorWithAlpha(color, to, element));
|
||||
return gradient;
|
||||
};
|
||||
};
|
||||
|
||||
const resolveDatasetColors = (chartData, element) => {
|
||||
chartData.datasets?.forEach((dataset) => {
|
||||
dataset.borderColor = resolveColor(dataset.borderColor, element);
|
||||
@@ -78,10 +107,47 @@
|
||||
return chartData;
|
||||
};
|
||||
|
||||
const resolveScaleColors = (scales, element) => {
|
||||
Object.values(scales || {}).forEach((scale) => {
|
||||
['border', 'grid', 'ticks', 'angleLines', 'pointLabels'].forEach((key) => {
|
||||
if (scale[key]?.color !== undefined) {
|
||||
scale[key].color = resolveColor(scale[key].color, element);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return scales;
|
||||
};
|
||||
|
||||
const chartColor = (element, token) => resolveColor(`var(${token})`, element);
|
||||
|
||||
const colorMix = (color, opacity) => `color-mix(in oklab, ${color} ${opacity * 100}%, transparent)`;
|
||||
|
||||
const readCssPixels = (element, property, fallback = 0) => {
|
||||
const value = getComputedStyle(element).getPropertyValue(property).trim();
|
||||
if (!value) return fallback;
|
||||
|
||||
const number = Number.parseFloat(value);
|
||||
return Number.isFinite(number) ? number : fallback;
|
||||
};
|
||||
|
||||
const applyDatasetDefaults = (chartData, type, { barRadius, element }) => {
|
||||
chartData.datasets?.forEach((dataset) => {
|
||||
if (type === 'bar' || dataset.type === 'bar') {
|
||||
if (dataset.borderRadius === undefined) dataset.borderRadius = barRadius;
|
||||
}
|
||||
|
||||
if (dataset._basecoatSurface) {
|
||||
dataset.backgroundColor = surfaceColor(dataset.borderColor || dataset.backgroundColor, element, dataset._basecoatSurface);
|
||||
delete dataset._basecoatSurface;
|
||||
}
|
||||
});
|
||||
|
||||
return chartData;
|
||||
};
|
||||
|
||||
const usesCartesianScales = (type) => !['pie', 'doughnut', 'polarArea', 'radar'].includes(type);
|
||||
|
||||
const ensureContainer = (canvas) => {
|
||||
if (canvas.parentElement?.classList.contains('chart')) {
|
||||
canvas.parentElement.dataset.basecoatChartContainer = 'true';
|
||||
@@ -128,6 +194,13 @@
|
||||
labels,
|
||||
datasets: entries.map(([key, item], index) => {
|
||||
const color = item.color || colorForIndex(index);
|
||||
const dataset = item.dataset || {};
|
||||
const surface = item.surface === true
|
||||
? { from: 0.4 }
|
||||
: item.surface === 'gradient'
|
||||
? { from: 0.8, to: 0.1 }
|
||||
: item.surface;
|
||||
|
||||
return {
|
||||
label: item.label || key,
|
||||
data: rows.map((row) => valueFor(row, key)),
|
||||
@@ -137,7 +210,10 @@
|
||||
type: item.type,
|
||||
yAxisID: item.axis,
|
||||
hidden: item.hidden,
|
||||
...(item.dataset || {}),
|
||||
...dataset,
|
||||
...(surface && item.backgroundColor === undefined && dataset.backgroundColor === undefined
|
||||
? { _basecoatSurface: surface }
|
||||
: {}),
|
||||
};
|
||||
}),
|
||||
};
|
||||
@@ -276,23 +352,9 @@
|
||||
const borderColor = chartColor(canvas, '--border');
|
||||
const gridColor = resolveColor(colorMix('var(--border)', 0.5), canvas);
|
||||
const mutedColor = chartColor(canvas, '--muted-foreground');
|
||||
|
||||
canvas.classList.remove('chart');
|
||||
canvas._basecoatChartContainer = container;
|
||||
canvas.dataset.chartLegend = String(legend);
|
||||
|
||||
const chart = new Chart(canvas, {
|
||||
type,
|
||||
data: resolveDatasetColors(chartData, canvas),
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
...userOptions,
|
||||
scales: {
|
||||
const barRadius = readCssPixels(canvas, '--chart-bar-radius');
|
||||
const defaultScales = usesCartesianScales(type)
|
||||
? {
|
||||
x: {
|
||||
border: { display: false, color: borderColor },
|
||||
grid: { display: false, color: gridColor },
|
||||
@@ -305,8 +367,29 @@
|
||||
ticks: { display: false, color: mutedColor },
|
||||
...(userOptions.scales?.y || {}),
|
||||
},
|
||||
...(Object.fromEntries(Object.entries(userOptions.scales || {}).filter(([key]) => key !== 'x' && key !== 'y'))),
|
||||
}
|
||||
: {};
|
||||
const scales = {
|
||||
...defaultScales,
|
||||
...(Object.fromEntries(Object.entries(userOptions.scales || {}).filter(([key]) => key !== 'x' && key !== 'y'))),
|
||||
};
|
||||
|
||||
canvas.classList.remove('chart');
|
||||
canvas._basecoatChartContainer = container;
|
||||
canvas.dataset.chartLegend = String(legend);
|
||||
|
||||
const chart = new Chart(canvas, {
|
||||
type,
|
||||
data: resolveDatasetColors(applyDatasetDefaults(chartData, type, { barRadius, element: canvas }), canvas),
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
...userOptions,
|
||||
scales: resolveScaleColors(scales, canvas),
|
||||
plugins: {
|
||||
...userOptions.plugins,
|
||||
legend: {
|
||||
|
||||
Reference in New Issue
Block a user