链接中的标签未显示

时间:2017-11-10 21:38:45

标签: javascript d3.js svg

我一直在尝试为Force Directed Graph中的链接添加标签。我的代码基于this answer。最终结果应如下所示:

enter image description here

我设法为文字制作图表。它在我查看页面源时出现。但由于某些原因,它不会在视觉上显示出来。它只是隐藏在SVG的某个地方。

这是我的小提琴:https://jsfiddle.net/1dm5bm7b/

以下是代码的相关部分:

var labelElements = g.append("g")
   .attr("class", "label")
   .selectAll("text")
   .data(links)
   .enter().append("text")
   .attr("font-size", 12)
   .attr("font-family", "sans-serif")
   .attr("fill", "#333")
   .attr("x", "50")
     .attr("y", "-20")
   .attr("text-anchor", "start")
   .append("textPath")
   .attr("xlink:href",function(d,i) { return "#linkId_" + i; })
   .text(function(link) {
       return link.value;
   })

simulation.nodes(nodes).on('tick', () => {
nodeElements
 .attr('cx', function(node) {
   return node.x
 })
 .attr('cy', function(node) {
   return node.y
 })
textElements
 .attr('x', function(node) {
   return node.x
 })
 .attr('y', function(node) {
   return node.y
 })
linkElements
 .attr('x1', function(link) {
   return link.source.x
 })
 .attr('y1', function(link) {
   return link.source.y
 })
 .attr('x2', function(link) {
   return link.target.x
 })
 .attr('y2', function(link) {
   return link.target.y
 })
labelElements
 .attr('x', function(link) {
   return link.target.x
 })
 .attr('y', function(link) {
   return link.target.y
 })
 })

1 个答案:

答案 0 :(得分:2)

正如comments中所述,您要追加<line>个元素,而不是<path>元素。

解决方案很简单:添加<path>元素而不是行,并更改tick函数:

linkElements.attr("d", function(link) {
    return "M" + link.source.x + "," + link.source.y 
    + " L" + link.target.x + "," + link.target.y;
});

以下是您更改的代码:

&#13;
&#13;
function getNeighbors(node) {
  return links.reduce(function(neighbors, link) {
    if (link.target.id === node.id) {
      neighbors.push(link.source.id)
    } else if (link.source.id === node.id) {
      neighbors.push(link.target.id)
    }
    return neighbors
  }, [node.id])
}

function isNeighborLink(node, link) {
  return link.target.id === node.id || link.source.id === node.id
}


function getNodeColor(node, neighbors) {
  // If is neighbor
  if (Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1) {
    return 'rgba(251, 130, 30, 1)'
      // return node.level === 1 ? '#9C4A9C' : 'rgba(251, 130, 30, 1)'
  } else {
    // Check the node level
    if (node.level === 0) {
      return '#E72148'
    } else if (node.level === 1) {
      return '#9C4A9C'
    } else {
      return '#D8ABD8'
    }
  }
  //return node.level === 0 ? '#91007B' : '#D8ABD8'
}

function getLinkColor(node, link) {
  return isNeighborLink(node, link) ? 'rgba(251, 130, 30, 1)' : 'rgba(251, 130, 30, 0.25)'
}

function getTextColor(node, neighbors) {
  return Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1 ? '#333' : '#bbb'
}

var width = window.innerWidth
var height = window.innerHeight

var svg = d3.select('svg')
  // svg.attr('width', width).attr('height', height)
svg.attr("width", '100%')
  .attr("height", '500px')
  .attr('viewBox', '250 0 800 600')
  //.attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height))
  .attr('preserveAspectRatio', 'xMidYMid')
  .append("g")
  .attr("transform", "translate(" + Math.min(width, height) / 2 + "," + Math.min(width, height) / 2 + ")");

//add zoom capabilities
var zoom_handler = d3.zoom()
  .scaleExtent([1 / 2, 8])
  .on("zoom", zoom_actions);

zoom_handler(svg);

function zoom_actions() {
  g.attr("transform", d3.event.transform)
}

function button_zoom_in() {
  zoom_handler.scaleBy(svg, 2);
}

function button_zoom_out() {
  zoom_handler.scaleBy(svg, 0.5);
}

