refactor(chart): enforce 400-line source limit
Some checks failed
Package component / package (push) Failing after 4m19s
Some checks failed
Package component / package (push) Failing after 4m19s
This commit is contained in:
351
src/components/WaveformChartView.vue
Normal file
351
src/components/WaveformChartView.vue
Normal file
@@ -0,0 +1,351 @@
|
||||
<script setup lang="ts">
|
||||
import { Pagination } from 'ant-design-vue'
|
||||
import { toRefs } from 'vue'
|
||||
|
||||
import { WaveformAnnotationContextMenu, WaveformAnnotationLayer } from './annotation'
|
||||
import WaveformAnnotationEditor from './annotation/WaveformAnnotationEditor.vue'
|
||||
import type { WaveformChartController } from './core/useWaveformChartController'
|
||||
import { WaveformHoverHost } from './interaction'
|
||||
import { WaveformHoverLayer, WaveformLegend, WaveformTrack } from './rendering'
|
||||
|
||||
const props = defineProps<{ controller: WaveformChartController }>()
|
||||
const {
|
||||
displayMode,
|
||||
activeInteractionMode,
|
||||
isCleanView,
|
||||
selection,
|
||||
containerStyle,
|
||||
overlayMode,
|
||||
resolvedChartLeftMargin,
|
||||
titleAreaHeight,
|
||||
pointerInsideChart,
|
||||
handleNativeContextMenu,
|
||||
titleAreaReserved,
|
||||
titleAreaStyle,
|
||||
titleVisible,
|
||||
titleMeasureStyle,
|
||||
resolvedTitleText,
|
||||
titleVisualStyle,
|
||||
titleTextStyle,
|
||||
titleLayout,
|
||||
chartWidth,
|
||||
drawingHeight,
|
||||
hasWaveformData,
|
||||
requestViewportReset,
|
||||
trackLayouts,
|
||||
clipPathId,
|
||||
chartTopMargin,
|
||||
gridCells,
|
||||
hasVisibleWaveformData,
|
||||
zoomable,
|
||||
isZoomMode,
|
||||
innerWidth,
|
||||
innerHeight,
|
||||
handleSharedPointerMove,
|
||||
beginSharedViewportDrag,
|
||||
finishViewportDrag,
|
||||
cancelViewportDrag,
|
||||
clearHover,
|
||||
handleAnnotationClick,
|
||||
handleAnnotationContextMenu,
|
||||
resolveFrameNumber,
|
||||
frameStyle,
|
||||
axes,
|
||||
resolvedZeroLine,
|
||||
timeUnit,
|
||||
yLabel,
|
||||
handleIndependentPointerMove,
|
||||
beginViewportDrag,
|
||||
hoverState,
|
||||
showTooltip,
|
||||
selectionBox,
|
||||
renderedAnnotations,
|
||||
annotationsVisible,
|
||||
handleExistingAnnotationContextMenu,
|
||||
beginAnnotationDrag,
|
||||
handleAnnotationMove,
|
||||
endAnnotationDrag,
|
||||
resolveLegendPosition,
|
||||
resolveLegendOrientation,
|
||||
legendBackgroundColor,
|
||||
legendInteractive,
|
||||
resolvedHiddenSeriesIds,
|
||||
toggleSeriesVisibility,
|
||||
resolvedXLabel,
|
||||
xAxisTitleY,
|
||||
hasChartArea,
|
||||
gridOptions,
|
||||
pageCount,
|
||||
currentPage,
|
||||
getPageSize,
|
||||
chartTracks,
|
||||
goToPage,
|
||||
annotationInteraction,
|
||||
editorDraft,
|
||||
contextMenu,
|
||||
editorSeries,
|
||||
editorSeriesOptions,
|
||||
confirmAnnotation,
|
||||
cancelAnnotation,
|
||||
changeDraftSeries,
|
||||
editContextAnnotation,
|
||||
deleteContextAnnotation,
|
||||
chartHeight,
|
||||
setContainer,
|
||||
setSvgElement,
|
||||
setTitleMeasureElement,
|
||||
setSharedOverlayElement,
|
||||
} = toRefs(props.controller)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:ref="setContainer"
|
||||
class="waveform-chart"
|
||||
:class="[
|
||||
`waveform-chart--${displayMode}`,
|
||||
`waveform-chart--interaction-${activeInteractionMode}`,
|
||||
{
|
||||
'waveform-chart--clean': isCleanView,
|
||||
'waveform-chart--panning': selection?.mode === 'pan',
|
||||
},
|
||||
]"
|
||||
:style="containerStyle"
|
||||
:data-display-mode="displayMode"
|
||||
:data-interaction-mode="activeInteractionMode"
|
||||
:data-overlay-mode="overlayMode"
|
||||
:data-chart-left-margin="resolvedChartLeftMargin"
|
||||
:data-title-area-height="titleAreaHeight"
|
||||
@pointerenter="pointerInsideChart = true"
|
||||
@pointerleave="pointerInsideChart = false"
|
||||
@contextmenu.capture="handleNativeContextMenu"
|
||||
>
|
||||
<div
|
||||
v-if="titleAreaReserved"
|
||||
class="waveform-chart__title-area"
|
||||
:style="titleAreaStyle"
|
||||
:role="titleVisible ? 'heading' : undefined"
|
||||
:aria-level="titleVisible ? 2 : undefined"
|
||||
:aria-hidden="isCleanView || undefined"
|
||||
>
|
||||
<span
|
||||
:ref="setTitleMeasureElement"
|
||||
class="waveform-chart__title-measure"
|
||||
:style="titleMeasureStyle"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{{ resolvedTitleText }}
|
||||
</span>
|
||||
<span v-if="titleVisible" class="waveform-chart__title-visual" :style="titleVisualStyle">
|
||||
<span
|
||||
class="waveform-chart__title-text"
|
||||
:style="titleTextStyle"
|
||||
:data-title-scale="titleLayout.scale"
|
||||
:data-title-wrapped="titleLayout.wrapped || undefined"
|
||||
>
|
||||
{{ resolvedTitleText }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<svg
|
||||
:ref="setSvgElement"
|
||||
class="waveform-chart__svg"
|
||||
:width="chartWidth"
|
||||
:height="drawingHeight"
|
||||
role="img"
|
||||
:aria-label="hasWaveformData ? '波形折线图' : '暂无波形数据'"
|
||||
@dblclick="requestViewportReset"
|
||||
>
|
||||
<defs>
|
||||
<clipPath
|
||||
v-for="track in trackLayouts"
|
||||
:id="`${clipPathId}-${track.index}`"
|
||||
:key="`${clipPathId}-${track.index}`"
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
>
|
||||
<rect :width="track.width" :height="track.height" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<g :transform="`translate(${resolvedChartLeftMargin}, ${chartTopMargin})`">
|
||||
<g
|
||||
v-if="displayMode !== 'compact' && !isCleanView"
|
||||
class="waveform-chart__grid-slots"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<g
|
||||
v-for="cell in gridCells"
|
||||
:key="`grid-slot-${cell.slotIndex}`"
|
||||
:transform="`translate(${cell.left}, ${cell.top})`"
|
||||
>
|
||||
<rect
|
||||
v-if="!cell.series"
|
||||
class="waveform-chart__grid-slot-placeholder"
|
||||
:width="cell.width"
|
||||
:height="cell.cellHeight"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
<rect
|
||||
v-if="displayMode !== 'independent' && trackLayouts.length && hasVisibleWaveformData"
|
||||
:ref="setSharedOverlayElement"
|
||||
class="waveform-chart__overlay waveform-chart__overlay--shared"
|
||||
:class="{
|
||||
'is-zoomable': zoomable && isZoomMode,
|
||||
'is-annotating': activeInteractionMode === 'annotation',
|
||||
}"
|
||||
:width="innerWidth"
|
||||
:height="innerHeight"
|
||||
@pointermove="handleSharedPointerMove"
|
||||
@pointerdown="beginSharedViewportDrag"
|
||||
@pointerup="finishViewportDrag"
|
||||
@pointercancel="cancelViewportDrag"
|
||||
@pointerleave="clearHover"
|
||||
@click="handleAnnotationClick"
|
||||
@contextmenu="handleAnnotationContextMenu"
|
||||
/>
|
||||
|
||||
<!-- 轨道渲染 -->
|
||||
<WaveformTrack
|
||||
v-for="track in trackLayouts"
|
||||
:key="`${track.index}-${track.series.name}`"
|
||||
:track="track"
|
||||
:clip-path-id="clipPathId"
|
||||
:inner-width="innerWidth"
|
||||
:zoomable="zoomable"
|
||||
:display-mode="displayMode"
|
||||
:interaction-mode="activeInteractionMode"
|
||||
:frame-number="resolveFrameNumber(track.index)"
|
||||
:frame-style="frameStyle"
|
||||
:axes="axes"
|
||||
:clean-view="isCleanView"
|
||||
:zero-line="resolvedZeroLine"
|
||||
:time-unit="timeUnit"
|
||||
:y-label="yLabel"
|
||||
@pointer-move="handleIndependentPointerMove($event, track.index)"
|
||||
@pointer-down="beginViewportDrag($event, track.index, true)"
|
||||
@pointer-up="finishViewportDrag"
|
||||
@pointer-cancel="cancelViewportDrag"
|
||||
@pointer-leave="clearHover"
|
||||
@click="handleAnnotationClick($event, track.index)"
|
||||
@contextmenu="handleAnnotationContextMenu($event, track.index)"
|
||||
/>
|
||||
|
||||
<WaveformHoverLayer
|
||||
:state="hoverState"
|
||||
:tracks="trackLayouts"
|
||||
:clip-path-id="clipPathId"
|
||||
:visible="showTooltip"
|
||||
/>
|
||||
|
||||
<rect
|
||||
v-if="selectionBox && selection?.mode === 'box'"
|
||||
class="waveform-chart__zoom-selection"
|
||||
:x="selectionBox.x"
|
||||
:y="selectionBox.y"
|
||||
:width="selectionBox.width"
|
||||
:height="selectionBox.height"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<WaveformAnnotationLayer
|
||||
v-if="!isCleanView"
|
||||
:annotations="renderedAnnotations"
|
||||
:visible="annotationsVisible"
|
||||
@contextmenu="handleExistingAnnotationContextMenu"
|
||||
@drag-start="beginAnnotationDrag"
|
||||
@move="handleAnnotationMove"
|
||||
@drag-end="endAnnotationDrag"
|
||||
/>
|
||||
|
||||
<g v-if="!isCleanView" class="waveform-chart__legend-layer">
|
||||
<g
|
||||
v-for="track in trackLayouts"
|
||||
: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="resolveLegendPosition(track.id)"
|
||||
:orientation="resolveLegendOrientation(resolveLegendPosition(track.id))"
|
||||
:background-color="legendBackgroundColor"
|
||||
:interactive="legendInteractive"
|
||||
:hidden-series-ids="resolvedHiddenSeriesIds"
|
||||
:width="track.width ?? innerWidth"
|
||||
:height="track.height"
|
||||
@toggle="toggleSeriesVisibility"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<text
|
||||
v-if="resolvedXLabel && !isCleanView"
|
||||
class="waveform-chart__label waveform-chart__x-label"
|
||||
:x="innerWidth / 2"
|
||||
:y="xAxisTitleY"
|
||||
text-anchor="middle"
|
||||
>
|
||||
{{ resolvedXLabel }}
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<text
|
||||
v-if="hasChartArea && !hasWaveformData"
|
||||
class="waveform-chart__empty"
|
||||
:x="chartWidth / 2"
|
||||
:y="drawingHeight / 2"
|
||||
text-anchor="middle"
|
||||
>
|
||||
暂无有效波形数据
|
||||
</text>
|
||||
</svg>
|
||||
|
||||
<Pagination
|
||||
v-if="gridOptions.showPagination && pageCount > 1 && !isCleanView"
|
||||
class="waveform-chart__pagination"
|
||||
aria-label="波形分页"
|
||||
:current="currentPage"
|
||||
:page-size="getPageSize(gridOptions)"
|
||||
:total="chartTracks.length"
|
||||
:show-size-changer="false"
|
||||
:show-quick-jumper="false"
|
||||
@change="goToPage"
|
||||
/>
|
||||
|
||||
<WaveformAnnotationEditor
|
||||
v-if="editorDraft && !isCleanView"
|
||||
:annotation="editorDraft.annotation"
|
||||
:mode="editorDraft.mode"
|
||||
:series="editorSeries"
|
||||
:series-options="editorSeriesOptions"
|
||||
:time-unit="timeUnit"
|
||||
@confirm="confirmAnnotation"
|
||||
@cancel="cancelAnnotation"
|
||||
@series-change="changeDraftSeries"
|
||||
/>
|
||||
|
||||
<WaveformAnnotationContextMenu
|
||||
v-if="!isCleanView"
|
||||
:visible="contextMenu !== null"
|
||||
:x="contextMenu?.x || 0"
|
||||
:y="contextMenu?.y || 0"
|
||||
:can-edit="Boolean(contextMenu?.annotationId)"
|
||||
@edit="editContextAnnotation"
|
||||
@delete="deleteContextAnnotation"
|
||||
@close="annotationInteraction.closeContextMenu"
|
||||
/>
|
||||
|
||||
<WaveformHoverHost
|
||||
:state="hoverState"
|
||||
:visible="showTooltip"
|
||||
:time-unit="timeUnit"
|
||||
:container-width="chartWidth"
|
||||
:container-height="chartHeight"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user