D3 将 XML 多边形 ID 映射到 JSON 数据

D3 Map XML Polygon ids to JSON data

我有一个 svg/xml file 正在使用 d3.xml(...)

加载到 d3

这是 SVG

output

我也有一个小的JSON数据集

const data = [{
    "id": "polygon5256", //roof
    "value": 39.5
  },
  {
    "id": "polygon1628",  //grass
    "value": 3.93
  },
  {
    "id": "polygon5254", //left wall
    "value": 3.14
  },
  {
    "id": "path5894", //door step
    "value": 20.98
  }
]

我正在尝试将 JSON 数据集中的 ID 连接到 XML 数据中的相应 ID(多边形和路径)。您知道我如何将可选择的 paths/polygons 限制为仅 JSON 数据中的那些吗?所以只有可用的ID会受到鼠标事件的影响?

这是我的jsfiddle

如有任何帮助,我们将不胜感激

在您的 fiddle 中您有 d3.select('#polygon5256') 但您可以使用 selectAll 和不同的 CSS 选择器将事件添加到任何多边形:

d3.selectAll("svg polygon")

您也想要 path(用于门阶),因此您需要的 CSS 选择器是:

d3.selectAll("svg polygon, svg path")

在处理程序中,您可以获得多边形的 id(因为您使用的是 d3 v5.9.2):

d3.event.target.id

请注意,如果您使用的是更高版本的 D3 库,则此处理将需要更改(请参阅 D3 v6 changes

我已将您的 fiddle 更改为具有单个可见 div,其中鼠标悬停和鼠标移出处理程序仅填充标签(如果在 data 中可用)或清除文本。

工作示例:

const data = [
  { "id": "polygon5256", "value": 39.5 }, // roof
  { "id": "polygon1628", "value": 3.93 }, // grass
  { "id": "polygon5254", "value": 3.14 }, // left wall
  { "id": "path5894", "value": 20.98 } // door step
];


// just make one visible div and leave text till later
const tooltip = d3.select("body")
  .append("div")
  .style("position", "absolute")
  .style("z-index", "10")
  .style("visibility", "visible");

const svgUrl = "https://raw.githubusercontent.com/gangrel11/samplefiles/main/house.svg";
d3.xml(svgUrl).then(render);

// on render set an event for any polygon of the svg
function render(data) {

  d3.select("body").node().append(data.documentElement)
  d3.selectAll("svg polygon, svg path")
    .on("mouseover", mouseover)
    .on("mouseout", mouseout);
    
}

// set the text of the div if it's in the data set
function mouseover(d) {
  const id = d3.event.target.id;
  const obj = data.find(item => item.id === id);
  const text = obj ? `${id} - ${obj.value}` : "";
  tooltip.text(text);
  d3.select(`#${id}`).style("opacity", 0.5);
}

// clear the text of the div
function mouseout(d) {
  const id = d3.event.target.id;
  tooltip.text("");
  d3.select(`#${id}`).style("opacity", 1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

编辑

如果你想将 paths/polygons 限制为仅 JSON 数据中的那些,你可以换掉这个:

function render(data) {

  d3.select("body").node().append(data.documentElement)
  d3.selectAll("svg polygon, svg path")
    .on("mouseover", mouseover)
    .on("mouseout", mouseout);
    
}

为此(注意 render 的函数签名必须更改,因为我们在函数中引用 data 数组):

function render(svg) {

  // add svg
  d3.select("body").node().append(svg.documentElement)
  
  // add events for ids  
  const ids = data.map(d => d.id);
  ids.forEach(id => d3.select(`#${id}`)
    .on("mouseover", mouseover)
    .on("mouseout", mouseout)
  );
  
}

工作示例:

const data = [
  { "id": "polygon5256", "value": 39.5 }, // roof
  { "id": "polygon1628", "value": 3.93 }, // grass
  { "id": "polygon5254", "value": 3.14 }, // left wall
  { "id": "path5894", "value": 20.98 } // door step
];

// just make one visible div and leave text till later
const tooltip = d3.select("body")
  .append("div")
  .style("position", "absolute")
  .style("z-index", "10")
  .style("visibility", "visible");

// load external svg and render
const svgUrl = "https://raw.githubusercontent.com/gangrel11/samplefiles/main/house.svg";
d3.xml(svgUrl).then(render);

// on render set an event for anything with an id within data
function render(svg) {

  // add svg
  d3.select("body").node().append(svg.documentElement)
  
  // add events for ids  
  const ids = data.map(d => d.id);
  ids.forEach(id => d3.select(`#${id}`)
    .on("mouseover", mouseover)
    .on("mouseout", mouseout)
  );
  
}

// set the text of the div if it's in the data set
function mouseover(d) {
  const id = d3.event.target.id;
  const obj = data.find(item => item.id === id);
  const text = obj ? `${id} - ${obj.value}` : "";
  tooltip.text(text);
  d3.select(`#${id}`).style("opacity", 0.5);
}

// clear the text of the div
function mouseout(d) {
  const id = d3.event.target.id;
  tooltip.text("");
  d3.select(`#${id}`).style("opacity", 1);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>