feat(chart): add multi-axis overlay controls
This commit is contained in:
@@ -77,10 +77,9 @@ describe('waveform annotation controls', () => {
|
||||
)
|
||||
expect(wrapper.get('.waveform-annotation-editor__coordinates').text()).toContain('Y2')
|
||||
expect(wrapper.get('button.is-primary').attributes('disabled')).toBeDefined()
|
||||
await vi.waitFor(
|
||||
() => expect(wrapper.findAllComponents(ColorPicker)).toHaveLength(3),
|
||||
{ timeout: 5000 },
|
||||
)
|
||||
await vi.waitFor(() => expect(wrapper.findAllComponents(ColorPicker)).toHaveLength(3), {
|
||||
timeout: 5000,
|
||||
})
|
||||
const colorPickers = wrapper.findAllComponents(ColorPicker)
|
||||
expect(wrapper.findAll('.waveform-annotation-editor__color-field')).toHaveLength(3)
|
||||
expect(colorPickers.map((picker) => picker.props('pureColor'))).toEqual([
|
||||
@@ -156,10 +155,9 @@ describe('waveform annotation controls', () => {
|
||||
},
|
||||
})
|
||||
await flushPromises()
|
||||
await vi.waitFor(
|
||||
() => expect(wrapper.findAllComponents(ColorPicker)).toHaveLength(3),
|
||||
{ timeout: 5000 },
|
||||
)
|
||||
await vi.waitFor(() => expect(wrapper.findAllComponents(ColorPicker)).toHaveLength(3), {
|
||||
timeout: 5000,
|
||||
})
|
||||
|
||||
expect(
|
||||
wrapper.findAllComponents(ColorPicker).map((picker) => picker.props('pureColor')),
|
||||
|
||||
@@ -32,11 +32,27 @@ const createTrack = (
|
||||
|
||||
describe('waveform annotation markup', () => {
|
||||
it('interpolates a line value at the pointer X', () => {
|
||||
expect(interpolateAnnotationPoint([{ x: 0, y: 0 }, { x: 2, y: 10 }], 1)).toEqual({
|
||||
expect(
|
||||
interpolateAnnotationPoint(
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 2, y: 10 },
|
||||
],
|
||||
1,
|
||||
),
|
||||
).toEqual({
|
||||
x: 1,
|
||||
y: 5,
|
||||
})
|
||||
expect(interpolateAnnotationPoint([{ x: 0, y: 0 }, { x: 2, y: 10 }], 3)).toBeNull()
|
||||
expect(
|
||||
interpolateAnnotationPoint(
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 2, y: 10 },
|
||||
],
|
||||
3,
|
||||
),
|
||||
).toBeNull()
|
||||
})
|
||||
|
||||
it('sorts line candidates by screen distance and keeps series metadata', () => {
|
||||
@@ -106,10 +122,16 @@ describe('waveform annotation markup', () => {
|
||||
})
|
||||
|
||||
it('filters invalid entries and separates nearby annotation boxes', () => {
|
||||
const track = createTrack(0, 'a', 0, [
|
||||
{ x: 0, y: 1 },
|
||||
{ x: 1, y: 2 },
|
||||
], 300)
|
||||
const track = createTrack(
|
||||
0,
|
||||
'a',
|
||||
0,
|
||||
[
|
||||
{ x: 0, y: 1 },
|
||||
{ x: 1, y: 2 },
|
||||
],
|
||||
300,
|
||||
)
|
||||
const annotations: WaveformAnnotation[] = [
|
||||
{ id: 'first', seriesId: 'a', x: 1, y: 2, text: '第一个标注' },
|
||||
{ id: 'second', seriesId: 'a', x: 1, y: 2, text: '第二个标注' },
|
||||
@@ -136,10 +158,16 @@ describe('waveform annotation markup', () => {
|
||||
})
|
||||
|
||||
it('prefers centered vertical placements and moves below a top boundary', () => {
|
||||
const track = createTrack(0, 'a', 0, [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 1, y: 5 },
|
||||
], 200)
|
||||
const track = createTrack(
|
||||
0,
|
||||
'a',
|
||||
0,
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 1, y: 5 },
|
||||
],
|
||||
200,
|
||||
)
|
||||
|
||||
const centered = layoutAnnotations(
|
||||
[{ id: 'centered', seriesId: 'a', x: 1, y: 5, text: '居中' }],
|
||||
@@ -166,10 +194,16 @@ describe('waveform annotation markup', () => {
|
||||
})
|
||||
|
||||
it('reverses direction when the preferred placement is clipped by a boundary', () => {
|
||||
const track = createTrack(0, 'a', 0, [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 1, y: 5 },
|
||||
], 200)
|
||||
const track = createTrack(
|
||||
0,
|
||||
'a',
|
||||
0,
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 1, y: 5 },
|
||||
],
|
||||
200,
|
||||
)
|
||||
|
||||
const nearTop = layoutAnnotations(
|
||||
[{ id: 'top-space', seriesId: 'a', x: 1, y: 7.5, text: '顶部空间不足' }],
|
||||
@@ -207,10 +241,16 @@ describe('waveform annotation markup', () => {
|
||||
})
|
||||
|
||||
it('uses later directional candidates when vertical candidates collide', () => {
|
||||
const track = createTrack(0, 'a', 0, [
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 1, y: 5 },
|
||||
], 200)
|
||||
const track = createTrack(
|
||||
0,
|
||||
'a',
|
||||
0,
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: 1, y: 5 },
|
||||
],
|
||||
200,
|
||||
)
|
||||
const rendered = layoutAnnotations(
|
||||
[
|
||||
{ id: 'one', seriesId: 'a', x: 1, y: 5, text: '同一位置一' },
|
||||
@@ -225,5 +265,4 @@ describe('waveform annotation markup', () => {
|
||||
expect(rendered[1].placement).not.toBe('top')
|
||||
expect(rendered[1].box).not.toMatchObject({ x: rendered[0].box.x, y: rendered[0].box.y })
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -91,7 +91,9 @@ export function findAnnotationSeriesCandidates(
|
||||
},
|
||||
]
|
||||
})
|
||||
.sort((first, second) => first.distance - second.distance || first.trackIndex - second.trackIndex)
|
||||
.sort(
|
||||
(first, second) => first.distance - second.distance || first.trackIndex - second.trackIndex,
|
||||
)
|
||||
}
|
||||
let annotationTextMeasurementContext: CanvasRenderingContext2D | null | undefined
|
||||
|
||||
@@ -113,7 +115,9 @@ export function measureAnnotationTextWidth(text: string): number {
|
||||
}
|
||||
}
|
||||
}
|
||||
return annotationTextMeasurementContext?.measureText(text).width ?? fallbackAnnotationTextWidth(text)
|
||||
return (
|
||||
annotationTextMeasurementContext?.measureText(text).width ?? fallbackAnnotationTextWidth(text)
|
||||
)
|
||||
}
|
||||
|
||||
export function resolveAnnotationStyle(style?: WaveformAnnotationStyle) {
|
||||
|
||||
@@ -51,14 +51,7 @@ export interface AnnotationBoxLayout {
|
||||
}
|
||||
|
||||
export type AnnotationPlacement =
|
||||
| 'top'
|
||||
| 'bottom'
|
||||
| 'right'
|
||||
| 'left'
|
||||
| 'top-right'
|
||||
| 'top-left'
|
||||
| 'bottom-right'
|
||||
| 'bottom-left'
|
||||
'top' | 'bottom' | 'right' | 'left' | 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'
|
||||
|
||||
export interface RenderedAnnotation {
|
||||
annotation: WaveformAnnotation
|
||||
|
||||
Reference in New Issue
Block a user