如何将D3.js v3散点图注释文本绑定到对应数据点
我明白你现在遇到的问题了——全局的vm.annotateText会让所有tooltip都显示同一段注释,没法对应到单个数据点对吧?咱们得把注释和触发操作的那个数据点绑定起来,下面是具体的实现方案:
解决方案思路
核心是把注释文本存储在对应的数据点对象里,而不是用全局变量。这样每个数据点有自己独立的注释,tooltip显示时直接读取当前数据点的注释内容即可。
1. 修改右键菜单事件,记录当前操作的数据点
首先在右键点击事件里,拿到当前点击的数据点对象,把它关联到后续的注释输入流程中:
eventGroup.select("circle") .attr("class", "dot") .attr("r", 4) .attr("cx", 10) .attr("cy", 10) .attr("fill", function(d) { return d.evtColor ? d.evtColor : "#229ae5"; }) .attr("stroke", function(d) { return d.evtColor ? d.evtColor : "#229ae5"; }) .attr("stroke-width", 2) .on("contextmenu", function(d) { d3.event.preventDefault(); // 阻止浏览器默认右键菜单弹出 var currentDotData = d; // 保存当前点击的数据点对象 var position = d3.mouse(this.parentNode); d3.select("#context-menu") .style("position", "absolute") .style("left", (d3.event.pageX - 220) + "px") .style("top", (d3.event.pageY - 70) + "px") .style("display", "inline-block") .on("click", function() { d3.select("#context-menu").style("display", "none"); var annotateBox = d3.select("#annotateBox") .style("position", "absolute") .style("left", (d3.event.pageX - 220) + "px") .style("top", (d3.event.pageY - 70) + "px") .style("display", "inline-block"); // 将当前数据点绑定到注释框元素上,方便后续获取 annotateBox.datum(currentDotData); // 如果该数据点已有注释,自动填充到文本框 annotateBox.select("textarea").property("value", currentDotData.annotation || ""); }); });
2. 修改Done按钮逻辑,把注释保存到对应数据点
调整你的AngularJS控制器里的vm.removeButton方法,将文本框内容存入绑定的数据点对象,而非全局变量:
vm.removeButton = function() { // 获取注释框绑定的当前数据点 var currentDotData = d3.select("#annotateBox").datum(); // 获取文本框输入的注释内容 var annotationText = d3.select("#annotateBox textarea").property("value"); // 把注释存入数据点的自定义属性中 currentDotData.annotation = annotationText.trim(); // 隐藏注释框 d3.select("#annotateBox").style("display", "none"); // 可选:如果tooltip需要即时更新,这里可以触发tooltip的刷新逻辑 // 比如使用d3.tip的话,可以调用tip.hide()再针对当前点调用tip.show() };
3. 修改Tooltip显示逻辑,读取当前数据点的注释
最后,在你的tooltip渲染逻辑里,替换全局变量为当前数据点的注释属性:
// 假设你用d3.tip实现tooltip,示例如下 var tip = d3.tip() .attr('class', 'd3-tip') .html(function(d) { // 读取当前数据点的annotation属性,而非全局的vm.annotateText var tooltipContent = '<div>数据点信息:xxx</div>'; if (d.annotation) { tooltipContent += '<div>注释:' + d.annotation + '</div>'; } return tooltipContent; });
额外注意事项
- 一定要加上
d3.event.preventDefault(),否则浏览器默认右键菜单会和你的自定义菜单同时弹出; - 如果需要注释持久化(比如刷新页面不丢失),可以把包含注释的数据点集合保存到后端接口或本地存储中。
内容的提问来源于stack exchange,提问作者user2128
相关产品推荐
相关产品推荐

