我正在尝试在我使用d3.js v3创建的散点图上实现注释功能。当我单击每个数据点时,文本框出现在我输入文本的位置。添加文本后,它将显示为该特定数据点的工具提示。我执行它的方式是:
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() {
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");
d3.select("#annotateBox")
.style("position", "absolute")
.style("left", (d3.event.pageX - 220) + "px")
.style("top", (d3.event.pageY - 70) + "px")
.style("display", "inline-block");
});
});
在HTML文件中,我定义了addAnnotation
按钮和textarea
,我将在其中添加文字:
<ul id="context-menu" class="menu" style="display:none;">
<li class="addAnnotation"><a href="">Add Annotation</a></li>
</ul>
<div id="annotateBox" style="display:none;">
<div class="annotateInput" style="display:table-caption">
<textarea rows="3" cols="50" maxlength="100" style="color:black" ng-model="vm.annotateText" autofocus></textarea>
<button type="button" class="btn btn-primary pull-right" ng-click="vm.removeButton()">Done</button>
</div>
</div>
我接下来要做的是,单击数据点时弹出的文本区域中添加的文本,我希望该文本绑定到该特定数据点而不是全部。有没有办法将文本区域分配给调用它的事件,而不是所有人都共有。目前,我作为一个数据点的一部分添加的任何文本也显示在其余数据点中。
答案 0 :(得分:2)
有两种方法可以设置这些值:
更改基准是最常见的,惯用的D3方式,可以做你想要的。此外,由于局部变量在v3中不起作用,因此这是您应该使用的解决方案:
这可能是最容易记录的方式。毕竟,D3(或DDD)意味着数据驱动文档。
这样做非常简单:只需使用事件监听器中的第一个参数设置任何所需的属性,传统上称为d
(对于“基准”):
selection.on("contextmenu", function(d) {
//first argument here ---------------^
例如,名为textArea
的属性:
d3.select("textarea").node().value = d.textArea || "";
d3.select("button").on("click", function() {
d.textArea = d3.select("textarea").node().value;
});
请注意:要使此解决方案有效,您的datum
必须是对象。
这是一个非常基本的示例,基于您的代码。右键单击每个圆圈,键入内容并单击“完成”。在另一个圆圈中执行相同操作,然后再次右键单击上一个圆圈:您将看到圆圈保留数据。
var svg = d3.select("svg");
var color = d3.scaleOrdinal(d3.schemeCategory10);
var data = d3.range(5).map(function(d) {
return {
name: "foo"
}
});
var circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", 15)
.attr("cy", 50)
.attr("cx", function(_, i) {
return 50 + 50 * i
})
.style("fill", function(_, i){
return color(i);
});
circles.on("contextmenu", function(d) {
d3.event.preventDefault();
d3.select("#annotateBox")
.style("position", "absolute")
.style("left", (d3.event.pageX - 50) + "px")
.style("top", (d3.event.pageY + 20) + "px")
.style("display", "inline-block");
d3.select("textarea").node().value = d.textArea || "";
d3.select("button").on("click", function() {
d.textArea = d3.select("textarea").node().value;
})
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="annotateBox" style="display:none;">
<div class="annotateInput" style="display:table-caption">
<textarea rows="3" cols="50" maxlength="100" style="color:black" autofocus></textarea>
<button type="button">Done</button>
</div>
</div>
<svg></svg>
由于您正在使用D3 v3,下一个解决方案现在不适合您(更改v4取决于您拥有的代码,它可能非常简单,也可能是一场噩梦)。但是,描述局部变量如何工作很有意思,因为变量绑定到DOM元素,而不是更改数据结构:
var local = d3.local();
...并在事件侦听器中设置值:
var thisCircle = this;
d3.select("textarea").node().value = local.get(thisCircle) || "";
d3.select("button").on("click", function() {
local.set(thisCircle, d3.select("textarea").node().value);
});
以下是演示:
var svg = d3.select("svg");
var color = d3.scaleOrdinal(d3.schemeCategory10);
var local = d3.local();
var data = d3.range(5).map(function(d) {
return {
name: "foo"
}
});
var circles = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", 15)
.attr("cy", 50)
.attr("cx", function(_, i) {
return 50 + 50 * i
})
.style("fill", function(_, i) {
return color(i);
});
circles.on("contextmenu", function(d) {
var thisCircle = this;
d3.event.preventDefault();
d3.select("#annotateBox")
.style("position", "absolute")
.style("left", (d3.event.pageX - 50) + "px")
.style("top", (d3.event.pageY + 20) + "px")
.style("display", "inline-block");
d3.select("textarea").node().value = local.get(thisCircle) || "";
d3.select("button").on("click", function() {
local.set(thisCircle, d3.select("textarea").node().value);
})
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="annotateBox" style="display:none;">
<div class="annotateInput" style="display:table-caption">
<textarea rows="3" cols="50" maxlength="100" style="color:black" autofocus></textarea>
<button type="button">Done</button>
</div>
</div>
<svg></svg>