// simulation setup with all forces
var linkForce = d3
  .forceLink()
  .id(function(link) {
    return link.id 
  })
  // Alternative: using the distance from the data "strength"
  //.distance(50).strength(function (link) { return link.strength })
  // If don't want to use this, use default here:
  .distance(50).strength(.7)

var simulation = d3
  .forceSimulation()
  .force('link', linkForce)
  .force('charge', d3.forceManyBody().strength(-1500))
  .force('radial', d3.forceRadial(function(d) {
    return d.level * 50
  }, width / 2, height / 2))
  .force('center', d3.forceCenter(width / 2, height / 2))

var dragDrop = d3.drag().on('start', function(node) {
  node.fx = node.x
  node.fy = node.y
}).on('drag', function(node) {
  simulation.alphaTarget(0.7).restart()
  node.fx = d3.event.x
  node.fy = d3.event.y
}).on('end', function(node) {
  if (!d3.event.active) {
    simulation.alphaTarget(0)
  }
  node.fx = null
  node.fy = null
})

function selectNode(selectedNode) {
  var neighbors = getNeighbors(selectedNode)

  // we modify the styles to highlight selected nodes
  nodeElements.attr('fill', function(node) {
    return getNodeColor(node, neighbors)
  })
  textElements.attr('fill', function(node) {
    return getTextColor(node, neighbors)
  })
  linkElements.attr('stroke', function(link) {
    return getLinkColor(selectedNode, link)
  })
}



// Enables zooming
var g = svg.append("g")
  .attr("class", "everything");
// Enables zooming end

// Create circling orbit
var circles = g.selectAll(null) // use g.selectAll instead of svg.selectAll to enable zoom
  .data([200, 350]) // sets the circle radius
  .enter()
  .append("circle")
  .attr("cx", width / 2)
  .attr("cy", height / 2)
  .attr("r", d => d)
  .style("fill", "none")
  .style("stroke", "#ddd");

var linkElements = g.append("g") // use g.append instead of svg.append to enable zoom
  .attr("class", "links")
  .selectAll("line")
  .data(links)
  .enter().append("path")
  .attr("id", function(d, i) {
    return "linkId_" + i;
  })
  .attr("stroke-width", function(link) {
    var linkWidthNormalize = link.value / 1000000000; // in milyar
    // under assumption that smallest 10 milyar, largest > 40 triliun
    if (linkWidthNormalize >= 40001) {
      return 12;
    } else if (linkWidthNormalize >= 20001 && linkWidthNormalize <= 40000) {
      return 10;
    } else if (linkWidthNormalize >= 9001 && linkWidthNormalize <= 20000) {
      return 8;
    } else if (linkWidthNormalize >= 4001 && linkWidthNormalize <= 9000) {
      return 6;
    } else if (linkWidthNormalize >= 10 && linkWidthNormalize <= 4000) {
      return 4;
    } else {
      return 2;
    }
    // return linkWidthNormalize;
  })
  .attr("stroke", "rgba(251, 130, 30, 0.5)")

var labelElements = g.append("g")
  .attr("class", "label")
  .selectAll("text")
  .data(links)
  .enter().append("text")
  .attr("font-size", 12)
  .attr("font-family", "sans-serif")
  .attr("fill", "#333")
  .attr("x", "50")
  .attr("y", "-20")
  .attr("text-anchor", "start")
  .append("textPath")
  .attr("xlink:href", function(d, i) {
    return "#linkId_" + i;
  })
  .text(function(link) {
    return link.value;
  })

var nodeElements = g.append("g") // use g.append instead of svg.append to enable zoom
  .attr("class", "nodes")
  .selectAll("circle")
  .data(nodes)
  .enter().append("circle")
  .attr("r", 12)
  .attr("fill", getNodeColor)
  .attr("stroke", "#fff")
  .attr('stroke-width', 2)
  .call(dragDrop)
  //.on('click', selectNode)      // alternative
  .on('mouseover', selectNode)

var textElements = g.append("g") // use g.append instead of svg.append to enable zoom
  .attr("class", "texts")
  .selectAll("text")
  .data(nodes)
  .enter().append("text")
  .text(function(node) {
    return node.label
  })
  .attr("font-size", 10)
  .attr("font-family", "sans-serif")
  .attr("text-anchor", "middle")
  .attr("fill", "#333")
  .attr("style", "font-weight:bold; -webkit-text-stroke: 1px #fff; text-shadow: 3px 3px 0 #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff")
  .attr("dx", 0)
  .attr("dy", 20)



