求助:在Plotly.js中基于背景图片实现点击绘制直线
实现Plotly.js背景图上点击绘制连续直线
核心思路
- 维护变量记录上一次点击的坐标,每次点击时:
- 获取点击位置对应的图表数据坐标系值
- 若已有上一个点,将两个点作为线段端点添加到散点图数据数组
- 调用
Plotly.update更新图表,渲染新线段
- 给散点图配置
mode: 'lines+markers',同时显示线段与点击标记点,提升交互可视化效果
修改后的完整代码
<script src='https://cdn.plot.ly/plotly-2.16.1.min.js'></script> <div id='plotlyContainer'></div> <script> var d3 = Plotly.d3; var imgWidth = 0; var imgHeight = 0; const imgs = new Image(); let plotCon = document.getElementById('plotlyContainer'); // 记录上一次点击的坐标 let lastPoint = null; imgs.onload = function() { imgWidth = this.width; imgHeight = this.height; loadImgGraph(imgWidth, imgHeight); } imgs.src = 'https://i.sstatic.net/cRbua.png'; function loadImgGraph(imgWidth, imgHeight) { var data = [ { x: [], y: [], type: 'scatter', mode: 'lines+markers', // 同时显示线段和点击标记点 line: {color: '#ff0000', width: 2}, // 自定义直线样式 marker: {size: 6, color: '#0000ff'} // 自定义标记点样式 } ]; var layout = { autosize: false, width: imgWidth, height: imgHeight, xaxis: {range: [0, 100], dtick: 25, ticks: 'outside', tickwidth: 2, gridcolor: "black", gridwidth: 2, mirror: true, linecolor: 'black', linewidth: 1}, yaxis: {range: [140, 0], dtick: 20, ticks: 'outside', tickwidth: 2, gridcolor: "black", gridwidth: 2, mirror: true, linecolor: 'black', linewidth: 1}, margin: { l: 32, r: 20, b: 30, t: 30 }, images: [ { source: 'https://i.sstatic.net/cRbua.png', xref: 'paper', yref: 'paper', x: 0, y: 1, sizex: 1, sizey: 1, sizing: 'fill', opacity: 1, layer: 'below' } ], }; Plotly.newPlot('plotlyContainer', data, layout).then(clickEv); function clickEv() { var xaxis = plotCon._fullLayout.xaxis; var yaxis = plotCon._fullLayout.yaxis; var l = plotCon._fullLayout.margin.l; var t = plotCon._fullLayout.margin.t; plotCon.addEventListener('mousemove', function(evt) { var xInDataCoord = xaxis.p2c(evt.x - l); var yInDataCoord = yaxis.p2c(evt.y - t); Plotly.relayout(plotCon, 'title', ['x: ' + xInDataCoord.toFixed(2), 'y : ' + yInDataCoord.toFixed(2)].join('<br>')); }); plotCon.on('plotly_click', function(evt){ // 直接通过Plotly点击事件获取数据坐标系下的坐标 const clickX = evt.points[0].x; const clickY = evt.points[0].y; if (lastPoint) { // 添加线段的起点与终点 data[0].x.push(lastPoint.x, clickX); data[0].y.push(lastPoint.y, clickY); // 可选:添加null让每条线段独立(非连续折线) // data[0].x.push(null); // data[0].y.push(null); // 更新图表数据 Plotly.update(plotCon, data); } // 更新上一次点击的坐标记录 lastPoint = {x: clickX, y: clickY}; }); } } </script>
关键修改说明
- 状态变量新增:
lastPoint用于存储上一次点击的坐标,作为下一条线段的起点 - 数据系列优化:配置
mode: 'lines+markers'并自定义样式,让绘制的线段和点击点更清晰 - 点击事件逻辑优化:
- 利用
evt.points[0]直接获取转换后的data坐标系坐标,无需手动计算 - 存在上一个点时,将两个点坐标添加到数据数组,调用
Plotly.update高效更新图表
- 利用
- 可选分段模式:若需要让每条线段独立显示,可在每段线段后给x、y数组添加
null分隔
内容的提问来源于stack exchange,提问作者Vinodh Ganesh
相关产品推荐
相关产品推荐

