Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Registry } from "../../../registry";
import { GlobalChart } from "../../../types/chart/chartjs";

export const chartJsExtensionRegistry = new Registry<{
register: (chart: GlobalChart) => void;
unregister: (chart: GlobalChart) => void;
}>();

export function areChartJSExtensionsLoaded() {
return globalThis.Chart ? !!globalThis.Chart.registry.plugins.get("chartShowValuesPlugin") : true;
}

export function registerChartJSExtensions() {
if (!globalThis.Chart || areChartJSExtensionsLoaded()) {
return;
}
for (const registryItem of chartJsExtensionRegistry.getAll()) {
registryItem.register(globalThis.Chart);
}
}

export function unregisterChartJsExtensions() {
if (!globalThis.Chart) {
return;
}
for (const registryItem of chartJsExtensionRegistry.getAll()) {
registryItem.unregister(globalThis.Chart);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import {
} from "../../../types/chart";
import { Figure } from "../../../types/figure";
import { deepCopy } from "../../misc";
import {
areChartJSExtensionsLoaded,
registerChartJSExtensions,
unregisterChartJsExtensions,
} from "./chart_js_extension";
import { drawGaugeChart } from "./gauge_chart_rendering";
import { drawScoreChart } from "./scorecard_chart";
import { getScorecardConfiguration } from "./scorecard_chart_config_builder";
Expand Down Expand Up @@ -35,13 +40,36 @@ export async function chartToImageUrl(
const canvas = createRenderingSurface(figure.width, figure.height);
let imageUrl: string | undefined;
if ("chartJsConfig" in runtime) {
if (!globalThis.Chart) {
console.log("Chart.js library is not loaded");
return imageUrl;
}
const extensionsLoaded = areChartJSExtensionsLoaded();
if (!extensionsLoaded) {
registerChartJSExtensions();
}
if (!globalThis.Chart.registry.controllers.get(type)) {
console.log(`Chart of type "${type}" is not registered in Chart.js library.`);
if (!extensionsLoaded) {
unregisterChartJsExtensions();
}
return imageUrl;
}

const config = deepCopy(runtime.chartJsConfig);
config.plugins = [backgroundColorChartJSPlugin];
const chart = new (globalThis as any).Chart(canvas, config as ChartConfiguration);

const chart = new globalThis.Chart(
canvas as unknown as HTMLCanvasElement,
config as ChartConfiguration
);
try {
imageUrl = await canvasToObjectUrl(canvas);
} finally {
chart.destroy();
if (!extensionsLoaded) {
unregisterChartJsExtensions();
}
}
}
// TODO: make a registry of chart types to their rendering functions
Expand Down Expand Up @@ -70,13 +98,36 @@ export async function chartToImageFile(
const canvas = createRenderingSurface(figure.width, figure.height);
let chartBlob: Blob | null = null;
if ("chartJsConfig" in runtime) {
if (!globalThis.Chart) {
console.log("Chart.js library is not loaded");
return chartBlob;
}
const extensionsLoaded = areChartJSExtensionsLoaded();
if (!extensionsLoaded) {
registerChartJSExtensions();
}
if (!globalThis.Chart.registry.controllers.get(type)) {
console.log(`Chart of type "${type}" is not registered in Chart.js library.`);
if (!extensionsLoaded) {
unregisterChartJsExtensions();
}
return chartBlob;
}

const config = deepCopy(runtime.chartJsConfig);
config.plugins = [backgroundColorChartJSPlugin];
const chart = new (globalThis as any).Chart(canvas, config as ChartConfiguration);

const chart = new globalThis.Chart(
canvas as unknown as HTMLCanvasElement,
config as ChartConfiguration
);
try {
chartBlob = await canvasToBlob(canvas);
} finally {
chart.destroy();
if (!extensionsLoaded) {
unregisterChartJsExtensions();
}
}
} else {
if (!globalThis.OffscreenCanvas)
Expand Down
1 change: 1 addition & 0 deletions packages/o-spreadsheet-engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export { Registry } from "./registry";
export { StateObserver } from "./state_observer";
export * from "./translation";
export { CellValue } from "./types/cells";
export type * from "./types/chart/chartjs";
export { SpreadsheetClipboardData } from "./types/clipboard";
export { CoreGetters, PluginGetters } from "./types/core_getters";
export * from "./types/errors";
Expand Down
7 changes: 7 additions & 0 deletions packages/o-spreadsheet-engine/src/types/chart/chartjs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as ChartJs from "chart.js";

export type GlobalChart = typeof ChartJs & typeof ChartJs.Chart;

declare global {
var Chart: GlobalChart | undefined;
}
28 changes: 0 additions & 28 deletions src/components/figures/chart/chartJs/chart_js_extension.ts

This file was deleted.

11 changes: 8 additions & 3 deletions src/components/figures/chart/chartJs/chartjs.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import {
chartJsExtensionRegistry,
registerChartJSExtensions,
} from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_js_extension";
import { ChartJSRuntime } from "@odoo/o-spreadsheet-engine/types/chart/chart";
import { SpreadsheetChildEnv } from "@odoo/o-spreadsheet-engine/types/spreadsheet_env";
import { Component, onMounted, onWillUnmount, useEffect, useRef } from "@odoo/owl";
import { Chart, ChartConfiguration } from "chart.js/auto";
import { deepCopy, deepEquals } from "../../../../helpers";
import { Store, useStore } from "../../../../store_engine";
import { UID } from "../../../../types";
import { chartJsExtensionRegistry, registerChartJSExtensions } from "./chart_js_extension";
import { ChartAnimationStore } from "./chartjs_animation_store";
import { getCalendarChartController } from "./chartjs_calendar_chart";
import { chartColorScalePlugin } from "./chartjs_colorscale_plugin";
Expand Down Expand Up @@ -43,7 +46,6 @@ chartJsExtensionRegistry.add("funnelElement", {
chartJsExtensionRegistry.add("funnelTooltipPositioner", {
register: (Chart) =>
(Chart.Tooltip.positioners.funnelTooltipPositioner = funnelTooltipPositioner),
// @ts-expect-error
unregister: (Chart) => (Chart.Tooltip.positioners.funnelTooltipPositioner = undefined),
});
chartJsExtensionRegistry.add("sunburstLabelsPlugin", {
Expand Down Expand Up @@ -131,6 +133,9 @@ export class ChartJsComponent extends Component<Props, SpreadsheetChildEnv> {
}

protected createChart(chartRuntime: ChartJSRuntime) {
if (!globalThis.Chart) {
throw new Error("Chart.js library is not loaded");
}
let chartData = chartRuntime.chartJsConfig as ChartConfiguration<any>;
if (this.shouldAnimate && this.animationStore) {
const chartType = this.env.model.getters.getChart(this.props.chartId)?.type;
Expand All @@ -142,7 +147,7 @@ export class ChartJsComponent extends Component<Props, SpreadsheetChildEnv> {

const canvas = this.canvas.el as HTMLCanvasElement;
const ctx = canvas.getContext("2d")!;
this.chart = new window.Chart(ctx, chartData);
this.chart = new globalThis.Chart(ctx, chartData);
}

protected updateChartJs(chartRuntime: ChartJSRuntime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ export function getCalendarChartController(): ChartComponent & {
prototype: BarController;
new (chart: Chart, datasetIndex: number): BarController;
} {
return class CalendarChartController extends window.Chart.BarController {
if (!globalThis.Chart) {
throw new Error("Chart.js library is not loaded");
}
return class CalendarChartController extends globalThis.Chart.BarController {
static id = "calendar";
static defaults = {
...window.Chart?.BarController.defaults,
...globalThis.Chart?.BarController.defaults,
dataElementType: "bar",
animations: {
numbers: { type: "number", properties: [] }, // Disable number animations (width, height, ...)
Expand Down
14 changes: 10 additions & 4 deletions src/components/figures/chart/chartJs/chartjs_funnel_chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ export function getFunnelChartController(): ChartComponent & {
prototype: BarController;
new (chart: Chart, datasetIndex: number): BarController;
} {
return class FunnelChartController extends window.Chart.BarController {
if (!globalThis.Chart) {
throw new Error("Chart.js library is not loaded");
}
return class FunnelChartController extends globalThis.Chart.BarController {
static id = "funnel";
static defaults = {
...window.Chart?.BarController.defaults,
...globalThis.Chart?.BarController.defaults,
dataElementType: "funnel",
animation: {
duration: (ctx: any) => {
Expand Down Expand Up @@ -48,11 +51,14 @@ export function getFunnelChartElement(): ChartComponent & {
prototype: BarElement;
new (cfg: AnyObject): BarElement;
} {
if (!globalThis.Chart) {
throw new Error("Chart.js library is not loaded");
}
/**
* Similar to a bar chart element, but it's a trapezoid rather than a rectangle. The top is of width
* `width`, and the bottom is of width `nextElementWidth`.
*/
return class FunnelChartElement extends window.Chart.BarElement {
return class FunnelChartElement extends globalThis.Chart.BarElement {
static id = "funnel";

/** Overwrite this to draw a trapezoid rather then a rectangle */
Expand Down Expand Up @@ -155,6 +161,6 @@ declare module "chart.js" {
}

export interface TooltipPositionerMap {
funnelTooltipPositioner: TooltipPositionerFunction<"funnel">;
funnelTooltipPositioner: TooltipPositionerFunction<"funnel"> | undefined;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
} from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_common";
import { useRef } from "@odoo/owl";
import { Chart, ChartConfiguration } from "chart.js/auto";
import { chartJsExtensionRegistry } from "../../../../../../packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_js_extension";
import { clip } from "../../../../../helpers";
import { Store, useStore } from "../../../../../store_engine";
import { ChartJSRuntime } from "../../../../../types";
import { withZoom } from "../../../../helpers/zoom";
import { chartJsExtensionRegistry } from "../chart_js_extension";
import { ChartJsComponent } from "../chartjs";
import { ZoomableChartStore } from "./zoomable_chart_store";
import { zoomWindowPlugin } from "./zoomable_chartjs_plugins";
Expand Down Expand Up @@ -125,6 +125,9 @@ export class ZoomableChartJsComponent extends ChartJsComponent {
}

protected createChart(chartRuntime: ChartJSRuntime) {
if (!globalThis.Chart) {
throw new Error("Chart.js library is not loaded");
}
const chartData = chartRuntime.chartJsConfig as ChartConfiguration<any>;
this.isBarChart = chartData.type === "bar";
this.chartId = `${chartData.type}-${this.props.chartId}`;
Expand All @@ -144,7 +147,7 @@ export class ZoomableChartJsComponent extends ChartJsComponent {
this.masterChart?.destroy();
const masterChartCtx = (this.masterChartCanvas!.el as HTMLCanvasElement).getContext("2d")!;

this.masterChart = new window.Chart(
this.masterChart = new globalThis.Chart(
masterChartCtx,
this.getMasterChartConfiguration(chartRuntime["masterChartConfig"] as ChartConfiguration<any>)
);
Expand All @@ -155,6 +158,9 @@ export class ZoomableChartJsComponent extends ChartJsComponent {
}

protected updateChartJs(chartRuntime: ChartJSRuntime) {
if (!globalThis.Chart) {
throw new Error("Chart.js library is not loaded");
}
const chartData = chartRuntime.chartJsConfig as ChartConfiguration<any>;
const newDatasetBoundaries = this.getAxisLimitsFromDataset(chartData);
if (
Expand Down Expand Up @@ -182,7 +188,7 @@ export class ZoomableChartJsComponent extends ChartJsComponent {
);
if (!this.masterChart) {
const masterChartCtx = (this.masterChartCanvas!.el as HTMLCanvasElement).getContext("2d")!;
this.masterChart = new window.Chart(masterChartCtx, masterChartConfig);
this.masterChart = new globalThis.Chart(masterChartCtx, masterChartConfig);
} else {
this.masterChart.data = masterChartConfig.data;
this.masterChart.config.options = masterChartConfig.options;
Expand Down
2 changes: 1 addition & 1 deletion src/components/spreadsheet/spreadsheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
useRef,
useSubEnv,
} from "@odoo/owl";
import { unregisterChartJsExtensions } from "../../../packages/o-spreadsheet-engine/src/helpers/figures/charts/chart_js_extension";
import { batched } from "../../helpers";
import { ImageProvider } from "../../helpers/figures/images/image_provider";
import { Store, useStore, useStoreProvider } from "../../store_engine";
Expand All @@ -25,7 +26,6 @@ import { CSSProperties, HeaderGroup, InformationNotification, Pixel } from "../.
import { BottomBar } from "../bottom_bar/bottom_bar";
import { ComposerFocusStore } from "../composer/composer_focus_store";
import { SpreadsheetDashboard } from "../dashboard/dashboard";
import { unregisterChartJsExtensions } from "../figures/chart/chartJs/chart_js_extension";
import { FullScreenFigure } from "../full_screen_figure/full_screen_figure";
import { Grid } from "../grid/grid";
import { HeaderGroupContainer } from "../header_group/header_group_container";
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/figures/charts/runtime/chartjs_scales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ export function getFunnelChartScales(

function getGeoChartProjection(projection: GeoChartProjection) {
if (projection === "conicConformal") {
return window.ChartGeo.geoConicConformal().rotate([100, 0]); // Centered on the US
return globalThis.ChartGeo.geoConicConformal().rotate([100, 0]); // Centered on the US
}
return projection;
}
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ import { supportedPivotPositionalFormulaRegistry } from "./helpers/pivot/pivot_p
import { ChartTerms } from "@odoo/o-spreadsheet-engine/components/translations_terms";
import { arg } from "@odoo/o-spreadsheet-engine/functions/arguments";
import { functionRegistry } from "@odoo/o-spreadsheet-engine/functions/function_registry";
import { chartJsExtensionRegistry } from "@odoo/o-spreadsheet-engine/helpers/figures/charts/chart_js_extension";
import {
areDomainArgsFieldsValid,
createCustomFields,
Expand Down Expand Up @@ -160,7 +161,6 @@ import {
import { errorTypes } from "@odoo/o-spreadsheet-engine/types/errors";
import { CellComposerStore } from "./components/composer/composer/cell_composer_store";
import { ClickableCellSortIcon } from "./components/dashboard/clickable_cell_sort_icon/clickable_cell_sort_icon";
import { chartJsExtensionRegistry } from "./components/figures/chart/chartJs/chart_js_extension";
import { ZoomableChartJsComponent } from "./components/figures/chart/chartJs/zoomable_chart/zoomable_chartjs";
import { ChartDashboardMenu } from "./components/figures/chart/chart_dashboard_menu/chart_dashboard_menu";
import { GaugeChartComponent } from "./components/figures/chart/gauge/gauge_chart_component";
Expand Down
2 changes: 0 additions & 2 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* - interface GridState: the internal type of the state managed by the model
*/

import * as Chart from "chart.js";
import * as ChartGeo from "chartjs-chart-geo";

export {
Expand Down Expand Up @@ -47,7 +46,6 @@ export * from "@odoo/o-spreadsheet-engine/types/workbook_data";

declare global {
interface Window {
Chart: typeof Chart & typeof Chart.Chart;
ChartGeo: typeof ChartGeo;
}
}
Loading