Javascript 无法在D3强制定向图中渲染图像

Javascript 无法在D3强制定向图中渲染图像,javascript,html,d3.js,svg,Javascript,Html,D3.js,Svg,我有一个共享边界的国家的武力导向图。我想在每个节点上显示该国国旗。我可以看到生成的HTML中的图像,也可以看到它占用了窗口中的空间,但它不可见 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta

我有一个共享边界的国家的武力导向图。我想在每个节点上显示该国国旗。我可以看到生成的HTML中的图像,也可以看到它占用了窗口中的空间,但它不可见

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="flags/flags.css">
  <link rel="stylesheet" href="index.css">
  <title>National Contiguity Visualization</title>
</head>
<body>
  <div class="details">National Contiguity</div>
  <svg class="plot"></svg>
  <div class="tooltip hidden"></div>
  <svg width="100" height="100">
      <foreignobject class="node" >

          <img class="flag flag-cz" alt="Czech Republic" src="flags/blank.png"/>                    
      </foreignobject>
  </svg>

  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="index.js"></script>
</body>
</html>
尝试了svg图像元素和foreignobject方法。直接用HTML编写的代码被正确呈现。在过去的3/4天内无法解决此问题

回购:

提前感谢。

  • 在foreignObject标记上需要宽度和高度属性
  • foreignObject用大写字母O拼写,尽管HTML标记不区分大小写,但元素的DOM创建,因此d3区分大小写
  • d3希望HTML标记以xhtml为前缀:
因为您没有提供标志,所以我使用了一个示例标志。请注意,此时所有节点都是一个接一个地放置的,但如果无法解决这个问题,我想这是另一个问题

