feat(chart): support per-track legend positions
This commit is contained in:
@@ -1079,6 +1079,61 @@ describe('WaveformChart', () => {
|
||||
expect(wrapper.attributes('data-chart-left-margin')).toBe('64')
|
||||
})
|
||||
|
||||
it('resolves legend positions by stable track id across pages', async () => {
|
||||
const wrapper = await mountSizedChart(
|
||||
{
|
||||
kind: 'series',
|
||||
series: Array.from({ length: 8 }, (_, index) => ({
|
||||
id: `series-${index}`,
|
||||
trackId: `frame-${Math.floor(index / 2)}`,
|
||||
name: `series ${index}`,
|
||||
data: {
|
||||
kind: 'points' as const,
|
||||
points: [
|
||||
{ x: 0, y: index },
|
||||
{ x: 1, y: index + 1 },
|
||||
],
|
||||
},
|
||||
})),
|
||||
},
|
||||
{
|
||||
grid: { rowCount: 2, columnCount: 1, showPagination: true },
|
||||
legend: {
|
||||
position: 'left',
|
||||
orientation: 'auto',
|
||||
trackPositions: {
|
||||
'frame-0': 'top',
|
||||
'frame-1': 'bottom-right',
|
||||
'frame-2': 'bottom',
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
const legendForTrack = (trackId: string) =>
|
||||
wrapper.get(`[data-legend-track-id="${trackId}"] .waveform-chart__legend`)
|
||||
|
||||
expect(legendForTrack('frame-0').attributes('data-position')).toBe('top')
|
||||
expect(legendForTrack('frame-0').attributes('data-orientation')).toBe('horizontal')
|
||||
expect(legendForTrack('frame-1').attributes('data-position')).toBe('bottom-right')
|
||||
expect(legendForTrack('frame-1').attributes('data-orientation')).toBe('vertical')
|
||||
|
||||
await wrapper.setProps({
|
||||
legend: {
|
||||
position: 'left',
|
||||
orientation: 'vertical',
|
||||
trackPositions: { 'frame-0': 'top', 'frame-1': 'bottom-right', 'frame-2': 'bottom' },
|
||||
},
|
||||
})
|
||||
expect(legendForTrack('frame-0').attributes('data-orientation')).toBe('vertical')
|
||||
|
||||
await wrapper.get('.ant-pagination-next button').trigger('click')
|
||||
expect(legendForTrack('frame-2').attributes('data-position')).toBe('bottom')
|
||||
expect(legendForTrack('frame-2').attributes('data-orientation')).toBe('vertical')
|
||||
expect(legendForTrack('frame-3').attributes('data-position')).toBe('left')
|
||||
expect(legendForTrack('frame-3').attributes('data-orientation')).toBe('vertical')
|
||||
})
|
||||
|
||||
it('applies a configurable alpha background to every visible legend', async () => {
|
||||
const wrapper = await mountSizedChart(
|
||||
{
|
||||
|
||||
@@ -290,7 +290,6 @@ const containerStyle = computed(() => ({
|
||||
width: fixedWidth.value === undefined ? '100%' : `${fixedWidth.value}px`,
|
||||
height: fixedHeight.value === undefined ? '100%' : `${fixedHeight.value}px`,
|
||||
}))
|
||||
const legendPosition = computed<WaveformLegendPosition>(() => props.legend?.position ?? 'top-right')
|
||||
const isCleanView = computed(() => props.cleanView === true)
|
||||
const resolvedZeroLine = computed(() => {
|
||||
const width = props.zeroLine?.width
|
||||
@@ -311,13 +310,17 @@ const hiddenSeriesIdSet = computed(() =>
|
||||
: new Set(props.hiddenSeriesIds),
|
||||
)
|
||||
const resolvedHiddenSeriesIds = computed(() => Array.from(hiddenSeriesIdSet.value))
|
||||
const legendOrientation = computed<Exclude<WaveformLegendOrientation, 'auto'>>(() => {
|
||||
function resolveLegendPosition(trackId: string): WaveformLegendPosition {
|
||||
return props.legend?.trackPositions?.[trackId] ?? props.legend?.position ?? 'top-right'
|
||||
}
|
||||
|
||||
function resolveLegendOrientation(
|
||||
position: WaveformLegendPosition,
|
||||
): Exclude<WaveformLegendOrientation, 'auto'> {
|
||||
const orientation = props.legend?.orientation ?? 'auto'
|
||||
if (orientation !== 'auto') return orientation
|
||||
return legendPosition.value === 'top' || legendPosition.value === 'bottom'
|
||||
? 'horizontal'
|
||||
: 'vertical'
|
||||
})
|
||||
return position === 'top' || position === 'bottom' ? 'horizontal' : 'vertical'
|
||||
}
|
||||
const resolvedTitleText = computed(() => props.title?.text.trim() ?? '')
|
||||
const titleAreaReserved = computed(
|
||||
() =>
|
||||
@@ -1966,13 +1969,14 @@ onBeforeUnmount(() => {
|
||||
:key="`legend-${track.index}-${track.series.name}`"
|
||||
class="waveform-chart__legend-track"
|
||||
:data-legend-track-index="track.index"
|
||||
:data-legend-track-id="track.id"
|
||||
:transform="`translate(${track.left}, ${track.top})`"
|
||||
>
|
||||
<WaveformLegend
|
||||
v-if="!track.isEmpty && track.legendSeries.length > 1"
|
||||
:series="track.legendSeries"
|
||||
:position="legendPosition"
|
||||
:orientation="legendOrientation"
|
||||
:position="resolveLegendPosition(track.id)"
|
||||
:orientation="resolveLegendOrientation(resolveLegendPosition(track.id))"
|
||||
:background-color="legendBackgroundColor"
|
||||
:interactive="legendInteractive"
|
||||
:hidden-series-ids="resolvedHiddenSeriesIds"
|
||||
|
||||
@@ -371,6 +371,7 @@ export function buildTrackLayouts(options: BuildTrackLayoutsOptions): TrackLayou
|
||||
})
|
||||
|
||||
return {
|
||||
id: displayTrack.id,
|
||||
index,
|
||||
series,
|
||||
seriesList: displayTrack.visibleSeries,
|
||||
|
||||
@@ -72,6 +72,8 @@ export interface HoveredSeriesPoint extends DisplaySeries {
|
||||
* 轨道布局
|
||||
*/
|
||||
export interface TrackLayout {
|
||||
/** Stable track key derived from trackId, or from the series id when trackId is omitted. */
|
||||
id: string
|
||||
index: number
|
||||
series: DisplaySeries
|
||||
/** Visible series used by rendering and interaction code. */
|
||||
|
||||
Reference in New Issue
Block a user