You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
9.0 KiB
212 lines
9.0 KiB
export default function AlpineChart(Alpine) {
|
|
Alpine.directive(
|
|
"chart",
|
|
function (el, { expression }, { evaluateLater, cleanup }) {
|
|
const getContent = evaluateLater(expression);
|
|
|
|
import("apexcharts").then(({ default: ApexCharts }) => {
|
|
getContent((userConfig) => {
|
|
if (!userConfig || typeof userConfig !== "object") return;
|
|
|
|
// 1. Fetch live computed CSS variables directly from :root (document.documentElement)
|
|
const getCoreUIColors = () => {
|
|
const style = getComputedStyle(document.body);
|
|
|
|
// CoreUI v4/v5 & Bootstrap 5 theme variable names
|
|
const bodyColor =
|
|
style.getPropertyValue("--cui-body-color").trim() ||
|
|
style.getPropertyValue("--bs-body-color").trim() ||
|
|
"#a6b0cf";
|
|
|
|
const secondaryColor =
|
|
style
|
|
.getPropertyValue("--cui-secondary-color")
|
|
.trim() ||
|
|
style
|
|
.getPropertyValue("--bs-secondary-color")
|
|
.trim() ||
|
|
"#8a93a2";
|
|
|
|
const borderColor =
|
|
style
|
|
.getPropertyValue("--cui-border-color")
|
|
.trim() ||
|
|
style
|
|
.getPropertyValue(
|
|
"--bs-border-color-translucent",
|
|
)
|
|
.trim() ||
|
|
style
|
|
.getPropertyValue("--bs-border-color")
|
|
.trim() ||
|
|
"rgba(255, 255, 255, 0.08)";
|
|
|
|
const primaryColor =
|
|
style.getPropertyValue("--cui-primary").trim() ||
|
|
style.getPropertyValue("--bs-primary").trim() ||
|
|
"#6366f1";
|
|
|
|
const theme =
|
|
document.documentElement.getAttribute(
|
|
"data-coreui-theme",
|
|
) ||
|
|
document.documentElement.getAttribute(
|
|
"data-bs-theme",
|
|
) ||
|
|
"dark";
|
|
|
|
return {
|
|
bodyColor,
|
|
secondaryColor,
|
|
borderColor,
|
|
primaryColor,
|
|
theme,
|
|
};
|
|
};
|
|
|
|
const colors = getCoreUIColors();
|
|
|
|
// 2. Base Configuration explicitly overriding ApexCharts SVG text fills
|
|
const baseConfig = {
|
|
chart: {
|
|
type: "line",
|
|
height: 360,
|
|
foreColor: colors.secondaryColor, // Sets default text/legend colors
|
|
background: "transparent",
|
|
},
|
|
colors: [colors.primaryColor],
|
|
theme: {
|
|
mode: colors.theme,
|
|
},
|
|
tooltip: {
|
|
theme: colors.theme,
|
|
},
|
|
grid: {
|
|
borderColor: colors.borderColor,
|
|
},
|
|
xaxis: {
|
|
labels: {
|
|
style: {
|
|
colors: colors.secondaryColor,
|
|
fontSize: "12px",
|
|
},
|
|
},
|
|
axisBorder: { color: colors.borderColor },
|
|
axisTicks: { color: colors.borderColor },
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
style: {
|
|
colors: colors.secondaryColor,
|
|
fontSize: "12px",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
// Deep merge user options with base configuration
|
|
const options = Object.assign({}, baseConfig, userConfig);
|
|
options.chart = Object.assign(
|
|
{},
|
|
baseConfig.chart,
|
|
userConfig.chart,
|
|
);
|
|
options.theme = Object.assign(
|
|
{},
|
|
baseConfig.theme,
|
|
userConfig.theme,
|
|
);
|
|
options.tooltip = Object.assign(
|
|
{},
|
|
baseConfig.tooltip,
|
|
userConfig.tooltip,
|
|
);
|
|
|
|
// Preserve user primary colors if explicitly provided in PHP, otherwise use CoreUI's
|
|
if (!userConfig.colors) {
|
|
options.colors = baseConfig.colors;
|
|
}
|
|
|
|
requestAnimationFrame(() => {
|
|
const chart = new ApexCharts(el, options);
|
|
chart.render();
|
|
|
|
// 3. Theme switch handler
|
|
const observer = new MutationObserver(() => {
|
|
const updated = getCoreUIColors();
|
|
|
|
chart.updateOptions(
|
|
{
|
|
chart: {
|
|
foreColor: updated.secondaryColor,
|
|
},
|
|
theme: { mode: updated.theme },
|
|
tooltip: { theme: updated.theme },
|
|
grid: { borderColor: updated.borderColor },
|
|
xaxis: {
|
|
labels: {
|
|
style: {
|
|
colors: updated.secondaryColor,
|
|
},
|
|
},
|
|
axisBorder: {
|
|
color: updated.borderColor,
|
|
},
|
|
axisTicks: {
|
|
color: updated.borderColor,
|
|
},
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
style: {
|
|
colors: updated.secondaryColor,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
false,
|
|
true,
|
|
);
|
|
});
|
|
|
|
observer.observe(document.documentElement, {
|
|
attributes: true,
|
|
attributeFilter: [
|
|
"data-coreui-theme",
|
|
"data-bs-theme",
|
|
"class",
|
|
],
|
|
});
|
|
|
|
// 4. Dynamic update event listener
|
|
const name = el.getAttribute("id");
|
|
const eventHandler = (event) => {
|
|
const detail = event.detail || event;
|
|
if (detail.series)
|
|
chart.updateSeries(detail.series, true);
|
|
if (detail.options)
|
|
chart.updateOptions(detail.options, true);
|
|
};
|
|
|
|
if (name) {
|
|
window.addEventListener(
|
|
`chart-${name}-update`,
|
|
eventHandler,
|
|
);
|
|
}
|
|
|
|
cleanup(() => {
|
|
observer.disconnect();
|
|
if (name)
|
|
window.removeEventListener(
|
|
`chart-${name}-update`,
|
|
eventHandler,
|
|
);
|
|
chart.destroy();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
},
|
|
);
|
|
}
|
|
|