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
1 change: 1 addition & 0 deletions packages/o-spreadsheet-engine/src/types/chart/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export interface ChartCreationContext {
readonly treemapColoringOptions?: TreeMapColoringOptions;
readonly zoomable?: boolean;
readonly humanize?: boolean;
readonly slicesColors?: string[];
}

export type ChartAxisFormats = { [axisId: string]: Format | undefined } | undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/o-spreadsheet-engine/src/types/chart/pie_chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CommonChartDefinition } from "./common_chart";

export interface PieChartDefinition extends CommonChartDefinition {
readonly type: "pie";
readonly slicesColors?: string[];
readonly aggregated?: boolean;
readonly isDoughnut?: boolean;
readonly showValues?: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { PieChartDefinition } from "@odoo/o-spreadsheet-engine/types/chart";
import { deepCopy } from "@odoo/o-spreadsheet-engine";
import { PieChartDefinition, PieChartRuntime } from "@odoo/o-spreadsheet-engine/types/chart";
import { SpreadsheetChildEnv } from "@odoo/o-spreadsheet-engine/types/spreadsheet_env";
import { DEFAULT_DOUGHNUT_CHART_HOLE_SIZE } from "@odoo/o-spreadsheet-engine/xlsx/constants";
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { Checkbox } from "../../components/checkbox/checkbox";
import { SidePanelCollapsible } from "../../components/collapsible/side_panel_collapsible";
import { RoundColorPicker } from "../../components/round_color_picker/round_color_picker";
import { Section } from "../../components/section/section";
import { GeneralDesignEditor } from "../building_blocks/general_design/general_design_editor";
import { ChartHumanizeNumbers } from "../building_blocks/humanize_numbers/humanize_numbers";
Expand All @@ -24,9 +27,24 @@ export class PieChartDesignPanel extends Component<
PieHoleSize,
Checkbox,
ChartHumanizeNumbers,
SidePanelCollapsible,
RoundColorPicker,
};
static props = ChartSidePanelPropsObject;

protected state = useState({ index: 0 });

private runtime!: PieChartRuntime;

setup() {
super.setup();
this.runtime = this.env.model.getters.getChartRuntime(this.props.chartId) as PieChartRuntime;
}

getLabels() {
return this.runtime.chartJsConfig.data.labels;
}

