修复图表实例标识并扩展版本兼容性
All checks were successful
Package component / package (push) Successful in 6m0s

This commit is contained in:
李启源
2026-07-21 16:37:35 +08:00
parent 65a0c4933c
commit 07e9855eac
9 changed files with 448 additions and 9 deletions

View File

@@ -188,6 +188,38 @@ describe('WaveformChart', () => {
})),
})
it('keeps clip path ids unique across chart instances', async () => {
const data: WaveformData = {
kind: 'series',
series: [
{
id: 'channel-1',
name: '通道 1',
data: {
kind: 'points',
points: [
{ x: 0, y: 0 },
{ x: 1, y: 1 },
],
},
},
],
}
const first = await mountSizedChart(data)
const second = await mountSizedChart(data)
const firstClipPathId = first.get('clipPath').attributes('id')
const secondClipPathId = second.get('clipPath').attributes('id')
expect(firstClipPathId).toBeTruthy()
expect(secondClipPathId).toBeTruthy()
expect(firstClipPathId).not.toBe(secondClipPathId)
expect(first.get('[clip-path]').attributes('clip-path')).toContain(firstClipPathId)
expect(second.get('[clip-path]').attributes('clip-path')).toContain(secondClipPathId)
first.unmount()
second.unmount()
})
it('places start, middle, and end step transitions at the expected X positions', async () => {
const lineTypes = ['step-start', 'step-middle', 'step-end', 'step-after'] as const
const wrapper = await mountSizedChart({

View File

@@ -21,7 +21,6 @@ import {
onMounted,
ref,
shallowRef,
useId,
watch,
type CSSProperties,
} from 'vue'
@@ -79,6 +78,7 @@ import { buildTrackLayouts, measureTrackYAxisClearance, Y_AXIS_EXPONENT_GAP } fr
import { calculateRotatedTitleLayout, TITLE_AREA_HORIZONTAL_PADDING } from './core/title'
import { usePreparedWaveformSeries } from './core/useWaveformData'
import WaveformAnnotationEditor from './annotation/WaveformAnnotationEditor.vue'
import { useWaveformInstanceId } from '../utils/waveformId'
const props = withDefaults(
defineProps<{
@@ -174,7 +174,7 @@ const suppressHoverUntilMove = ref(false)
const currentPage = ref(1)
const resizeObserver = shallowRef<ResizeObserver>()
const zoomBehaviors = new Map<number | 'shared', ZoomBehavior<SVGRectElement, unknown>>()
const clipPathId = `${useId()}-waveform-clip`
const clipPathId = useWaveformInstanceId('waveform-clip')
const internalInteractionMode = ref<WaveformInteractionMode | undefined>(undefined)
const internalHiddenSeriesIds = ref(new Set(props.defaultHiddenSeriesIds))
const annotationInteraction = useWaveformAnnotationInteraction()

View File

@@ -1,10 +1,11 @@
<script setup lang="ts">
import { computed, defineAsyncComponent, nextTick, ref, useId, watch } from 'vue'
import { computed, defineAsyncComponent, nextTick, ref, watch } from 'vue'
import type { WaveformAnnotation } from '../../types'
import { formatAnnotationTime, formatPlainNumber, type TimeUnit } from '../../utils'
import { ANNOTATION_MAX_TEXT_LENGTH, resolveAnnotationStyle } from './markup'
import type { AnnotationSeriesCandidate, AnnotationSeriesInfo } from './types'
import { useWaveformInstanceId } from '../../utils/waveformId'
const ColorPicker = defineAsyncComponent(async () => {
await import('vue3-colorpicker/style.css')
@@ -29,7 +30,7 @@ const emit = defineEmits<{
}>()
const textarea = ref<HTMLTextAreaElement>()
const dialogTitleId = `waveform-annotation-editor-title-${useId()}`
const dialogTitleId = useWaveformInstanceId('waveform-annotation-editor-title')
const text = ref('')
const borderColor = ref('')
const textColor = ref('')

View File

@@ -8,6 +8,30 @@ import WaveformAnnotationLayer from './WaveformAnnotationLayer.vue'
import WaveformAnnotationToolbar from './WaveformAnnotationToolbar.vue'
describe('waveform annotation controls', () => {
it('keeps dialog title ids unique across editor instances', () => {
const first = mount(WaveformAnnotationEditor, {
props: {
annotation: { id: 'first', seriesId: 'a', x: 1, y: 2, text: '说明' },
mode: 'edit',
},
})
const second = mount(WaveformAnnotationEditor, {
props: {
annotation: { id: 'second', seriesId: 'a', x: 1, y: 2, text: '说明' },
mode: 'edit',
},
})
const firstTitleId = first.get('h2').attributes('id')
const secondTitleId = second.get('h2').attributes('id')
expect(firstTitleId).toBeTruthy()
expect(secondTitleId).toBeTruthy()
expect(firstTitleId).not.toBe(secondTitleId)
expect(first.get('[role="dialog"]').attributes('aria-labelledby')).toBe(firstTitleId)
expect(second.get('[role="dialog"]').attributes('aria-labelledby')).toBe(secondTitleId)
})
it('allows changing the annotation series inside the editor', async () => {
const wrapper = mount(WaveformAnnotationEditor, {
props: {