javascript - D3 绑定(bind)文本和 SVG

标签 javascript d3.js

我正在创建我的第一个 d3.js 项目,其中包含可以拖动、添加或删除居中文本的圆圈,但我似乎无法将文本绑定(bind)到圆圈。我看到了一些问题 similar to mine ,但我希望这足够不同,因为我尝试应用这些解决方案,但它们没有用。我不仅在寻找解决方案,而且我想知道我在这里做错了什么。

任何见解都会非常有帮助!

我尝试创建一个组变量 group 并假设我可以使用它来绑定(bind)两个元素。我的心智模型有什么问题?

chart = {

  const dataset = [
  {start: new Date("2019-09-23 1:00 AM"), target: 70},
  {start: new Date("2019-09-23 8:00 AM"), target: 75},
  {start: new Date("2019-09-23 9:00 PM"), target: 70},
  {start: new Date("2019-09-23 1:00 PM"), target: 75},
  {start: new Date("2019-09-23 5:00 PM"), target: 70},
  {start: new Date("2019-09-23 6:00 PM"), target: 65},
]

  var xScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, function(d) {
      return d.x_pos
    })]).range([0, width]);

  const svg = d3.create("svg")
      .attr("viewBox", [0, 0, width, height])
      .attr("stroke-width", 2);

    svg.append("g")
      .call(xAxis)

  var group = svg.selectAll('g')
  .data(dataset)
  .enter()
  .append("g")
  .attr("transform", 
        "translate(" + margin.left + "," + margin.top + ")")

   group.append("circle")
     .data(dataset)
     .enter()
     .append("circle")
     .join("circle")
     .attr("cx", d => x(d.start))
     .attr("cy", 55)
     .attr("r", 30)
     .attr("fill", "red")
     .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .on("click", removeElement);

  group.append("text")
    .data(dataset)
    .enter()
    .append("text")
    .attr("x", function(d) { return x(d.start) - 10; })
    .attr("y", function(d) { return 60; })
    .style("fill", "white")
    .text(function(d) { return d.target })
   .call(d3.drag()
    .on("drag", dragged))
   .on("click", removeElement)


  svg.on("click", function() {
    var coords = d3.mouse(this);

    var newData = {
      x: d3.event.x,
      y: d3.event.y,
      target: 0
    };

    dataset.push(newData);

    group.append("circle")
      .attr("cx", function(d) {
        return x(d.start);
      })
      .attr("cy", function(d) {
        return 55;
      })
      .attr("r", 30)
      .style("fill", "red")
      .attr('id', function(d, i) {
        return 'circle_' + i;
      })
      .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended))
      .on("click", removeElement);

    group.append("text")
    .data(dataset)
    .enter()
    .append("text")
    .attr("x", function(d) { return x(d.start) - 10; })
    .attr("y", function(d) { return 60; })
    .style("fill", "white")
    .text(function(d) { return d.target })
   .call(d3.drag()
   .on("drag", dragged))
   .on("click", removeElement)

  })

  function dragstarted(d) {
    d3.select(this).raise().attr("stroke", "black");
  }

  function dragged(d) {
    // tried adding .select("circle") from prior SO posts
    d3.select(this)
      .attr("cx", d.x = d3.event.x)
      .attr("cy", d.y = 55);
    d3.select(this) //.select("text")
      .attr("x", d.x = d3.event.x - 10)
      .attr("y", d.y = 60);
  }

  function dragended(d) {
       d3.select(this).attr("stroke", null);
  }

  function removeElement(d) {
    d3.event.stopPropagation()
    d3.select(this)
      .remove();
  }

  return svg.node();
}
x = d3.scaleTime()
    .domain([new Date("2019, 9, 23 12:00 AM"), new Date("2019, 9, 23, 11:59 PM")])
    .rangeRound([margin.left, width - margin.right])

interval = d3.timeHour.every(1)

xAxis = g => g
    .attr("transform", `translate(0,${height - margin.bottom})`)
    .call(g => g.append("g")
        .call(d3.axisBottom(x)
            .ticks(interval)
            .tickSize(-height + margin.top + margin.bottom)
            .tickFormat(() => null))
        .call(g => g.select(".domain")
            .attr("fill", "#ddd")
            .attr("stroke", null))
        .call(g => g.selectAll(".tick line")
            .attr("stroke", "#fff")
            .attr("stroke-opacity", d => d <= d3.timeHour(d) ? 1 : 0.5)))
    .call(g => g.append("g")
        .call(d3.axisBottom(x)
            .ticks(d3.timeHour)
            .tickPadding(0))
        .attr("text-anchor", null)
        .call(g => g.select(".domain").remove())
        .call(g => g.selectAll("text").attr("x", 6)))

margin = ({top: 10, right: 0, bottom: 20, left: 0})
height = 120
d3 = require("d3@5")

笔记本链接:https://observablehq.com/d/c0b23251c8bdafa2

最佳答案

您需要将 svg 视为一组元素,其中元素也可以是一组元素。

圆圈里面有文字是什么样子的?

<svg...>
    <g id="myGroup">
          <circle style="" cx="250" cy="250" r="245"></circle>
          <text x="50%" y="50%" stroke="#111"> Hello !</text>
    </g>
</svg>

现在如果你想从头开始生成这个 svg :

var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var group = document.createElementNS("http://www.w3.org/2000/svg","g");
group.setAttribute("id","myGroup")
var newCircle = document.createElementNS(svgNS,"circle"); 
var newText = document.createElementNS(svgNS,"text");
newText.setAttributeNS(null,"x", "50%");     
newText.setAttributeNS(null,"y", "50%"); 
document.getElementById("svg").appendChild(myGroup);
document.getElementById("myGroup").appendChild(newCircle);

圆圈和文字绑定(bind)成一个组。然后拖动你的组,而不是你的圈子 ;)

关于javascript - D3 绑定(bind)文本和 SVG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58082571/

相关文章:

javascript - D3图上的显示区域

Javascript Uncaught Reference错误函数未定义

javascript - 如何将星期几格式化为单个字母?

javascript - foreignObject 中的背景图像隐藏了 Firefox 上的其他 svg 元素

javascript - 如何在自定义视频播放器上激活全屏

javascript - 使用复选框过滤数据 - D3

javascript - 在 javascript 中搜索 (D3)

javascript - 在 Promise 中调用函数

javascript - jQuery 替换两个存在于 TD 中的 div 类

javascript - 使用 window.onerror 处理 JavaScript 错误