vtk.js

vtk.js


火柴棍绘制

<ol> <li> <p><strong>数据提取与范围设置</strong>:</p> <pre><code class="language-javascript">const xData = data.frequency.image_data; const yData = data.lg_energy.image_data; const xExtent = d3.extent(xData); const yExtent = d3.extent(yData);</code></pre> <ul> <li><code>xData</code> 和 <code>yData</code> 从输入数据中提取出频率和能量的数据数组。</li> <li><code>d3.extent</code> 用于计算数据的最小值和最大值,分别为 <code>xExtent</code> 和 <code>yExtent</code>。</li> </ul> </li> <li> <p><strong>检查数据范围</strong>:</p> <pre><code class="language-javascript">if (xExtent[0] === 0) { xExtent[0] = xExtent[0]; } if (xExtent[1] === 0) { xExtent[1] = xExtent[1]; } if (yExtent[0] === 0) { yExtent[0] = yExtent[0]; } if (yExtent[1] === 0) { yExtent[1] = yExtent[1]; }</code></pre> <ul> <li>这部分代码看起来是多余的,因为它没有改变 <code>xExtent</code> 和 <code>yExtent</code> 的值。如果要进行额外的处理,可以添加实际的逻辑。</li> </ul> </li> <li> <p><strong>设置图形宽高和容器</strong>:</p> <pre><code class="language-javascript">const width = imageWidth; const height = imageHeight; let gs = g.select('.line-g'); if (gs.size() === 0) { gs = g.append('g').attr('class', 'line-g').style('pointer-events', 'none'); } gs.html('');</code></pre> <ul> <li><code>width</code> 和 <code>height</code> 被设置为输入的图形尺寸。</li> <li>选择或创建一个名为 <code>line-g</code> 的 <code>&amp;lt;g&amp;gt;</code> 元素,用于包含所有图形元素,并确保它不响应鼠标事件。</li> </ul> </li> <li> <p><strong>创建 X 轴和 Y 轴比例尺</strong>:</p> <pre><code class="language-javascript">const xAxisScale = d3.scaleLinear() .domain([xExtent[0], xExtent[1]]) .rangeRound([60, width - 60]); gs.append('g') .attr('class', 'axis-x') .attr('transform', `translate(0,${height - 60})`) .call(d3.axisBottom(xAxisScale).ticks(6)) .selectAll('path,line,text') .attr('stroke', '#fff');</code></pre> <ul> <li><code>xAxisScale</code> 和 <code>yAxisScale</code> 设置了 X 轴和 Y 轴的比例尺,将数据范围映射到图形的像素范围。</li> <li>将 X 轴添加到图形底部,并设置其刻度和样式。</li> </ul> </li> <li> <p><strong>绘制 Y 轴</strong>:</p> <pre><code class="language-javascript">const yAxisScale = d3.scaleLinear() .domain([yExtent[0], yExtent[1]]) .rangeRound([height - 60, 10]); gs.append('g') .attr('class', 'axis-y') .attr('transform', 'translate(60,10)') .call(d3.axisLeft(yAxisScale)) .selectAll('path,line,text') .attr('stroke', '#fff');</code></pre> <ul> <li>同样设置 Y 轴比例尺,并将 Y 轴添加到图形左侧。</li> </ul> </li> <li> <p><strong>添加 X 轴标签</strong>:</p> <pre><code class="language-javascript">gs.append('text') .attr('dy', '.75em') .attr('y', height - 30) .attr('x', function (d) { return (xAxisScale(xExtent[1]) - xAxisScale(xExtent[0])) / 2 + 60; }) .attr('text-anchor', 'middle') .attr('font-size', 12) .text('频率') .style('fill', '#fff');</code></pre> <ul> <li>在 X 轴下方添加“频率”标签,并进行适当的定位和样式设置。</li> </ul> </li> <li> <p><strong>绘制矩形标记</strong>:</p> <pre><code class="language-javascript">gs.selectAll('.rect') .data(yData) .enter() .append('rect') .style('stroke', function (d) { return 'blue'; }) .attr('width', 4) .attr('height', function (d) { const y = yAxisScale(d); return height - 60 - y &amp;lt; 0 ? 0 : height - 60 - y; }) .style('cursor', 'pointer') .attr('fill', 'blue') .style('pointer-events', 'all') .attr('x', function (d, index) { const x = xAxisScale(xData[index]) - 2; return x; }) .attr('y', function (d, index) { return yAxisScale(d); }) .attr('title', (d, index) =&amp;gt; `${d}`) .attr('r', 5);</code></pre> <ul> <li>绘制蓝色矩形标记,位置根据 <code>xData</code> 和 <code>yData</code> 数据设置,并支持鼠标悬停提示。</li> </ul> </li> <li> <p><strong>绘制圆形标记</strong>:</p> <pre><code class="language-javascript">gs.selectAll('.circle') .data(yData) .enter() .append('circle') .style('stroke', function (d) { return 'red'; }) .style('cursor', 'pointer') .attr('fill', 'red') .style('pointer-events', 'all') .attr('cx', function (d, index) { const x = xAxisScale(xData[index]); return x; }) .attr('cy', function (d, index) { return yAxisScale(d); }) .attr('title', (d, index) =&amp;gt; `${d}`) .attr('r', 5);</code></pre> <ul> <li>绘制红色圆形标记,位置设置与矩形相同,并支持鼠标悬停提示。</li> </ul> </li> <li><strong>添加能量标签</strong>: <pre><code class="language-javascript">const txt = gs.append('text') .attr('dy', '.75em') .attr('x', 5) .attr('y', function (d) { return (yAxisScale(yExtent[0]) - yAxisScale(yExtent[1])) / 2 - 30; }) .attr('text-anchor', 'middle') .attr('font-size', 12) .style('fill', '#fff'); txt.append('tspan') .attr('dx', '1em') .text('能'); txt.append('tspan') .attr('dy', '1em') .attr('dx', '-1em') .text('量');</code></pre> <ul> <li>在图形上添加“能量”标签,由两个 <code>tspan</code> 元素组成,用于显示“能”和“量”两个字。</li> </ul></li> </ol> <p>这段代码的核心任务是通过 D3.js 绘制一个带有 X 轴和 Y 轴的散点图,并在图上显示标记和标签。</p> <p>完整代码</p> <pre><code class="language-javascript"> scatterPointPOD_DMD(data, imageWidth, imageHeight, g) { const xData = data.frequency.image_data; const yData = data.lg_energy.image_data; const xExtent = d3.extent(xData); const yExtent = d3.extent(yData); if (xExtent[0] === 0) { xExtent[0] = xExtent[0]; } if (xExtent[1] === 0) { xExtent[1] = xExtent[1]; } if (yExtent[0] === 0) { yExtent[0] = yExtent[0]; } if (yExtent[1] === 0) { yExtent[1] = yExtent[1]; } const width = imageWidth; const height = imageHeight; let gs = g.select('.line-g'); if (gs.size() === 0) { gs = g.append('g').attr('class', 'line-g').style('pointer-events', 'none'); } gs.html(''); const xAxisScale = d3.scaleLinear() .domain([xExtent[0], xExtent[1]]) .rangeRound([60, width - 60]); gs.append('g') // 创建x轴比例尺 .attr('class', 'axis-x') .attr('transform', `translate(0,${height - 60})`) .call(d3.axisBottom(xAxisScale).ticks(6)) .selectAll('path,line,text') .attr('stroke', '#fff'); const yAxisScale = d3.scaleLinear() .domain([yExtent[0], yExtent[1]]) .rangeRound([height - 60, 10]); gs.append('g') .attr('class', 'axis-y') .attr('transform', 'translate(60,10)') .call(d3.axisLeft(yAxisScale)) .selectAll('path,line,text') .attr('stroke', '#fff'); gs.append('text') .attr('dy', '.75em') .attr('y', height - 30) .attr('x', function (d) { return (xAxisScale(xExtent[1]) - xAxisScale(xExtent[0])) / 2 + 60; }) .attr('text-anchor', 'middle') .attr('font-size', 12) .text('频率') .style('fill', '#fff'); gs.selectAll('.rect') .data(yData) .enter() .append('rect') .style('stroke', function (d) { return 'blue'; }) .attr('width', 4) .attr('height', function (d) { const y = yAxisScale(d); return height - 60 - y &amp;lt; 0 ? 0 : height - 60 - y; }) .style('cursor', 'pointer') .attr('fill', 'blue') .style('pointer-events', 'all') .attr('x', function (d, index) { const x = xAxisScale(xData[index]) - 2; return x; }) .attr('y', function (d, index) { return yAxisScale(d); }) .attr('title', (d, index) =&amp;gt; `${d}`) .attr('r', 5); gs.selectAll('.circle') .data(yData) .enter() .append('circle') .style('stroke', function (d) { return 'red'; }) .style('cursor', 'pointer') .attr('fill', 'red') .style('pointer-events', 'all') .attr('cx', function (d, index) { const x = xAxisScale(xData[index]); return x; }) .attr('cy', function (d, index) { return yAxisScale(d); }) .attr('title', (d, index) =&amp;gt; `${d}`) .attr('r', 5); const txt = gs.append('text') .attr('dy', '.75em') .attr('x', 5) .attr('y', function (d) { return (yAxisScale(yExtent[0]) - yAxisScale(yExtent[1])) / 2 - 30; }) .attr('text-anchor', 'middle') .attr('font-size', 12) .style('fill', '#fff'); txt.append('tspan') .attr('dx', '1em') .text('能'); txt.append('tspan') .attr('dy', '1em') .attr('dx', '-1em') .text('量'); }</code></pre>

页面列表

ITEM_HTML