diff --git a/common/changes/@visactor/vchart/feat-support-includeFullBand-in-markarea_2025-09-10-11-13.json b/common/changes/@visactor/vchart/feat-support-includeFullBand-in-markarea_2025-09-10-11-13.json new file mode 100644 index 0000000000..6c6d9933e9 --- /dev/null +++ b/common/changes/@visactor/vchart/feat-support-includeFullBand-in-markarea_2025-09-10-11-13.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "feat: support includFullBand api in markArea\n\n", + "type": "none", + "packageName": "@visactor/vchart" + } + ], + "packageName": "@visactor/vchart", + "email": "lixuef1313@163.com" +} \ No newline at end of file diff --git a/packages/vchart/src/component/marker/interface.ts b/packages/vchart/src/component/marker/interface.ts index 28fb3d169c..b2d67958b6 100644 --- a/packages/vchart/src/component/marker/interface.ts +++ b/packages/vchart/src/component/marker/interface.ts @@ -340,6 +340,13 @@ export type IMarkerSpec = IComponentSpec & { * @since 1.11.0 */ coordinateType?: string; + + /** + * 在band轴下标注组件是否包含全band + * @default false + * @since 2.0.5 + */ + includeFullBand?: boolean; }; export type IMarkerSymbol = IMarkerRef & { diff --git a/packages/vchart/src/component/marker/mark-area/cartesian-mark-area.ts b/packages/vchart/src/component/marker/mark-area/cartesian-mark-area.ts index 140b451993..3b743e06eb 100644 --- a/packages/vchart/src/component/marker/mark-area/cartesian-mark-area.ts +++ b/packages/vchart/src/component/marker/mark-area/cartesian-mark-area.ts @@ -38,11 +38,12 @@ export class CartesianMarkArea extends BaseMarkArea { const isPositionLayout = isValid(spec.positions); const autoRange = spec.autoRange ?? false; + const includeFullBand = spec.includeFullBand ?? false; let points: IPoint[] = []; let lines: IPoint[][] = []; if (doXYProcess) { - lines = xyLayout(data, startRelativeSeries, endRelativeSeries, relativeSeries, autoRange); + lines = xyLayout(data, startRelativeSeries, endRelativeSeries, relativeSeries, autoRange, includeFullBand); // 格式为 [[{x, y}], [{x, y}]] // 顺序为左下角开始逆时针绘制 const [start, end] = lines; @@ -61,7 +62,7 @@ export class CartesianMarkArea extends BaseMarkArea { ]; } } else if (doXProcess || doYProcess) { - lines = xyLayout(data, startRelativeSeries, endRelativeSeries, relativeSeries, autoRange); + lines = xyLayout(data, startRelativeSeries, endRelativeSeries, relativeSeries, autoRange, includeFullBand); const [start, end] = lines; if (start && start.length && end && end.length) { points = [...start, end[1], end[0]]; diff --git a/packages/vchart/src/component/marker/utils.ts b/packages/vchart/src/component/marker/utils.ts index a0abc90935..c687fa208a 100644 --- a/packages/vchart/src/component/marker/utils.ts +++ b/packages/vchart/src/component/marker/utils.ts @@ -28,8 +28,20 @@ import type { IRegion } from '../../region/interface'; // eslint-disable-next-line no-duplicate-imports import type { OffsetPoint } from './interface'; import type { IAxisHelper, IPolarAxisHelper } from '../axis'; +import type { BandScale } from '@visactor/vscale'; import { isContinuous } from '@visactor/vscale'; +type FullBandTemp = { + min: { + value: number; + index: number; + }; + max: { + value: number; + index: number; + }; +}; + function isNeedExtendDomain(domain: number[], datum: number, autoRange: boolean) { if (!autoRange) { return false; @@ -141,7 +153,8 @@ export function xyLayout( startRelativeSeries: IMarkerSupportSeries, endRelativeSeries: IMarkerSupportSeries, relativeSeries: IMarkerSupportSeries, - autoRange: boolean + autoRange: boolean, + includeFullBand: boolean = false ) { const regionStart = startRelativeSeries.getRegion(); const regionStartLayoutStartPoint = regionStart.getLayoutStartPoint(); @@ -172,22 +185,37 @@ export function xyLayout( const lines: IPoint[][] = []; const dataPoints = data.latestData[0] && data.latestData[0].latestData ? data.latestData[0].latestData : data.latestData; - const xDomain = (relativeSeries as ICartesianSeries).getXAxisHelper().getScale(0).domain(); - const yDomain = (relativeSeries as ICartesianSeries).getYAxisHelper().getScale(0).domain(); + + const xAxisHelper = (relativeSeries as ICartesianSeries).getXAxisHelper(); + const yAxisHelper = (relativeSeries as ICartesianSeries).getXAxisHelper(); + + const xDomain = xAxisHelper.getScale(0).domain(); + const yDomain = yAxisHelper.getScale(0).domain(); + + const isXExpand = includeFullBand && !xAxisHelper.isContinuous && !!xAxisHelper.getBandwidth; + const isyExpand = includeFullBand && !yAxisHelper.isContinuous && !!yAxisHelper.getBandwidth; + const xTemp: FullBandTemp = { min: null, max: null }; + const yTemp: FullBandTemp = { min: null, max: null }; + dataPoints.forEach((datum: IPoint) => { const isValidX = isValid(datum.x); const isValidY = isValid(datum.y); + let x; + let y; if (isValidX && isValidY) { - const x = getXValue(datum, xDomain, autoRange, refSeries, regionWidth, regionStartLayoutStartPoint); - const y = getYValue(datum, yDomain, autoRange, refSeries, regionHeight, regionStartLayoutStartPoint); + x = getXValue(datum, xDomain, autoRange, refSeries, regionWidth, regionStartLayoutStartPoint); + y = getYValue(datum, yDomain, autoRange, refSeries, regionHeight, regionStartLayoutStartPoint); + setTempWithValid(x, isXExpand, xTemp, lines.length); + setTempWithValid(y, isyExpand, yTemp, lines.length); lines.push([{ x, y }]); } else if (isValidX) { - const x = getXValue(datum, xDomain, autoRange, refSeries, regionWidth, regionStartLayoutStartPoint); - const y = Math.max( + x = getXValue(datum, xDomain, autoRange, refSeries, regionWidth, regionStartLayoutStartPoint); + y = Math.max( regionStartLayoutStartPoint.y + regionStart.getLayoutRect().height, regionEndLayoutStartPoint.y + regionEnd.getLayoutRect().height ); const y1 = Math.min(regionStartLayoutStartPoint.y, regionEndLayoutStartPoint.y); + setTempWithValid(x, isXExpand, xTemp, lines.length); lines.push([ { x: x, @@ -199,12 +227,13 @@ export function xyLayout( } ]); } else if (isValidY) { - const x = Math.min(regionStartLayoutStartPoint.x, regionEndLayoutStartPoint.x); - const y = getYValue(datum, yDomain, autoRange, refSeries, regionHeight, regionStartLayoutStartPoint); + x = Math.min(regionStartLayoutStartPoint.x, regionEndLayoutStartPoint.x); + y = getYValue(datum, yDomain, autoRange, refSeries, regionHeight, regionStartLayoutStartPoint); const x1 = Math.max( regionStartLayoutStartPoint.x + regionStart.getLayoutRect().width, regionEndLayoutStartPoint.x + regionEnd.getLayoutRect().width ); + setTempWithValid(y, isyExpand, yTemp, lines.length); lines.push([ { x: x, @@ -217,10 +246,55 @@ export function xyLayout( ]); } }); - + setTempToLines(lines, xAxisHelper, yAxisHelper, xTemp, yTemp); return lines; } +function setTempToLines( + lines: IPoint[][], + xAxisHelper: IAxisHelper | IPolarAxisHelper, + yAxisHelper: IAxisHelper | IPolarAxisHelper, + xTemp: FullBandTemp, + yTemp: FullBandTemp +) { + if (xTemp.min || xTemp.max) { + const xBandSize = xAxisHelper.getBandwidth(0) * (1 + (xAxisHelper.getScale(0) as BandScale).paddingInner()); + if (xTemp.min) { + lines[xTemp.min.index].forEach(p => (p.x -= xBandSize / 2)); + } + if (xTemp.max) { + lines[xTemp.max.index].forEach(p => (p.x += xBandSize / 2)); + } + } + if (yTemp.min || yTemp.max) { + const yBandSize = yAxisHelper.getBandwidth(0) * (1 + (yAxisHelper.getScale(0) as BandScale).paddingInner()); + if (yTemp.min) { + lines[yTemp.min.index].forEach(p => (p.y -= yBandSize / 2)); + } + if (yTemp.max) { + lines[yTemp.max.index].forEach(p => (p.y += yBandSize / 2)); + } + } +} + +function setTempWithValid(v: number, isExpand: boolean, temp: FullBandTemp, index: number): number { + if (isExpand) { + if (temp.min === null || temp.min.value > v) { + temp.min = { + value: v, + index + }; + } + if (temp.max === null || temp.max.value < v) { + temp.max = { + value: v, + index + }; + } + } + return v; +} + export function polarLayout( data: DataView, startRelativeSeries: IMarkerSupportSeries,