使用HTML textarea将数据绑定到每个元素

时间:2018-01-01 00:37:53

标签: javascript html angularjs d3.js

我正在尝试在我使用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>

我接下来要做的是,单击数据点时弹出的文本区域中添加的文本,我希望该文本绑定到该特定数据点而不是全部。有没有办法将文本区域分配给调用它的事件,而不是所有人都共有。目前,我作为一个数据点的一部分添加的任何文本也显示在其余数据点中。

1 个答案:

答案 0 :(得分:2)

有两种方法可以设置这些值:

  1. 更改原点;
  2. 使用局部变量(仅限v4,而不是你的情况)。
  3. 更改基准是最常见的,惯用的D3方式,可以做你想要的。此外,由于局部变量在v3中不起作用,因此这是您应该使用的解决方案:

    解决方案1:更改原点

    这可能是最容易记录的方式。毕竟,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元素,而不是更改数据结构:

    解决方案2:局部变量

    在D3 v4中引入了{p> Local variables,并且不太常见。基本上,您需要定义本地...

    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>