feat(mmsmapping): 添加 XML 映射生成功能和波形标记功能
- 新增 getXmlFromJsonApi 接口用于从 JSON 生成 XML 映射 - 添加 XML 映射相关的数据结构定义和响应处理 - 实现 XML 映射生成功能,支持 JSON 到 XML 的转换 - 添加波形图表点击事件处理和标记功能 - 实现趋势图表的标记点显示和标签功能 - 更新界面以支持 XML 映射预览和导出 - 优化图表交互体验,添加标记工具模式 - 重构部分界面组件以支持新的映射功能
This commit is contained in:
@@ -40,12 +40,68 @@ const emit = defineEmits<{
|
||||
end: number
|
||||
}
|
||||
]
|
||||
'chart-click': [
|
||||
value: {
|
||||
dataIndex: number
|
||||
axisValue: string | number
|
||||
}
|
||||
]
|
||||
}>()
|
||||
let chart: echarts.ECharts | any = null
|
||||
let isPanPointerDown = false
|
||||
|
||||
const getChartViewportRoot = () => chart?.getZr()?.painter?.getViewportRoot?.() as HTMLElement | undefined
|
||||
|
||||
const getAxisPixel = (dataIndex: number) => {
|
||||
const pixelValue = chart?.convertToPixel?.({ xAxisIndex: 0 }, dataIndex)
|
||||
|
||||
if (Array.isArray(pixelValue)) return Number(pixelValue[0])
|
||||
|
||||
return Number(pixelValue)
|
||||
}
|
||||
|
||||
const getClosestAxisDataIndex = (axisValue: unknown, offsetX: number) => {
|
||||
const xAxisData = props.options?.xAxis?.data
|
||||
|
||||
if (!Array.isArray(xAxisData) || !xAxisData.length) return -1
|
||||
|
||||
const candidateIndexes = new Set<number>()
|
||||
const axisNumber = Number(axisValue)
|
||||
const directIndex = xAxisData.findIndex((item: unknown) => item === axisValue)
|
||||
|
||||
if (Number.isFinite(axisNumber)) {
|
||||
candidateIndexes.add(Math.round(axisNumber))
|
||||
}
|
||||
|
||||
if (directIndex >= 0) {
|
||||
candidateIndexes.add(directIndex)
|
||||
}
|
||||
|
||||
xAxisData.forEach((item: unknown, index: number) => {
|
||||
if (String(item) === String(axisValue)) {
|
||||
candidateIndexes.add(index)
|
||||
}
|
||||
})
|
||||
|
||||
const validCandidates = Array.from(candidateIndexes).filter(index => index >= 0 && index < xAxisData.length)
|
||||
|
||||
if (validCandidates.length) {
|
||||
return validCandidates.reduce((closestIndex, currentIndex) => {
|
||||
const closestDistance = Math.abs(getAxisPixel(closestIndex) - offsetX)
|
||||
const currentDistance = Math.abs(getAxisPixel(currentIndex) - offsetX)
|
||||
|
||||
return currentDistance < closestDistance ? currentIndex : closestIndex
|
||||
}, validCandidates[0])
|
||||
}
|
||||
|
||||
return xAxisData.reduce((closestIndex: number, _item: unknown, currentIndex: number) => {
|
||||
const closestDistance = Math.abs(getAxisPixel(closestIndex) - offsetX)
|
||||
const currentDistance = Math.abs(getAxisPixel(currentIndex) - offsetX)
|
||||
|
||||
return currentDistance < closestDistance ? currentIndex : closestIndex
|
||||
}, 0)
|
||||
}
|
||||
|
||||
const resetChartCursor = () => {
|
||||
const viewportRoot = getChartViewportRoot()
|
||||
if (viewportRoot) viewportRoot.style.cursor = ''
|
||||
@@ -55,14 +111,20 @@ const resetChartCursor = () => {
|
||||
const updatePanCursor = (event: { offsetX: number; offsetY: number }) => {
|
||||
const viewportRoot = getChartViewportRoot()
|
||||
|
||||
if (!viewportRoot || props.options?.activeTool !== 'pan') {
|
||||
if (!viewportRoot || (props.options?.activeTool !== 'pan' && props.options?.activeTool !== 'mark')) {
|
||||
resetChartCursor()
|
||||
return
|
||||
}
|
||||
|
||||
// 平移只在图形绘图区内生效,鼠标样式同步限制到同一范围,避免坐标轴和空白区误导操作。
|
||||
const isInGrid = chart?.containPixel?.({ gridIndex: 0 }, [event.offsetX, event.offsetY])
|
||||
viewportRoot.style.cursor = isInGrid ? (isPanPointerDown ? 'grabbing' : 'grab') : ''
|
||||
viewportRoot.style.cursor = isInGrid
|
||||
? props.options?.activeTool === 'mark'
|
||||
? 'crosshair'
|
||||
: isPanPointerDown
|
||||
? 'grabbing'
|
||||
: 'grab'
|
||||
: ''
|
||||
}
|
||||
|
||||
const bindPanCursorEvents = () => {
|
||||
@@ -73,10 +135,12 @@ const bindPanCursorEvents = () => {
|
||||
zr.off('mousedown', handlePanCursorMouseDown)
|
||||
zr.off('mouseup', handlePanCursorMouseUp)
|
||||
zr.off('globalout', resetChartCursor)
|
||||
zr.off('click', handleChartClick)
|
||||
zr.on('mousemove', updatePanCursor)
|
||||
zr.on('mousedown', handlePanCursorMouseDown)
|
||||
zr.on('mouseup', handlePanCursorMouseUp)
|
||||
zr.on('globalout', resetChartCursor)
|
||||
zr.on('click', handleChartClick)
|
||||
}
|
||||
|
||||
const unbindPanCursorEvents = () => {
|
||||
@@ -87,9 +151,34 @@ const unbindPanCursorEvents = () => {
|
||||
zr.off('mousedown', handlePanCursorMouseDown)
|
||||
zr.off('mouseup', handlePanCursorMouseUp)
|
||||
zr.off('globalout', resetChartCursor)
|
||||
zr.off('click', handleChartClick)
|
||||
resetChartCursor()
|
||||
}
|
||||
|
||||
function handleChartClick(params: any) {
|
||||
if (props.options?.activeTool !== 'mark' || !chart) return
|
||||
|
||||
const event = params?.event?.event || params?.event || params
|
||||
const offsetX = Number(event?.offsetX)
|
||||
const offsetY = Number(event?.offsetY)
|
||||
|
||||
if (!Number.isFinite(offsetX) || !Number.isFinite(offsetY)) return
|
||||
if (!chart.containPixel?.({ gridIndex: 0 }, [offsetX, offsetY])) return
|
||||
|
||||
const convertedValue = chart.convertFromPixel?.({ xAxisIndex: 0 }, [offsetX, offsetY])
|
||||
const rawAxisValue = Array.isArray(convertedValue) ? convertedValue[0] : convertedValue
|
||||
const xAxisData = props.options?.xAxis?.data
|
||||
const dataIndex = getClosestAxisDataIndex(rawAxisValue, offsetX)
|
||||
const axisValue = Array.isArray(xAxisData) ? xAxisData[dataIndex] : dataIndex
|
||||
|
||||
if (!Number.isInteger(dataIndex) || dataIndex < 0 || axisValue === undefined) return
|
||||
|
||||
emit('chart-click', {
|
||||
dataIndex,
|
||||
axisValue
|
||||
})
|
||||
}
|
||||
|
||||
function handlePanCursorMouseDown(event: { offsetX: number; offsetY: number }) {
|
||||
isPanPointerDown = true
|
||||
updatePanCursor(event)
|
||||
|
||||
Reference in New Issue
Block a user