d3.each() 一次存储一个值,而不是一次存储所有值



我正在尝试将一些矩形的x和y坐标存储到数组中。有 20 个矩形,我将值存储在 20 个数组的数组中。数组中的每个项目如下所示:

[
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0}
  ];

我在矩形追加中添加了一个.each(),如下所示:

.each(function(d,i) {
    return polyMaster[i][0].y = d3.select(this).attr('y');
 })

此时,我注意到所有y值都相同。我通过尝试确认了这一点:

.each(function(d,i) {
    return polyMaster[i][0].y = i;
})

返回19 - 最后一个索引。因此,似乎我以前的所有索引y都被新的索引覆盖了。

var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
    .append('svg')
    .attr('width', totalWidth)
    .attr('height', totalHeight);
var graphGroup = svg.append('g')
    .attr('transform', "translate("+margins.left+","+margins.top+ ")");
var heightScale = d3.scaleLinear()
    .domain([.01,.09])
    .range([7,50]);
var data = [{'manager': 'Mirae Asset', 'share': 0.016},
  {'manager': 'Manulife', 'share': 0.015},
  {'manager': 'ChinaAMC', 'share': 0.012},
  {'manager': 'Principal', 'share': 0.015},
  {'manager': 'Aberdeen Standard', 'share': 0.013},
  {'manager': 'CSOP', 'share': 0.015},
  {'manager': 'BOCI-Prudential', 'share': 0.019},
  {'manager': 'Allianz', 'share': 0.016},
  {'manager': 'HSBC', 'share': 0.027},
  {'manager': 'Deutsche Bank', 'share': 0.014},
  {'manager': 'Invesco', 'share': 0.025},
  {'manager': 'First State', 'share': 0.033},
  {'manager': 'JP Morgan', 'share': 0.041},
  {'manager': 'Value Partners', 'share': 0.04},
  {'manager': 'Schroders', 'share': 0.051},
  {'manager': 'Hang Seng', 'share': 0.063},
  {'manager': 'UBS', 'share': 0.056},
  {'manager': 'SSgA', 'share': 0.066},
  {'manager': 'Fidelity', 'share': 0.088},
  {'manager': 'BlackRock', 'share': 0.084}];
  var poly = [
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0}
  ];
  var polyMaster = new Array(20).fill(poly);
  var colorMap = {
    'Fidelity':"#003366",
    'BlackRock':"#366092",
    'SSgA':"#4f81b9",
    'Hang Seng':"#95b3d7",
    'UBS':"#b8cce4",
    'Schroders':"#e7eef8",
    'JP Morgan':"#a6a6a6",
    'Value Partners':"#d9d9d9",
    'Yuanta':"#ffffcc",
    'First State':"#ffffcc",
    'HSBC':'#f6d18b',
    'Invesco':'#e4a733',
    'BOCI-Prudential':"#b29866",
    'Allianz':'#a6a6a6',
    'Mirae Asset':'#d9d9d9',
    'Manulife':'#e7eef8',
    'CSOP':'#b8cce4',
    'Principal':'#95b3d7',
    'Deutsche Bank':'#4f81b9',
    'Aberdeen Standard':'#366092',
    'ChinaAMC':'#003366'
  };
      var sortedData = data.sort(function(a,b) {
        return b.share - a.share;
      });
      let counterRect = 0,
        counterText = 0;
        var column = graphGroup.selectAll('.ranks')
            .data(sortedData)
            .attr('class', 'ranks')
          .enter().append("g");
        column.append("rect")
            .attr("width", 120)
            .attr("height", function(d) {
              return heightScale(d.share)
            })
            .attr('x', function(d) {return 0})
            .attr('y', function(d, i) {
              let previous = counterRect;
              return (counterRect += heightScale(d.share)+2, previous)
            })
            .each(function(d,i) {
              if (i>=0) {
                return polyMaster[i][0].x = 120;
              }
            })
            .each(function(d,i) {
              if (i>=0) {
                const index = i;
                polyMaster[index][0].y = d3.select(this).attr('y');
              }
            })
            .style('fill',function(d,i) {return colorMap[d.manager]});
            column.append("text")
              .attr('x', function(d) {return 60})
              .attr('y', function(d, i) {
                let previous = counterText;
                return (counterText += heightScale(d.share)+2, previous + (heightScale(d.share)/2))
              })
              .attr("dominant-baseline", "central")
              .attr('text-anchor', 'middle')
              .text(function(d) {
                return d.manager;
              });
              console.log(polyMaster)
<script src="https://d3js.org/d3.v5.min.js"></script>

问题

