From 7b1d44bba8b94e58b3a6e3349055e3e5e06c2fd3 Mon Sep 17 00:00:00 2001 From: Jerry Date: Wed, 18 Dec 2024 21:11:55 +0800 Subject: [PATCH] feat: add on background-layer --- src/pages/Feature/D3/DataDemo.tsx | 19 +- src/pages/Feature/D3/Frequency.tsx | 201 ++++++++++++++------ src/pages/Feature/D3/components/DataUnit.ts | 21 +- 3 files changed, 171 insertions(+), 70 deletions(-) diff --git a/src/pages/Feature/D3/DataDemo.tsx b/src/pages/Feature/D3/DataDemo.tsx index 785eadd..bfc56d7 100644 --- a/src/pages/Feature/D3/DataDemo.tsx +++ b/src/pages/Feature/D3/DataDemo.tsx @@ -366,7 +366,6 @@ ${JSON.stringify(match.customInfo, null, 2)} const typeHeight = typeHeights[typeIndex]; const typeGroup = mainGroup.append('g').attr('class', 'type-group').attr('transform', `translate(0,${currentY})`); - console.log(typeHeight, 'typeHeight'); // 添加类型边框 // 使用实际计算的高度绘制边框 typeGroup @@ -418,8 +417,8 @@ ${JSON.stringify(match.customInfo, null, 2)} typeData.ranges.forEach((freq: any, i: any) => { const startX = getXPosition(freq.range[0]); const endX = getXPosition(freq.range[1]); - const blockHeight = 25; - const yOffset = 35 + freq.level * (blockHeight + 5); + const blockHeight = 25; // 频率块高度 + const yOffset = 35 + freq.level * (blockHeight + 5); // 计算频率块的垂直位置 // 创建频率块组 const freqGroup = typeGroup @@ -512,13 +511,13 @@ ${JSON.stringify(match.customInfo, null, 2)} // 添加矩形 freqGroup - .append('rect') - .attr('x', startX) - .attr('y', 0) - .attr('width', Math.max(endX - startX, 2)) - .attr('height', blockHeight) - .attr('fill', `url(#${patternId})`) - .attr('rx', 3) + .append('rect') // 添加矩形 + .attr('x', startX) // 与频率块重叠 + .attr('y', 0) // 与频率块重叠 + .attr('width', Math.max(endX - startX, 2)) // 确保宽度不为0 + .attr('height', blockHeight) // 确保高度不为0 + .attr('fill', `url(#${patternId})`) // 使用斜线填充 + .attr('rx', 3) // 圆角 .style('pointer-events', 'none'); // 确保斜线不会干扰点击事件 } }); diff --git a/src/pages/Feature/D3/Frequency.tsx b/src/pages/Feature/D3/Frequency.tsx index bfc56d7..e2af45a 100644 --- a/src/pages/Feature/D3/Frequency.tsx +++ b/src/pages/Feature/D3/Frequency.tsx @@ -143,72 +143,163 @@ const Frequency = () => { // 添加鼠标移动事件监听 backgroundLayer.on('mousemove', function (event) { - // 获取鼠标在 SVG 中的位置,需要考虑偏移 + // 1. 获取鼠标位置并调整到正确的坐标系 const [mouseX] = d3.pointer(event); - const adjustedX = mouseX - margin.left; - // 找到最近的刻度值 - const nearestTick = frequencyTicks.reduce((prev: any, curr: any) => { - const prevX = xScale(prev.label); - const currX = xScale(curr.label); - return Math.abs(currX - adjustedX) < Math.abs(prevX - adjustedX) ? curr : prev; - }); + // 2. 创建一个更精确的频率计算方法 + // 首先找到鼠标位置两侧的刻度点 + let leftTick = frequencyTicks[0]; + let rightTick = frequencyTicks[1]; - // 清除并重绘虚线 - guidelineGroup.selectAll('*').remove(); - const xPos = xScale(nearestTick.label); + for (let i = 0; i < frequencyTicks.length - 1; i++) { + const currentTickX = xScale(frequencyTicks[i].label); + const nextTickX = xScale(frequencyTicks[i + 1].label); - // 绘制新的虚线 - guidelineGroup - .append('line') - .attr('x1', xPos) - .attr('y1', 0) - .attr('x2', xPos) - .attr('y2', totalHeight - margin.top) - .attr('stroke', '#666') - .attr('stroke-width', 1) - .attr('stroke-dasharray', '4,4'); + if (mouseX >= currentTickX && mouseX <= nextTickX) { + leftTick = frequencyTicks[i]; + rightTick = frequencyTicks[i + 1]; + break; + } + } + + // 3. 计算当前位置对应的频率值 + // 使用线性插值计算鼠标位置对应的频率值 + const leftX = xScale(leftTick.label); + const rightX = xScale(rightTick.label); + const progress = (mouseX - leftX) / (rightX - leftX); + + // 使用对数插值来处理频率值,因为频率范围是对数刻度 + const currentFrequency = Math.exp( + Math.log(leftTick.value) * (1 - progress) + Math.log(rightTick.value) * progress, + ); - // 查找并显示频率信息 - const currentHz = nearestTick.value; + // 4. 查找匹配的频率范围 const matches = data.flatMap((type: any) => type.ranges - .filter((range: any) => currentHz >= range.range[0] && currentHz <= range.range[1]) + .filter((range: any) => { + // 精确的范围匹配 + return currentFrequency >= range.range[0] && currentFrequency <= range.range[1]; + }) .map((range: any) => ({ typeName: type.typeName, ...range, })), ); - // 更新提示信息显示 - if (matches.length > 0) { - tooltip - .style('visibility', 'visible') - .style('left', `${event.pageX + 10}px`) - .style('top', `${event.pageY - 10}px`).html(` -
-
- 频率: ${nearestTick.label} -
- ${matches - .map( - (match: any) => ` -
-
- ${match.typeName} - ${match.frequencyName} -
-
- 范围: ${formatFrequency(match.range[0])} - ${formatFrequency(match.range[1])} -
+ // 5. 绘制虚线 + guidelineGroup.selectAll('*').remove(); + guidelineGroup + .append('line') + .attr('x1', mouseX) + .attr('y1', 0) + .attr('x2', mouseX) + .attr('y2', totalHeight - margin.top) + .attr('stroke', '#666') + .attr('stroke-width', 1) + .attr('stroke-dasharray', '4,4'); + + // 6. 更新 tooltip 显示 + const tooltipContent = ` +
+
+ 当前频率: ${formatFrequency(currentFrequency)} +
+ ${ + matches.length > 0 + ? matches + .map( + (match: any) => ` +
+
+ ${match.typeName} - ${match.frequencyName}
- `, - ) - .join('
')} -
- `); - } else { - tooltip.style('visibility', 'hidden'); +
+ 频率范围: ${formatFrequency(match.range[0])} - ${formatFrequency(match.range[1])} +
+
+${JSON.stringify(match.customInfo, null, 2)}
+            
+
+ `, + ) + .join('
') + : '
当前频率范围内无匹配项
' } +
+ `; + + tooltip + .style('visibility', 'visible') + .style('left', `${event.pageX - 240}px`) + .style('top', `${event.pageY - 70}px`) + .html(tooltipContent); + + // 获取鼠标在 SVG 中的位置,需要考虑偏移 + // const [mouseX] = d3.pointer(event); + // const adjustedX = mouseX - margin.left; + + // // 找到最近的刻度值 + // const nearestTick = frequencyTicks.reduce((prev: any, curr: any) => { + // const prevX = xScale(prev.label); + // const currX = xScale(curr.label); + // return Math.abs(currX - adjustedX) < Math.abs(prevX - adjustedX) ? curr : prev; + // }); + + // // 清除并重绘虚线 + // guidelineGroup.selectAll('*').remove(); + // const xPos = xScale(nearestTick.label); + + // // 绘制新的虚线 + // guidelineGroup + // .append('line') + // .attr('x1', xPos) + // .attr('y1', 0) + // .attr('x2', xPos) + // .attr('y2', totalHeight - margin.top) + // .attr('stroke', '#666') + // .attr('stroke-width', 1) + // .attr('stroke-dasharray', '4,4'); + + // // 查找并显示频率信息 + // const currentHz = nearestTick.value; + // const matches = data.flatMap((type: any) => + // type.ranges + // .filter((range: any) => currentHz >= range.range[0] && currentHz <= range.range[1]) + // .map((range: any) => ({ + // typeName: type.typeName, + // ...range, + // })), + // ); + + // // 更新提示信息显示 + // if (matches.length > 0) { + // tooltip + // .style('visibility', 'visible') + // .style('left', `${event.pageX + 10}px`) + // .style('top', `${event.pageY - 10}px`).html(` + //
+ //
+ // 频率: ${nearestTick.label} + //
+ // ${matches + // .map( + // (match: any) => ` + //
+ //
+ // ${match.typeName} - ${match.frequencyName} + //
+ //
+ // 范围: ${formatFrequency(match.range[0])} - ${formatFrequency(match.range[1])} + //
+ //
+ // `, + // ) + // .join('
')} + //
+ // `); + // } else { + // tooltip.style('visibility', 'hidden'); + // } }); // 处理鼠标离开事件 @@ -290,8 +381,8 @@ const Frequency = () => { if (matches.length > 0) { tooltip .style('visibility', 'visible') - .style('left', `${event.pageX + 10}px`) - .style('top', `${event.pageY - 10}px`).html(` + .style('left', `${event.pageX - 240}px`) + .style('top', `${event.pageY - 60}px`).html(`
频率: ${tickValue} @@ -453,8 +544,8 @@ ${JSON.stringify(match.customInfo, null, 2)} // 显示hover tooltip hoverTooltip .style('visibility', 'visible') - .style('left', `${event.pageX + 10}px`) - .style('top', `${event.pageY - 10}px`).html(` + .style('left', `${event.pageX - 240}px`) + .style('top', `${event.pageY - 60}px`).html(`
${typeData.typeName} - ${freq.frequencyName} diff --git a/src/pages/Feature/D3/components/DataUnit.ts b/src/pages/Feature/D3/components/DataUnit.ts index bb98392..bc632f1 100644 --- a/src/pages/Feature/D3/components/DataUnit.ts +++ b/src/pages/Feature/D3/components/DataUnit.ts @@ -37,7 +37,7 @@ export const data: any = [ }, { frequencyName: '设备A', - range: [1000000, 5000000000], // 100kHz-500kHz + range: [90000000, 140000000], // 100kHz-500kHz color: '#4299e1', slashStyle: { forward: false, backward: true }, customInfo: { @@ -48,7 +48,18 @@ export const data: any = [ }, { frequencyName: '设备A', - range: [10000000, 500000000], // 100kHz-500kHz + range: [1000000, 500000000], // 100kHz-500kHz + color: '#4299e1', + slashStyle: { forward: false, backward: true }, + customInfo: { + description: '测试设备', + power: '10W', + status: '正常', + }, + }, + { + frequencyName: '设备A', + range: [10000000, 50000000], // 100kHz-500kHz color: '#4299e1', slashStyle: { forward: true, backward: false }, customInfo: { @@ -59,7 +70,7 @@ export const data: any = [ }, { frequencyName: '设备A', - range: [10000000, 50000000000], // 100kHz-500kHz + range: [10000000, 500000000], // 100kHz-500kHz color: '#4299e1', slashStyle: { forward: true, backward: false }, customInfo: { @@ -75,7 +86,7 @@ export const data: any = [ ranges: [ { frequencyName: '设备c', - range: [1000000, 500000000], // 100kHz-500kHz + range: [1000000, 5000000], // 100kHz-500kHz color: '#4299e1', slashStyle: { forward: true, backward: false }, customInfo: { @@ -206,7 +217,7 @@ export const data: any = [ }, { frequencyName: '设备A', - range: [1000000, 600000000000], // 100kHz-500kHz + range: [1000000, 600000000], // 100kHz-500kHz color: '#4299e1', slashStyle: { forward: false, backward: true }, customInfo: {