追加时访问父数据

时间:2018-08-16 09:53:44

标签: javascript d3.js svg

我基本上有一些嵌套数据,例如:

const shapeGroups = [
      {
        title: 'shapeGroup_01',
        color: 'blue',
        shapes: [
          {
            shape:'rect',
            width: 30,
            height: 100,
            x: 250,
            y: 450
          }
        ]
      },
      {
        title: 'shapeGroup_01',
        color: 'blue',
        shapes: [
          {
            shape:'rect',
            width: 10,
            height: 40,
            x: 350,
            y:50
          }
        ]
      }
    ]

我感兴趣的是按照shapeGroup的rect属性中的定义在每个color中设置颜色。

const shapeGroups = [{
    title: 'shapeGroup_01',
    color: 'blue',
    shapes: [{
      shape: 'rect',
      width: 30,
      height: 100,
      x: 250,
      y: 450
    }]
  },
  {
    title: 'shapeGroup_01',
    color: 'blue',
    shapes: [{
      shape: 'rect',
      width: 10,
      height: 40,
      x: 350,
      y: 50
    }]
  }
]

const stage = d3.select('#stageContainer')
  .append('svg')
  .attr('id', '#stage')
  .attr('width', 1000)
  .attr('height', 1000)


const groups = stage
  .selectAll('.group')
  .data(shapeGroups)

const groupEnter = groups
  .enter()
  .append('g')
  .attr('class', 'group');

const getGroup = group => group.shapes;
const createShape = shape => document.createElementNS(d3.namespaces.svg, shape.shape)

groupEnter
  .selectAll('.shape')
  .data(getGroup)
  .enter()
  .append(createShape)
  .attr('fill', 'red') // I want the color as defined in the current group
  .attr('width', d => d.width)
  .attr('height', d => d.height)
  .attr('x', d => d.x)
  .attr('y', d => d.y)
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="stageContainer"></div>

换句话说,我需要一种在组级别设置color的方法,或者在我附加单个datum时以某种方式访问​​父.shape对象的方法。

1 个答案:

答案 0 :(得分:3)

正如您在我的answer here中所读到的那样,您无法从D3 v4 / v5中的所选内容中访问父级的基准或其索引。

一种解决方案是获取parentNode的数据:

.attr('fill', (_, i, n) => d3.select(n[i].parentNode).datum().color)

这是您所做的更改(我将两个具有不同颜色的矩形和SVG缩小,以便更好地可视化):

const shapeGroups = [{
    title: 'shapeGroup_01',
    color: 'blue',
    shapes: [{
      shape: 'rect',
      width: 30,
      height: 100,
      x: 250,
      y: 50
    }]
  },
  {
    title: 'shapeGroup_01',
    color: 'green',
    shapes: [{
      shape: 'rect',
      width: 10,
      height: 40,
      x: 350,
      y: 20
    }]
  }
];

const stage = d3.select('body')
  .append('svg')
  .attr('width', 400)
  .attr('height', 400)


const groups = stage
  .selectAll('.group')
  .data(shapeGroups)

const groupEnter = groups
  .enter()
  .append('g')
  .attr('class', 'group');

const getGroup = group => group.shapes;
const createShape = shape => document.createElementNS(d3.namespaces.svg, shape.shape)

groupEnter
  .selectAll('.shape')
  .data(getGroup)
  .enter()
  .append(createShape)
  .attr('fill', (_, i, n) => d3.select(n[i].parentNode).datum().color)
  .attr('width', d => d.width)
  .attr('height', d => d.height)
  .attr('x', d => d.x)
  .attr('y', d => d.y)
<script src="https://d3js.org/d3.v5.min.js"></script>

但是,到目前为止,最简单的解决方案是将fill设置为父选项本身:

const groupEnter = groups
    .enter()
    .append('g')
    .attr('class', 'group')
    .attr('fill', d => d.color);

这是演示:

const shapeGroups = [{
    title: 'shapeGroup_01',
    color: 'blue',
    shapes: [{
      shape: 'rect',
      width: 30,
      height: 100,
      x: 250,
      y: 50
    }]
  },
  {
    title: 'shapeGroup_01',
    color: 'green',
    shapes: [{
      shape: 'rect',
      width: 10,
      height: 40,
      x: 350,
      y: 20
    }]
  }
];

const stage = d3.select('body')
  .append('svg')
  .attr('width', 400)
  .attr('height', 400)


const groups = stage
  .selectAll('.group')
  .data(shapeGroups)

const groupEnter = groups
  .enter()
  .append('g')
  .attr('class', 'group')
  .attr('fill', d=>d.color);

const getGroup = group => group.shapes;
const createShape = shape => document.createElementNS(d3.namespaces.svg, shape.shape)

groupEnter
  .selectAll('.shape')
  .data(getGroup)
  .enter()
  .append(createShape)
  .attr('width', d => d.width)
  .attr('height', d => d.height)
  .attr('x', d => d.x)
  .attr('y', d => d.y)
<script src="https://d3js.org/d3.v5.min.js"></script>