mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 16:09:05 +00:00
296 lines
9.9 KiB
TypeScript
296 lines
9.9 KiB
TypeScript
// Copyright 2023 OpenObserve Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import { formatUnitValue, getUnitValue } from "../../convertDataIntoUnitValue";
|
|
import { getSeriesColor } from "../../colorPalette";
|
|
import {
|
|
getChartDimensions,
|
|
applyPieDonutChartAlignment,
|
|
applyPieDonutCenterAdjustment,
|
|
calculatePieChartContainer,
|
|
} from "../../legendConfiguration";
|
|
import { type SQLContext } from "../shared/types";
|
|
|
|
/**
|
|
* Applies chart-specific options for: pie AND donut
|
|
*
|
|
* Mutates `ctx.options` in place, exactly as the original switch cases did.
|
|
*/
|
|
export function applyPieDonutChart(ctx: SQLContext): void {
|
|
const {
|
|
options,
|
|
panelSchema,
|
|
store,
|
|
yAxisKeys,
|
|
chartMin,
|
|
chartMax,
|
|
chartPanelRef,
|
|
hoveredSeriesState,
|
|
defaultSeriesProps,
|
|
getAxisDataFromKey,
|
|
getPieChartRadius,
|
|
} = ctx;
|
|
|
|
if (panelSchema.type === "pie") {
|
|
// Add more padding for pie chart
|
|
options.grid = {
|
|
containLabel: true,
|
|
left: "15%",
|
|
right: "15%",
|
|
top: "15%",
|
|
bottom: "15%",
|
|
};
|
|
options.tooltip = {
|
|
trigger: "item",
|
|
textStyle: {
|
|
color: store.state.theme === "dark" ? "#fff" : "#000",
|
|
fontSize: 12,
|
|
},
|
|
backgroundColor:
|
|
store.state.theme === "dark" ? "rgba(0,0,0,1)" : "rgba(255,255,255,1)",
|
|
formatter: function (name: any) {
|
|
try {
|
|
// show tooltip for hovered panel only for other we only need axis so just return empty string
|
|
if (
|
|
hoveredSeriesState?.value &&
|
|
panelSchema.id &&
|
|
hoveredSeriesState?.value?.panelId != panelSchema.id
|
|
)
|
|
return "";
|
|
return `${name?.marker} ${name?.name} : <b>${formatUnitValue(
|
|
getUnitValue(
|
|
name?.value,
|
|
panelSchema.config?.unit,
|
|
panelSchema.config?.unit_custom,
|
|
panelSchema.config?.decimals,
|
|
),
|
|
)}</b>`;
|
|
} catch (error) {
|
|
return "";
|
|
}
|
|
},
|
|
};
|
|
//generate trace based on the y axis keys
|
|
options.series = yAxisKeys?.map((key: any) => {
|
|
const seriesObj = {
|
|
...defaultSeriesProps,
|
|
data: getAxisDataFromKey(key).map((it: any, i: number) => {
|
|
return { value: it, name: options?.xAxis[0]?.data[i] };
|
|
}),
|
|
itemStyle: {
|
|
color: ["palette-classic"].includes(panelSchema.config?.color?.mode)
|
|
? null
|
|
: (params: any) => {
|
|
return (
|
|
getSeriesColor(
|
|
panelSchema?.config?.color,
|
|
params.name,
|
|
[params.value],
|
|
chartMin,
|
|
chartMax,
|
|
store.state.theme,
|
|
panelSchema?.config?.color?.colorBySeries,
|
|
) ?? null
|
|
);
|
|
},
|
|
},
|
|
label: {
|
|
show: true,
|
|
formatter: "{d}%", // {b} represents name, {c} represents value {d} represents percent
|
|
position: "inside", // You can adjust the position of the labels
|
|
fontSize: 10,
|
|
},
|
|
percentPrecision: panelSchema.config?.decimals ?? 2,
|
|
};
|
|
return seriesObj;
|
|
});
|
|
|
|
if (options.series.length > 0) {
|
|
// Get current chart dimensions
|
|
const { chartWidth, chartHeight } = getChartDimensions(chartPanelRef);
|
|
|
|
// Calculate responsive radius that accounts for dynamic resizing
|
|
const pieRadius = getPieChartRadius(options.series[0].data);
|
|
options.series[0].radius = `${pieRadius}%`;
|
|
|
|
// Apply chart alignment - only when legend position is right and chart_align is explicitly set
|
|
const shouldApplyAlignment =
|
|
panelSchema.config?.show_legends &&
|
|
panelSchema.config?.legends_position === "right" &&
|
|
(panelSchema.config?.legends_type === "plain" ||
|
|
panelSchema.config?.legends_type === "scroll" ||
|
|
panelSchema.config?.legends_type === null) &&
|
|
panelSchema.config?.chart_align; // Only apply when chart_align is explicitly set
|
|
|
|
if (shouldApplyAlignment) {
|
|
// Apply chart alignment based on container properties
|
|
const containerProps = calculatePieChartContainer(
|
|
panelSchema,
|
|
chartWidth,
|
|
chartHeight,
|
|
options.series[0].data || [],
|
|
);
|
|
|
|
// Apply center positioning based on alignment requirements
|
|
if (containerProps.shouldUseGridAlignment) {
|
|
// Calculate center position for alignment within ONLY the chart area (excluding legend)
|
|
const chartAlign = panelSchema.config?.chart_align;
|
|
const chartAreaWidth = containerProps.availableWidth;
|
|
|
|
let centerX = 50; // Default center
|
|
let centerY = 50; // Default center
|
|
|
|
// For right legends, adjust horizontal positioning
|
|
const chartAreaRadius = Math.min(chartAreaWidth, chartHeight) * 0.4; // 40% of smaller dimension
|
|
const radiusAsPercentOfTotal = (chartAreaRadius / chartWidth) * 100;
|
|
const minSafeXInChartArea = radiusAsPercentOfTotal + 2; // 2% padding
|
|
switch (chartAlign) {
|
|
case "left": {
|
|
// Position chart to the left within ONLY the chart area
|
|
const leftPositionInChartArea = chartAreaWidth * 0.25; // 25% into chart area
|
|
centerX = Math.max(
|
|
minSafeXInChartArea,
|
|
(leftPositionInChartArea / chartWidth) * 100,
|
|
);
|
|
break;
|
|
}
|
|
case "center":
|
|
default: {
|
|
// Center within ONLY the chart area
|
|
const chartAreaCenter = chartAreaWidth / 2;
|
|
centerX = (chartAreaCenter / chartWidth) * 100;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const finalCenter = [`${centerX}%`, `${centerY}%`];
|
|
options.series[0].center = finalCenter;
|
|
} else {
|
|
// Fallback to default center when grid alignment is not used
|
|
options.series[0].center = ["50%", "50%"];
|
|
}
|
|
} else {
|
|
applyPieDonutCenterAdjustment(
|
|
panelSchema,
|
|
options,
|
|
chartWidth,
|
|
chartHeight,
|
|
);
|
|
}
|
|
}
|
|
|
|
options.xAxis = [];
|
|
options.yAxis = [];
|
|
} else {
|
|
// donut
|
|
// Add more padding for donut chart
|
|
options.grid = {
|
|
containLabel: true,
|
|
left: "15%",
|
|
right: "15%",
|
|
top: "15%",
|
|
bottom: "15%",
|
|
};
|
|
options.tooltip = {
|
|
trigger: "item",
|
|
textStyle: {
|
|
color: store.state.theme === "dark" ? "#fff" : "#000",
|
|
fontSize: 12,
|
|
},
|
|
backgroundColor:
|
|
store.state.theme === "dark" ? "rgba(0,0,0,1)" : "rgba(255,255,255,1)",
|
|
formatter: function (name: any) {
|
|
try {
|
|
// show tooltip for hovered panel only for other we only need axis so just return empty string
|
|
if (
|
|
hoveredSeriesState?.value &&
|
|
panelSchema.id &&
|
|
hoveredSeriesState?.value?.panelId != panelSchema.id
|
|
)
|
|
return "";
|
|
return `${name?.marker} ${name?.name} : <b>${formatUnitValue(
|
|
getUnitValue(
|
|
name?.value,
|
|
panelSchema.config?.unit,
|
|
panelSchema.config?.unit_custom,
|
|
panelSchema.config?.decimals,
|
|
),
|
|
)}<b/>`;
|
|
} catch (error) {
|
|
return "";
|
|
}
|
|
},
|
|
};
|
|
//generate trace based on the y axis keys
|
|
options.series = yAxisKeys?.map((key: any) => {
|
|
const seriesObj = {
|
|
...defaultSeriesProps,
|
|
data: getAxisDataFromKey(key).map((it: any, i: number) => {
|
|
return { value: it, name: options?.xAxis[0]?.data[i] };
|
|
}),
|
|
itemStyle: {
|
|
color: ["palette-classic"].includes(panelSchema.config?.color?.mode)
|
|
? null
|
|
: (params: any) => {
|
|
return (
|
|
getSeriesColor(
|
|
panelSchema?.config?.color,
|
|
params.name,
|
|
[params.value],
|
|
chartMin,
|
|
chartMax,
|
|
store.state.theme,
|
|
panelSchema?.config?.color?.colorBySeries,
|
|
) ?? null
|
|
);
|
|
},
|
|
},
|
|
label: {
|
|
show: true,
|
|
formatter: "{d}%", // {b} represents name, {c} represents value {d} represents percent
|
|
position: "inside", // You can adjust the position of the labels
|
|
fontSize: 10,
|
|
},
|
|
percentPrecision: panelSchema.config?.decimals ?? 2,
|
|
};
|
|
return seriesObj;
|
|
});
|
|
|
|
if (options.series.length > 0) {
|
|
// Get current chart dimensions
|
|
const { chartWidth, chartHeight } = getChartDimensions(chartPanelRef);
|
|
|
|
const outerRadius: number = getPieChartRadius(options.series[0].data);
|
|
|
|
// Adjust inner radius based on outer radius size for better proportions
|
|
const thickness = outerRadius > 70 ? 35 : 30;
|
|
const innterRadius = Math.max(outerRadius - thickness, 20); // Ensure minimum inner radius
|
|
|
|
options.series[0].radius = [`${innterRadius}%`, `${outerRadius}%`];
|
|
|
|
// Apply chart alignment and center positioning using centralized function
|
|
applyPieDonutChartAlignment(
|
|
panelSchema,
|
|
options,
|
|
chartWidth,
|
|
chartHeight,
|
|
);
|
|
}
|
|
|
|
options.xAxis = [];
|
|
options.yAxis = [];
|
|
}
|
|
}
|