Home > Software engineering >  D3 Map XML Polygon ids to JSON data
D3 Map XML Polygon ids to JSON data

Time:04-18

I have an svg/xml file that I'm loading into d3 using d3.xml(...)

This is the output of the SVG

I also have a small JSON dataset

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
  }
]

I'm trying to join the id's from the JSON dataset to the respective id's (polygons and paths) in the XML data.

Here is my jsfiddle

Any help would be much appreciated

CodePudding user response:

In your fiddle you have d3.select('#polygon5256') but you can add events to any polygon with selectAll and a different CSS selector:

d3.selectAll("svg polygon")

You want path too (for the door step) so the CSS selector you need is:

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

In the handler you can get the id of the polygon with (since you use d3 v5.9.2):

d3.event.target.id

Note that if you're using a later version of the D3 library this handling will need to change (see D3 v6 changes)

I've changed your fiddle to have a single visible div where the mouseover and mouseout handlers just populate labelling if available in data or clear the text.

Working example:

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>

  • Related