2

This should be a multilinegraph i have an array like this as data:

data = [[point:{x: 0, y: 1},point:{x: 0, y: 3}], [point:{x: 3, y: 1},point:{x: 3, y: 3}], [point:{x: 0, y: 6},point:{x: 1, y: 9}], [point:{x: 2, y: 6},point:{x: 3, y: 2}]]

code:

   gr.line = d3.line()
        .x((d) => d.point.x)
        .y((d) => d.point.y)
    let allGroup = gr.g.selectAll(".pathGroup").data(data)
    allGroup.exit().remove()
    let g = allGroup.enter()
        .append("g")
        .attr("class", "pathGroup")


    g.append("path")
        .attr("class", "line")
        .attr("stroke", (d) => {
            return 'red'
        })
        .attr("d", (d) => gr.line(d))

I want to add circles to the path. If i want to append circles to the group (in this case the variable g), i get the whole array. But i just need each item from the array to append the circle. I want to do it with data binding because i want to remove the items if the data changes. I get it done with forEach loop but i think is not a good solution. Somebody has an idea how to get it done with data binding?

2
  • Please share your line generator and tell us where do you want to append the circle (the first or the second point). Also, just for your information, .attr("d", (d) => gr.line(d)) is the same of .attr("d", gr.line). Commented Apr 12, 2018 at 23:41
  • i added line generator. I want to add circles at each point. The circles should be in the same group like the path Commented Apr 12, 2018 at 23:45

1 Answer 1

1

Your data is not valid. Judging by your line generator, you should have an array of objects, like this:

var data = [[{point:{x: 10, y: 10}}, {point:{x: 100, y: 30}}], 
    [{point:{x: 30, y: 100}},{point:{x: 230, y: 30}}]
];

Back to the question: you're correct, doing any kind of loop (as forEach) to append elements in a D3 code is normally a bad idea.

Just use the individual datum of the outer selection (which is an array itself) in the inner selection:

g.selectAll(null)
    .data(d=>d)
    .enter()
    .append("circle")
    //etc...

It's worth mentioning that I'm using selectAll(null) here because the enter/update/exit selections seem to operate in the outer selection, not in the inner selection. If that's not correct change that line accordingly.

Here is a demo, I'm changing the data values to better see the paths and the circles:

var data = [
  [{
    point: {
      x: 10,
      y: 10
    }
  }, {
    point: {
      x: 100,
      y: 30
    }
  }],
  [{
    point: {
      x: 30,
      y: 100
    }
  }, {
    point: {
      x: 230,
      y: 30
    }
  }]
];

var svg = d3.select("svg");

var line = d3.line()
  .x((d) => d.point.x)
  .y((d) => d.point.y);

var allGroup = svg.selectAll(".pathGroup").data(data);

var g = allGroup.enter()
  .append("g")
  .attr("class", "pathGroup")

g.append("path")
  .attr("class", "line")
  .attr("stroke", "red")
  .attr("stroke-width", "1px")
  .attr("d", line);

g.selectAll(null)
  .data(d => d)
  .enter()
  .append("circle")
  .attr("r", 4)
  .attr("fill", "teal")
  .attr("cx", d => d.point.x)
  .attr("cy", d => d.point.y);
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>

Sign up to request clarification or add additional context in comments.

5 Comments

thank you this works :) I want to have the exit().remove() for the inner and outer selection. Is this possible?
i have problem to update the lines after call the function multiple times. if i call g.selectAll('path').attr("d", line) it does not work.
@KTWorks please post a new question, with all the relevant details.
ok thank you very much. Here is my new Question: stackoverflow.com/questions/49820455/…
@Gerado Furtado maybe i you have time. Can you look on my question?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.