onPieHoleSizeChange(pieHolePercentage: number) {
this.props.updateChart(this.props.chartId, {
...this.props.definition,
Expand All @@ -36,4 +54,30 @@ export class PieChartDesignPanel extends Component<
get defaultHoleSize() {
return DEFAULT_DOUGHNUT_CHART_HOLE_SIZE;
}

updateEditedValues(ev: Event) {
this.state.index = (ev.target as HTMLSelectElement).selectedIndex;
}

updateSliceColor(color: string) {
let slicesColors = deepCopy(this.props.definition.slicesColors);
if (!slicesColors) {
slicesColors = Array(this.getLabels()?.length).fill("");
}
slicesColors[this.state.index] = color;
this.props.updateChart(this.props.chartId, {
...this.props.definition,
slicesColors,
});
}

getSliceColor() {
const slicesColors = this.props.definition.slicesColors;
if (slicesColors?.[this.state.index]) {
return slicesColors?.[this.state.index];
}
const dataSets = this.runtime.chartJsConfig.data.datasets;
const color = dataSets[0]?.backgroundColor?.[this.state.index];
return color;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,29 @@
/>
</t>
</GeneralDesignEditor>

<SidePanelCollapsible isInitiallyCollapsed="true" title.translate="Pie Slice">
<t t-set-slot="content">
<Section class="'py-0'">
<select
class="o-input pie-slice-selector"
t-on-change="(ev) => this.updateEditedValues(ev)">
<t t-foreach="getLabels()" t-as="label" t-key="label_index">
<option
t-att-value="label"
t-att-selected="state.index === label_index"
t-esc="label"
/>
</t>
</select>
</Section>
<Section class="'py-4'">
<div class="d-flex align-items-center">
<span class="o-section-title mb-0 pe-2">Series color</span>
<RoundColorPicker currentColor="getSliceColor()" onColorPicked.bind="updateSliceColor"/>
</div>
</Section>
</t>
</SidePanelCollapsible>
</t>
</templates>
4 changes: 4 additions & 0 deletions src/helpers/figures/charts/pie_chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class PieChart extends AbstractChart {
readonly background?: Color;
readonly legendPosition: LegendPosition;
readonly type = "pie";
readonly slicesColors?: string[];
readonly aggregated?: boolean;
readonly dataSetsHaveTitle: boolean;
readonly isDoughnut?: boolean;
Expand All @@ -73,6 +74,7 @@ export class PieChart extends AbstractChart {
this.isDoughnut = definition.isDoughnut;
this.showValues = definition.showValues;
this.pieHolePercentage = definition.pieHolePercentage;
this.slicesColors = definition.slicesColors;
}

static transformDefinition(
Expand Down Expand Up @@ -104,6 +106,7 @@ export class PieChart extends AbstractChart {
pieHolePercentage: context.pieHolePercentage,
showValues: context.showValues,
humanize: context.humanize,
slicesColors: context.slicesColors,
};
}

Expand Down Expand Up @@ -145,6 +148,7 @@ export class PieChart extends AbstractChart {
showValues: this.showValues,
pieHolePercentage: this.pieHolePercentage,
humanize: this.humanize,
slicesColors: this.slicesColors,
};
}

Expand Down
5 changes: 4 additions & 1 deletion src/helpers/figures/charts/runtime/chartjs_dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,10 @@ export function getPieChartDatasets(
const { dataSetsValues } = args;
const dataSets: ChartDataset<"pie">[] = [];
const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
const backgroundColor = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
const backgroundColor = getPieColors(
new ColorGenerator(dataSetsLength, definition.slicesColors),
dataSetsValues
);
for (const { label, data, hidden } of dataSetsValues) {
if (hidden) {
continue;
Expand Down
8 changes: 6 additions & 2 deletions src/helpers/figures/charts/runtime/chartjs_legend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ChartWithDataSetDefinition,
GenericDefinition,
LineChartDefinition,
PieChartDefinition,
SunburstChartDefinition,
SunburstChartJSDataset,
WaterfallChartDefinition,
Expand Down Expand Up @@ -70,12 +71,15 @@ export function getLineChartLegend(
}

export function getPieChartLegend(
definition: GenericDefinition<LineChartDefinition>,
definition: GenericDefinition<PieChartDefinition>,
args: ChartRuntimeGenerationArgs
): ChartLegend {
const { dataSetsValues } = args;
const dataSetsLength = Math.max(0, ...dataSetsValues.map((ds) => ds?.data?.length ?? 0));
const colors = getPieColors(new ColorGenerator(dataSetsLength), dataSetsValues);
const colors = getPieColors(
new ColorGenerator(dataSetsLength, definition.slicesColors),
dataSetsValues
);
const fontColor = chartFontColor(definition.background);
return {
...getLegendDisplayOptions(definition, args),
Expand Down
35 changes: 35 additions & 0 deletions tests/figures/chart/charts_component.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,41 @@ describe("charts", () => {
]);
});

test("can edit pie chart slices color", async () => {
createChart(
model,
{
dataSets: [
{ dataRange: "B1:B4", label: "serie_1" },
{ dataRange: "C1:C4", label: "serie_2" },
],
labelRange: "A2:A4",
type: "pie",
},
chartId
);
await mountChartSidePanel();
await openChartDesignSidePanel(model, env, fixture, chartId);

const color_menu = fixture.querySelectorAll(".o-round-color-picker-button")[1];

await click(color_menu);
await click(fixture, ".o-color-picker-line-item[data-color='#EFEFEF'");
//@ts-ignore
expect(model.getters.getChartDefinition(chartId).slicesColors).toEqual(["#EFEFEF", "", ""]);
setInputValueAndTrigger(".pie-slice-selector", "P3");

await click(color_menu);
await click(fixture, ".o-color-picker-line-item[data-color='#FF0000'");
//@ts-ignore

expect(model.getters.getChartDefinition(chartId).slicesColors).toEqual([
"#EFEFEF",
"",
"#FF0000",
]);
});

test("can edit chart data series vertical axis", async () => {
createChart(
model,
Expand Down
1 change: 1 addition & 0 deletions tests/figures/chart/pie_chart_plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe("pie chart", () => {
pieHolePercentage: 0,
showValues: false,
humanize: false,
slicesColors: [],
});
});

Expand Down
1 change: 1 addition & 0 deletions tests/test_helpers/chart_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,5 @@ export const GENERAL_CHART_CREATION_CONTEXT: Required<ChartCreationContext> = {
showHeaders: true,
zoomable: false,
humanize: false,
slicesColors: [],
};