Skip to content
Merged
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
Expand Up @@ -56,6 +56,7 @@ import type { SeriesOption } from 'echarts';
import {
EchartsTimeseriesChartProps,
EchartsTimeseriesFormData,
EchartsTimeseriesSeriesType,
OrientationType,
TimeseriesChartTransformedProps,
} from './types';
Expand Down Expand Up @@ -310,6 +311,14 @@ export default function transformProps(

let patternIncrement = 0;

// For horizontal bar charts, calculate min/max from data to avoid cutting off labels
const shouldCalculateDataBounds =
isHorizontal &&
seriesType === EchartsTimeseriesSeriesType.Bar &&
truncateYAxis;
let dataMax: number | undefined;
let dataMin: number | undefined;

rawSeries.forEach(entry => {
const derivedSeries = isDerivedSeries(entry, chartProps.rawFormData);
const lineStyle: LineStyleOption = {};
Expand All @@ -323,6 +332,21 @@ export default function transformProps(
const entryName = String(entry.name || '');
const seriesName = inverted[entryName] || entryName;

// Calculate min/max from data for horizontal bar charts
if (shouldCalculateDataBounds && entry.data && Array.isArray(entry.data)) {
(entry.data as [number, any][]).forEach((datum: [number, any]) => {
const value = datum[0];
if (typeof value === 'number' && !Number.isNaN(value)) {
if (dataMax === undefined || value > dataMax) {
dataMax = value;
}
if (dataMin === undefined || value < dataMin) {
dataMin = value;
}
}
});
}

let colorScaleKey = getOriginalSeries(seriesName, array);

// If this series name exactly matches a time compare value, it's a time-shifted series
Expand Down Expand Up @@ -498,6 +522,18 @@ export default function transformProps(
yAxisMin = calculateLowerLogTick(minPositiveValue);
}

// For horizontal bar charts, set max/min from calculated data bounds
if (shouldCalculateDataBounds) {
// Set max to actual data max to avoid gaps and ensure labels are visible
if (dataMax !== undefined && yAxisMax === undefined) {
yAxisMax = dataMax;
}
// Set min to actual data min for diverging bars
if (dataMin !== undefined && yAxisMin === undefined && dataMin < 0) {
yAxisMin = dataMin;
}
}

const tooltipFormatter =
xAxisDataType === GenericDataType.Temporal
? getTooltipTimeFormatter(tooltipTimeFormat)
Expand Down Expand Up @@ -603,6 +639,13 @@ export default function transformProps(
if (isHorizontal) {
[xAxis, yAxis] = [yAxis, xAxis];
[padding.bottom, padding.left] = [padding.left, padding.bottom];
// Increase right padding for horizontal bar charts to ensure value labels are visible
if (seriesType === EchartsTimeseriesSeriesType.Bar && showValue) {
padding.right = Math.max(
padding.right || 0,
TIMESERIES_CONSTANTS.horizontalBarLabelRightPadding,
);
}
}

const echartOptions: EChartsCoreOption = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export const TIMESERIES_CONSTANTS = {
dataZoomEnd: 100,
yAxisLabelTopOffset: 20,
extraControlsOffset: 22,
// Min right padding (px) for horizontal bar charts to ensure value labels are fully visible
horizontalBarLabelRightPadding: 70,
};

export const LABEL_POSITION: [LabelPositionEnum, string][] = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
* Base timestamp used for test data generation.
* This provides a consistent starting point for all test timestamps.
*/
export const BASE_TIMESTAMP = 599616000000;

/**
* Default interval between timestamps (300000000 ms ≈ 3.47 days).
* This matches the common pattern used in tests.
*/
export const DEFAULT_TIMESTAMP_INTERVAL = 300000000;

/**
* Creates a timestamp with an offset from the base timestamp.
*
* @param offset - Offset in milliseconds from BASE_TIMESTAMP
* @returns Timestamp value
*/
export function createTimestamp(offset: number = 0): number {
return BASE_TIMESTAMP + offset;
}

/**
* Creates an array of timestamps starting from the base timestamp.
*
* @param count - Number of timestamps to generate
* @param intervalMs - Interval between timestamps in milliseconds (default: DEFAULT_TIMESTAMP_INTERVAL)
* @returns Array of timestamp values
*/
export function createTimestamps(
count: number,
intervalMs: number = DEFAULT_TIMESTAMP_INTERVAL,
): number[] {
return Array.from({ length: count }, (_, index) =>
createTimestamp(index * intervalMs),
);
}

/**
* Creates a single test data row with a timestamp.
*
* @param values - Object containing series values (excluding __timestamp)
* @param timestamp - Timestamp value to include
* @returns Test data row with __timestamp property
*/
export function createTestDataRow(
values: Record<string, number>,
timestamp: number,
): Record<string, number> & { __timestamp: number } {
return {
...values,
__timestamp: timestamp,
};
}

/**
* Options for creating test data.
*/
export interface CreateTestDataOptions {
/** Base timestamp to start from (default: BASE_TIMESTAMP) */
baseTimestamp?: number;
/** Interval between timestamps in milliseconds (default: DEFAULT_TIMESTAMP_INTERVAL) */
intervalMs?: number;
}

/**
* Creates an array of test data rows with auto-generated timestamps.
*
* @param rows - Array of objects containing series values (without __timestamp)
* @param options - Options for timestamp generation
* @returns Array of test data rows with __timestamp properties
*
* @example
* ```typescript
* const data = createTestData(
* [
* { 'Series A': 15000 },
* { 'Series A': 20000 },
* { 'Series A': 18000 },
* ],
* { intervalMs: 300000000 }
* );
* // Returns:
* // [
* // { 'Series A': 15000, __timestamp: 599616000000 },
* // { 'Series A': 20000, __timestamp: 599916000000 },
* // { 'Series A': 18000, __timestamp: 600216000000 },
* // ]
* ```
*/
export function createTestData(
rows: Array<Record<string, number>>,
options: CreateTestDataOptions = {},
): Array<Record<string, number> & { __timestamp: number }> {
const {
baseTimestamp = BASE_TIMESTAMP,
intervalMs = DEFAULT_TIMESTAMP_INTERVAL,
} = options;

return rows.map((row, index) =>
createTestDataRow(row, baseTimestamp + index * intervalMs),
);
}
Loading
Loading