const-apirl=”https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json';
常量工具提示=document.getElementsByClassName('tooltip')[0];
常数dragstarted=d=>{
如果(!d3.event.active)simulation.alphaTarget(0.3.restart();
d、 fx=d.x;
d、 fy=d.y;
}
常数=d=>{
d、 fx=d3.event.x;
d、 fy=d3.event.y;
}
常数d=d=>{
如果(!d3.event.active)simulation.alphaTarget(0);
d、 fx=null;
d、 fy=null;
}
常数图=(数据)=>{
data.nodes=data.nodes.map((d,索引)=>{
d['id']=索引;
返回d;
});
常量边距={
前20名,
右:20,,
底部:10,
左:100
};
常量宽度=数学最大值(((window.innerWidth/100)*80)-margin.right-margin.left),700);
常量高度=((window.innerHeight/100)*80)-margin.bottom-margin.top;
const svg=d3.select('svg')
.attr('width',width+margin.left+margin.right+100)
.attr('height',height+margin.top+margin.bottom+100)
.append('g')
.attr('transform',
`翻译(${margin.left},${margin.top})`);
常量模拟=d3.forceSimulation()
.force('link',d3.forceLink().id(函数(d){return d.id;}).distance(100).strength(1))
.force('charge',d3.forceManyBody())
.力(“中心”,d3.力中心(宽度/2,高度/2));
常数dragstarted=d=>{
如果(!d3.event.active)simulation.alphaTarget(0.3.restart();
d、 fx=d.x;
d、 fy=d.y;
}
常数=d=>{
d、 fx=d3.event.x;
d、 fy=d3.event.y;
}
常数d=d=>{
如果(!d3.event.active)simulation.alphaTarget(0);
d、 fx=null;
d、 fy=null;
}
常量勾选=()=>{
链接
.attr(“x1”,d=>d.source.x)
.attr(“y1”,d=>d.source.y)
.attr(“x2”,d=>d.target.x)
.attr(“y2”,d=>d.target.y);
节点
.attr(“x”,函数(d){return d.x=Math.max(5,Math.min(width-5,d.x));}
.attr(“y”,函数(d){返回d.y=Math.max(5,Math.min(height-5,d.y));};
}
const link=svg.append('g')
.attr('class','links'))
.selectAll('行')
.数据(数据链接)
.enter().append('行')
.attr('stroke-width',函数(d){return Math.sqrt(d.value);});
const node=svg.append('g')
.attr('类','节点')
.selectAll(“.flag”)
.data(data.nodes)
.输入()
.append('foreignObject')
.attr('width','100')
.attr('height','100')
.append('xhtml:img')
.attr('src','https://flaglane.com/download/british-flag/british-flag-small.gif')
.attr('class',d=>`flag-flag-cz`)
.call(d3.drag()
.on('start',dragstarted)
.on('拖动',拖动)
.在('结束',拖行));
node.append(“标题”)
.text(函数(d){返回d.country;})
.exit();
模拟
.nodes(数据.nodes)
。在(勾选)上;
模拟力(“链接”)
.链接(数据链接);
}
常量fetchData=()=>{
返回获取(APIRL)
。然后(响应=>{
返回response.json();
});
};
const fetchAndPlot=async()=>{
试一试{
const response=等待获取数据();
情节(反应);
}捕获(e){
控制台错误(e);
}
}
fetchAndPlot()

民族邻接可视化
民族毗连

1。不要使用
foreingObject
。2.如果仍要使用它,请设置宽度和高度:
.attr(“宽度”,无论什么)。attr(“高度”,无论什么)
。尝试将宽度和高度属性添加到foreignObject标记,或者只使用SVG标记。foreignObject的宽度和高度?但我不确定这将如何解决渲染问题。我尝试了svg图像元素,但同样的事情也发生在那。。。图像未被渲染。@DhanushuUzumaki假设您要渲染一个矩形。不设置宽度和高度可以吗?它们是SVG1.1中的强制属性。SVG1.1规范说,如果省略它们,则不渲染任何内容。SVG 2改变了这一点,但我认为只有Chrome实现了这一点。我认为,
foreignObject
区分大小写的问题不是因为D3,因为D3是不区分渲染的。如果我错了,请纠正我,但是
foreignObject
应该有大写字母O,因为它是一个SVG元素,XML(与HTML不同)区分大小写。SVG作为标记嵌入HTML时不区分大小写。当您通过DOM创建它时,它是区分大小写的,无论是XML还是HTML,所以我认为它实际上是DOM而不是d3。我已经解释得更详细了。如果您查看D3
append()
方法的源代码,您将看到它使用了
document.createElements
。。。所以,这就解释了为什么它是区分大小写的。谢谢,@Robert和Gerardo现在图像被正确渲染了。如果我可以再请求一个帮助,x和y坐标将应用于最后附加的元素(本例中为img)。。有没有办法将其应用于foreignObject?@DhanushuUzumaki这很容易修复。但是,不要在评论中提出新问题:相反,发布新的问题
const apiUrl = 'https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json';
const tooltip = document.getElementsByClassName('tooltip')[0];

const dragstarted = d => {
  if (!d3.event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

const dragged = d => {
  d.fx = d3.event.x;
  d.fy = d3.event.y;
}

const dragended = d => {
  if (!d3.event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}

const plot = (data) => {
  data.nodes = data.nodes.map((d, index) => {
    d['id'] = index;
    return d;
  });
  const margin = {
    top: 20,
    right: 20,
    bottom: 10,
    left: 100
  };
  const width = Math.max((((window.innerWidth / 100) * 80) - margin.right - margin.left), 700);
  const height = ((window.innerHeight / 100) * 80) - margin.bottom - margin.top;
  const svg = d3.select('svg')
    .attr('width', width + margin.left + margin.right + 100)
    .attr('height', height + margin.top + margin.bottom + 100)
    .append('g')
    .attr('transform',
      `translate(${margin.left}, ${margin.top})`);

  const simulation = d3.forceSimulation()
    .force('link', d3.forceLink().id(function (d) { return d.id; }).distance(100).strength(1))
    .force('charge', d3.forceManyBody())
    .force('center', d3.forceCenter(width / 2, height / 2));

  const dragstarted = d => {
    if (!d3.event.active) simulation.alphaTarget(0.3).restart();
    d.fx = d.x;
    d.fy = d.y;
  }

  const dragged = d => {
    d.fx = d3.event.x;
    d.fy = d3.event.y;
  }

  const dragended = d => {
    if (!d3.event.active) simulation.alphaTarget(0);
    d.fx = null;
    d.fy = null;
  }

  const ticked = () => {
    link
      .attr("x1", d => d.source.x)
      .attr("y1", d => d.source.y)
      .attr("x2", d => d.target.x)
      .attr("y2", d => d.target.y);

    node
      .attr("x", function (d) { return d.x = Math.max(5, Math.min(width - 5, d.x)); })
      .attr("y", function (d) { return d.y = Math.max(5, Math.min(height - 5, d.y)); });
  }

  const link = svg.append('g')
    .attr('class', 'links')
    .selectAll('line')
    .data(data.links)
    .enter().append('line')
    .attr('stroke-width', function (d) { return Math.sqrt(d.value); });

  const node = svg.append('g')
    .attr('class', 'nodes')
    .selectAll('.flag')
    .data(data.nodes)
    .enter()
    .append('foreignobject')
    .append('img')
    .attr('src', 'flags/blank.png')
    .attr('class', d => `flag flag-cz`)
    .attr('width', '5px')
    .attr('height', '5px')
    .attr("x", -8)
    .attr("y", -8)
    .call(d3.drag()
      .on('start', dragstarted)
      .on('drag', dragged)
      .on('end', dragended));

  node.append("title")
    .text(function (d) { return d.country; })
    .exit();

  simulation
    .nodes(data.nodes)
    .on("tick", ticked);

  simulation.force("link")
    .links(data.links);

}

const fetchData = () => {
  return fetch(apiUrl)
    .then(response => {
      return response.json();
    });
};

const fetchAndPlot = async () => {
  try {
    const response = await fetchData();
    console.log(response);
    plot(response);
  } catch (e) {
    console.error(e);
  }
}

fetchAndPlot();