Home > Mobile >  Creating custom SVG element in D3 that binds to data
Creating custom SVG element in D3 that binds to data

Time:10-19

I'm working on a visualization of geometric spanners. My visualization has a hexagon that visits each point. The hexagon is constructed from three paths. Right now, my code shows a hexagon appearing and disappearing at each node sequentially. This is good, but I'd like to show the hexagon moving from one node to the next. I think I'd have to create a custom SVG element in HTML or bind two sets of data to the same figure (1-the positions to visit, 2-path positions to create the hexagon).

plot = {
  const height = 600
  const width = 800
  const numPoints = 10
  let nodes = []

  for (let i = 0; i < numPoints; i  ) {
    var x = Math.floor(Math.random() * (750 - 100)   100)
    var y = Math.floor(Math.random() * (550 - 100)   100)
    let point = {
        "x": x,
        "y": y
    }
    nodes.push(point)
  }
        
  const svg = d3
    .create("svg")
    .attr("width", width)
    .attr("height", height)
    .attr("viewBox", [0, 0, width, height])
    .attr("class", "svg-bg");

  const rayLength = 200;

  const data = [{source: [-rayLength, 0], target: [rayLength,0]},
                {source: [-rayLength*Math.cos(Math.PI/3),-rayLength*Math.sin(Math.PI/3)],                       target: [rayLength*Math.cos(Math.PI/3),rayLength*Math.sin(Math.PI/3)]},
                {source: [rayLength*Math.cos(Math.PI/3),-rayLength*Math.sin(Math.PI/3)],                       target: [-rayLength*Math.cos(Math.PI/3),rayLength*Math.sin(Math.PI/3)]},]

  const local = d3.local();
  var group = svg.selectAll("g")
    .data(nodes)
    .enter()
    .append("g")
    .attr("transform", function (d,i) {
      local.set(this,i);return "translate("   d.x   ","   d.y   ")"
    })

  var spanner = group.selectAll("path")
    .data(data)
    .enter()
    .append("path")
    .transition()
    .delay(function(d,i) {const p = local.get(this); return p*2000})
    .attr("d", function(d) {return "M" d.source[0] " " d.source[1] "L" d.target[0] " " d.target[1]})
    .attr("stroke", "#D3D3D3")
    .transition()
    .delay(function(d,i) {const p = local.get(this); return 1500})
  .remove()

  
  var circles = group.append("circle")
    .attr("r",3)
    .attr("fill","black")

  return svg.node()
}

CodePudding user response:

You can create a unique group for your spanner and then update its transform attribute by using the javascript setInterval function, and a d3 transition to smoothly translate it. I think you don't have to create a spanner for each point or bind data to it.

Take a look at this example: https://codepen.io/ccasenove/pen/RwymNMB

  • Related