我可以基于到不同数据对象的数据联接来更新D3选择器中的DOM元素吗

Can I update DOM elements in a D3 selector based on a data join to a different data object?

本文关键字:数据 更新 D3 选择器 元素 DOM 我可以 对象      更新时间:2023-09-26

tl;dr

我可以使用以下数据创建元素吗:

[{"id": 1, ...}, {"id: 2, ...}, ..]

并使用看起来像的数据更新元素的属性

[2, 4, 7]

(其中数组的元素是初始数据集的id的子集(。

长版本

我有这样的数据:

[
{
    "id": 1, 
    "latitude": 38.314552, 
    "longitude": -88.9025347755102, 
    "name": "JEFFERSON COUNTY JAIL ", 
    "official_name": "Jefferson County Justice Center", 
    "url": "https://www.ice.gov/detention-facilities/facilities/jeffeil.htm"
}, 
{
    "id": 2, 
    "latitude": 41.875702, 
    "longitude": -87.63072, 
    "name": "CHICAGO HOLD ROOM ", 
    "official_name": "Chicago Hold Room", 
    "url": ""
}, 
{
    "id": 3, 
    "latitude": 43.407029, 
    "longitude": -88.704349, 
    "name": "DODGE COUNTY JAIL, JUNEAU ", 
    "official_name": "Dodge Detention Facility", 
    "url": "https://www.ice.gov/detention-facilities/facilities/dodgewi.htm"
}, 
...
]

我把它放在一个类似这样的SVG地图上:

var projection = d3.geo.albersUsa()
    .scale(scale)
    .translate([width / 2, height / 2]);
var facilityCircles = svg.append("svg:g")
    .attr("id", "facilities");
d3.json("data/facilities.json", function(facilities) {
  var positions = [];
  var positionsByFacilityId = {};
  var pointSize = 5;
  facilities.forEach(function(facility) {
    var loc = [facility.longitude, facility.latitude];
    var pos = projection(loc);
    positions.push(pos);
    positionsByFacilityId[facility.id] = pos; 
  });
  facilityCircles.selectAll("circle")
                 .data(facilities, function(d) { return d.id; })
                 .enter().append("svg:circle")
                 .attr("data-facility-id", function(d, i) { return d.id; })
                 .attr("cx", function(d, i) { return positionsByFacilityId[d.id][0]; })
                 .attr("cy", function(d, i) { return positionsByFacilityId[d.id][1]; })
                 .attr("r", function(d, i) { return pointSize; });
 }

然而,稍后,我想基于另一个数据对象更新圆的属性,该数据对象只是表示初始数据中id属性子集的id数组,例如[2, 4, 5]

我可以这样做吗?只更新映射到具有给定id的数据对象的选定元素的属性?

      facilitiesSubset = [2, 4, 5];
      facilityCircles.selectAll("circle")
                 .data(facilitiesSubset)
                 .attr("fill", "green");

或者,我应该只从初始数据中提取id,并在对用于创建元素的data()的调用中使用这些id吗?

为了更容易一点,我建议稍微更改一下命名约定:

var facilityCircleContainer = svg.append("svg:g")
    .attr("id", "facilities");

由于svg:g对象实际上不是圆,所以它只是包含圆。那么:

  var facilityCircles = facilityCircleContainer.selectAll("circle")
                 .data(facilities, function(d) { return d.id; })
                 .enter().append("svg:circle")
                 .attr("data-facility-id", function(d, i) { return d.id; })
                 .ect(...)

facilityCircles现在指的是带有附加数据的圆。基于数组更新填充非常简单:

facilityCircles.attr("fill", function(d){
   facilitiesSubset.indexOf(d.id) != -1 ? "green" : "red"});