(function() { const dom = document.getElementById('chart-spectrum'); const width = dom.clientWidth || 800; const height = 400; const margin = { top: 20, right: 30, bottom: 40, left: 50 }; const innerW = width - margin.left - margin.right; const innerH = height - margin.top - margin.bottom; // 模拟频谱数据(实际使用时用 FFT 结果替换) const frequencies = []; const powers = []; for (let i = 0; i < 100; i++) { frequencies.push(i * 0.05); // 模拟两个主频 + 噪声 powers.push( 50 * Math.exp(-((i * 0.05 - 1.5) ** 2) / 0.1) + 35 * Math.exp(-((i * 0.05 - 3.2) ** 2) / 0.15) + Math.random() * 5 ); } const svg = d3.select(dom).append('svg').attr('width', width).attr('height', height); const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`); const xScale = d3.scaleLinear().domain([0, 5]).range([0, innerW]); const yScale = d3.scaleLinear().domain([0, d3.max(powers) * 1.1]).range([innerH, 0]); g.append('g').call(d3.axisBottom(xScale)).attr('transform', `translate(0,${innerH})`); g.append('g').call(d3.axisLeft(yScale)); g.append('text').attr('x', innerW / 2).attr('y', innerH + 35).attr('text-anchor', 'middle').text('频率 (Hz)'); g.append('text').attr('transform', 'rotate(-90)').attr('x', -innerH / 2).attr('y', -40).attr('text-anchor', 'middle').text('功率'); // 面积填充 const areaGen = d3.area() .x((d, i) => xScale(frequencies[i])) .y0(innerH).y1((d, i) => yScale(powers[i])); g.append('path').datum(powers) .attr('d', areaGen).attr('fill', '#3b82f6').attr('fill-opacity', 0.2); // 频谱曲线 const lineGen = d3.line() .x((d, i) => xScale(frequencies[i])) .y((d, i) => yScale(powers[i])); g.append('path').datum(powers) .attr('d', lineGen).attr('fill', 'none').attr('stroke', '#3b82f6').attr('stroke-width', 2); // 峰值标注 const peakIdx = powers.indexOf(d3.max(powers)); g.append('line') .attr('x1', xScale(frequencies[peakIdx])).attr('y1', yScale(powers[peakIdx])) .attr('x2', xScale(frequencies[peakIdx])).attr('y2', innerH) .attr('stroke', '#ef4444').attr('stroke-dasharray', '3,3'); g.append('text') .attr('x', xScale(frequencies[peakIdx]) + 5).attr('y', yScale(powers[peakIdx]) - 5) .attr('font-size', 10).attr('fill', '#ef4444') .text('主频: ' + frequencies[peakIdx].toFixed(2) + 'Hz'); window.addEventListener('resize', () => { const w = dom.clientWidth || 800; svg.attr('width', w); xScale.range([0, w - margin.left - margin.right]); }); })();