simulation.nodes(nodes).on('tick', () => {
  nodeElements
    .attr('cx', function(node) {
      return node.x
    })
    .attr('cy', function(node) {
      return node.y
    })
  textElements
    .attr('x', function(node) {
      return node.x
    })
    .attr('y', function(node) {
      return node.y
    })
  linkElements.attr("d", function(link) {
    return "M" + link.source.x + "," + link.source.y + " L" + link.target.x + "," + link.target.y;
  });
  labelElements
    .attr('x', function(link) {
      return link.target.x
    })
    .attr('y', function(link) {
      return link.target.y
    })
})

simulation.force("link").links(links)
&#13;
<div class="buttons" id="sunburst-buttons">
  <button class="btn btn-default" onclick="button_zoom_in()">+</button>
  <button class="btn btn-default" onclick="button_zoom_out()">-</button>
</div>
<svg height="600" id="sunburst-area" width="960"></svg>


<script src="https://d3js.org/d3.v4.min.js"></script>

<!-- Dataset -->
<script>
  var nodes = [{
    id: "pusat",
    group: 0,
    label: "Pusat",
    level: 0
  }, {
    id: "dki",
    group: 1,
    label: "Prov. DKI",
    level: 1
  }, {
    id: "jaksel",
    group: 1,
    label: "Kota Jakarta Selatan",
    level: 2
  }, {
    id: "jakpus",
    group: 1,
    label: "Kota Jakarta Pusat",
    level: 2
  }, {
    id: "jabar",
    group: 2,
    label: "Prov. Jawa Barat",
    level: 1
  }, {
    id: "sumedang",
    group: 2,
    label: "Kab. Sumedang",
    level: 2
  }, {
    id: "bekasi",
    group: 2,
    label: "Kota Bekasi",
    level: 2
  }, {
    id: "bandung",
    group: 2,
    label: "Kota Bandung",
    level: 2
  }, {
    id: "jatim",
    group: 3,
    label: "Prov. Jawa Timur",
    level: 1
  }, {
    id: "malang",
    group: 3,
    label: "Kota Malang",
    level: 2
  }, {
    id: "lamongan",
    group: 3,
    label: "Kota Lamongan",
    level: 2
  }, {
    id: "diy",
    group: 4,
    label: "Prov. DIY",
    level: 1
  }, {
    id: "sleman",
    group: 4,
    label: "Kab. Sleman",
    level: 2
  }, {
    id: "jogja",
    group: 4,
    label: "Kota Yogyakarta",
    level: 2
  }, {
    id: "bali",
    group: 5,
    label: "Prov. Bali",
    level: 1
  }, {
    id: "bali1",
    group: 5,
    label: "Kota Denpasar",
    level: 2
  }, {
    id: "bali2",
    group: 5,
    label: "Kab. Buleleng",
    level: 2
  }, {
    id: "ntt",
    group: 6,
    label: "Prov. NTT",
    level: 1
  }, {
    id: "ntt1",
    group: 6,
    label: "Kab. Alor",
    level: 2
  }, {
    id: "ntt2",
    group: 6,
    label: "Kab. Manggarai Timur",
    level: 2
  }, {
    id: "ntb",
    group: 7,
    label: "Prov. NTB",
    level: 1
  }, {
    id: "kabima",
    group: 7,
    label: "Kab. Bima",
    level: 2
  }, {
    id: "kobima",
    group: 7,
    label: "Kota Bima",
    level: 2
  }, {
    id: "kaltara",
    group: 8,
    label: "Prov. Kaltara",
    level: 1
  }, {
    id: "kubar",
    group: 8,
    label: "Kab. Kutai Barat",
    level: 2
  }, {
    id: "kutim",
    group: 8,
    label: "Kab. Kutai Timur",
    level: 2
  }, {
    id: "kaltim",
    group: 9,
    label: "Prov. Kaltim",
    level: 1
  }, {
    id: "bpp",
    group: 9,
    label: "Kota Balikpapan",
    level: 2
  }, {
    id: "samarinda",
    group: 9,
    label: "Kota Samarinda",
    level: 2
  }, {
    id: "kalsel",
    group: 10,
    label: "Prov. Kalsel",
    level: 1
  }, {
    id: "banjar",
    group: 10,
    label: "Kota Banjarmasin",
    level: 2
  }, {
    id: "tapin",
    group: 10,
    label: "Kab. Tapin",
    level: 2
  }, {
    id: "kalbar",
    group: 11,
    label: "Prov. Kalbar",
    level: 1
  }, {
    id: "melawi",
    group: 11,
    label: "Kab. Melawi",
    level: 2
  }, {
    id: "sambas",
    group: 11,
    label: "Kab. Sambas",
    level: 2
  }]
  var links = [
    // Pusat-Provinsi
    {
      source: "pusat",
      target: "dki",
      strength: .5,
      value: 100000000000
    }, {
      source: "pusat",
      target: "jabar",
      strength: .5,
      value: 30000000000
    }, {
      source: "pusat",
      target: "jatim",
      strength: .5,
      value: 100000000000
    }, {
      source: "pusat",
      target: "diy",
      strength: .5,
      value: 1000000000000
    }, {
      source: "pusat",
      target: "bali",
      strength: .5,
      value: 10000000000
    }, {
      source: "pusat",
      target: "ntt",
      strength: .5,
      value: 1000000000
    }, {
      source: "pusat",
      target: "ntb",
      strength: .5,
      value: 1000000000
    }, {
      source: "pusat",
      target: "kaltim",
      strength: .5,
      value: 5000000000000
    }, {
      source: "pusat",
      target: "kaltara",
      strength: .5,
      value: 5000000000000
    }, {
      source: "pusat",
      target: "kalsel",
      strength: .5,
      value: 10000000000000
    }, {
      source: "pusat",
      target: "kalbar",
      strength: .5,
      value: 1000000000
    },
    // Provinsi-Kab/Kota
    {
      source: "dki",
      target: "jaksel",
      strength: .7,
      value: 2000000000
    }, {
      source: "dki",
      target: "jakpus",
      strength: .7,
      value: 4000000000000
    }, {
      source: "jabar",
      target: "sumedang",
      strength: .7,
      value: 400000000000
    }, {
      source: "jabar",
      target: "bekasi",
      strength: .7,
      value: 40000000000
    }, {
      source: "jabar",
      target: "bandung",
      strength: .7,
      value: 40000000000
    }, {
      source: "jatim",
      target: "malang",
      strength: .7,
      value: 300000000000
    }, {
      source: "jatim",
      target: "lamongan",
      strength: .7,
      value: 100000000000
    }, {
      source: "diy",
      target: "sleman",
      strength: .7,
      value: 4500000000000
    }, {
      source: "diy",
      target: "jogja",
      strength: .7,
      value: 6700000000000
    }, {
      source: "bali",
      target: "bali1",
      strength: .7,
      value: 100000000000000
    }, {
      source: "bali",
      target: "bali2",
      strength: .7,
      value: 2400000000000
    }, {
      source: "ntt",
      target: "ntt1",
      strength: .7,
      value: 60000000000000
    }, {
      source: "ntt",
      target: "ntt2",
      strength: .7,
      value: 100000000000
    }, {
      source: "ntb",
      target: "kabima",
      strength: .7,
      value: 126000000000
    }, {
      source: "ntb",
      target: "kobima",
      strength: .7,
      value: 1000000000000
    }, {
      source: "kaltara",
      target: "kubar",
      strength: .7,
      value: 12420000000000
    }, {
      source: "kaltara",
      target: "kutim",
      strength: .7,
      value: 14400000000000
    }, {
      source: "kaltim",
      target: "bpp",
      strength: .7,
      value: 1470000000000
    }, {
      source: "kaltim",
      target: "samarinda",
      strength: .7,
      value: 1000000000000000
    }, {
      source: "kalsel",
      target: "banjar",
      strength: .7,
      value: 137000000000
    }, {
      source: "kalsel",
      target: "tapin",
      strength: .7,
      value: 5050000000000
    }, {
      source: "kalbar",
      target: "melawi",
      strength: .7,
      value: 2400000000000
    }, {
      source: "kalbar",
      target: "sambas",
      strength: .7,
      value: 5500000000000
    }
  ];

</script>
&#13;
&#13;
&#13;