【问题标题】:Binding data to each element using HTML textarea使用 HTML textarea 将数据绑定到每个元素
【发布时间】:2018-06-11 07:19:48
【问题描述】:

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

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

【问题讨论】:

    标签: javascript html angularjs d3.js


    【解决方案1】:

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

    1. 更改基准;
    2. 使用局部变量(仅限 v4,不适用于您的情况)。

    更改基准是 D3 最常见、最惯用的方式来做你想做的事。此外,由于局部变量在 v3 中不起作用,因此您应该使用以下解决方案:

    解决方案 1:更改基准

    这可能是最简单和记录在案的方法。毕竟,D3(或 DDD)的意思是 Data-Driven Documents

    这样做很容易:只需使用事件侦听器中的第一个参数设置您想要的任何属性,传统上称为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:局部变量

    Local variables 是在 D3 v4 中引入的,并且不太常见。基本上,你需要定义本地...

    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>

    【讨论】:

    • 感谢您提供这两种解决方案。我正在尝试实现我的第一个解决方案,但由于某种原因它不会读取 d3.select("textarea").node().value = d.textArea || ""; d3.select("button").on("click", function() { d.textArea = d3.select("textarea").node().value; });但我正在尝试调试它,我确定有一些小错误。
    猜你喜欢
    • 2020-11-17
    • 1970-01-01
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-23
    • 2016-02-23
    • 1970-01-01
    相关资源
    最近更新 更多