如何迭代存储 rect 的 y 属性,但一次仍然存储一个(以避免被覆盖(?

注意:我只是担心xy的第一个对象。其余三个将在稍后绘制,一旦我弄清楚如何执行上述操作。

您的问题与d3.each或其索引无关。你的问题就在这里:

var poly = [
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0}
];
var polyMaster = new Array(20).fill(poly);

所有数组中的所有对象都指向同一个对象(poly(。改变一个将改变它们。

快速解决方法是将JSON.parseJSON.stringify一起使用来复制对象:

var polyMaster = d3.range(20).map(()=>JSON.parse(JSON.stringify(poly)))

不过,有几种选择。另一个简单的方法是将数组直接传递到map内:

var polyMaster = d3.range(20).map(()=>[
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0}
])

另外,正如您所注意到的,我使用的是d3.range而不是new Array + fill

以下是更改的代码:

var margins = {top:20, bottom:300, left:30, right:100};
var height = 600;
var width = 900;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;
var outerRadius = (400 / 2);
var innerRadius = 15;
var svg = d3.select('body')
    .append('svg')
    .attr('width', totalWidth)
    .attr('height', totalHeight);
var graphGroup = svg.append('g')
    .attr('transform', "translate("+margins.left+","+margins.top+ ")");
var heightScale = d3.scaleLinear()
    .domain([.01,.09])
    .range([7,50]);
var data = [{'manager': 'Mirae Asset', 'share': 0.016},
  {'manager': 'Manulife', 'share': 0.015},
  {'manager': 'ChinaAMC', 'share': 0.012},
  {'manager': 'Principal', 'share': 0.015},
  {'manager': 'Aberdeen Standard', 'share': 0.013},
  {'manager': 'CSOP', 'share': 0.015},
  {'manager': 'BOCI-Prudential', 'share': 0.019},
  {'manager': 'Allianz', 'share': 0.016},
  {'manager': 'HSBC', 'share': 0.027},
  {'manager': 'Deutsche Bank', 'share': 0.014},
  {'manager': 'Invesco', 'share': 0.025},
  {'manager': 'First State', 'share': 0.033},
  {'manager': 'JP Morgan', 'share': 0.041},
  {'manager': 'Value Partners', 'share': 0.04},
  {'manager': 'Schroders', 'share': 0.051},
  {'manager': 'Hang Seng', 'share': 0.063},
  {'manager': 'UBS', 'share': 0.056},
  {'manager': 'SSgA', 'share': 0.066},
  {'manager': 'Fidelity', 'share': 0.088},
  {'manager': 'BlackRock', 'share': 0.084}];
  var poly = [
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0},
    {'x':0,'y':0}
  ];
  var polyMaster = d3.range(20).map(()=>JSON.parse(JSON.stringify(poly)))
  var colorMap = {
    'Fidelity':"#003366",
    'BlackRock':"#366092",
    'SSgA':"#4f81b9",
    'Hang Seng':"#95b3d7",
    'UBS':"#b8cce4",
    'Schroders':"#e7eef8",
    'JP Morgan':"#a6a6a6",
    'Value Partners':"#d9d9d9",
    'Yuanta':"#ffffcc",
    'First State':"#ffffcc",
    'HSBC':'#f6d18b',
    'Invesco':'#e4a733',
    'BOCI-Prudential':"#b29866",
    'Allianz':'#a6a6a6',
    'Mirae Asset':'#d9d9d9',
    'Manulife':'#e7eef8',
    'CSOP':'#b8cce4',
    'Principal':'#95b3d7',
    'Deutsche Bank':'#4f81b9',
    'Aberdeen Standard':'#366092',
    'ChinaAMC':'#003366'
  };
      var sortedData = data.sort(function(a,b) {
        return b.share - a.share;
      });
      let counterRect = 0,
        counterText = 0;
        var column = graphGroup.selectAll('.ranks')
            .data(sortedData)
            .attr('class', 'ranks')
          .enter().append("g");
        column.append("rect")
            .attr("width", 120)
            .attr("height", function(d) {
              return heightScale(d.share)
            })
            .attr('x', function(d) {return 0})
            .attr('y', function(d, i) {
              let previous = counterRect;
              return (counterRect += heightScale(d.share)+2, previous)
            })
            .each(function(d,i) {
              if (i>=0) {
                return polyMaster[i][0].x = 120;
              }
            })
            .each(function(d,i) {
              if (i>=0) {
                const index = i;
                polyMaster[index][0].y = d3.select(this).attr('y');
              }
            })
            .style('fill',function(d,i) {return colorMap[d.manager]});
            column.append("text")
              .attr('x', function(d) {return 60})
              .attr('y', function(d, i) {
                let previous = counterText;
                return (counterText += heightScale(d.share)+2, previous + (heightScale(d.share)/2))
              })
              .attr("dominant-baseline", "central")
              .attr('text-anchor', 'middle')
              .text(function(d) {
                return d.manager;
              });
              console.log(polyMaster)
<script src="https://d3js.org/d3.v5.min.js"></script>

最新更新