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

标签 javascript d3.js

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

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

我在我的 rect append 中添加了一个 .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>

问题

我如何迭代地存储我的矩形的 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>

关于javascript - d3.each() 一次存储一个值,而不是一次存储所有值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57388293/

相关文章:

javascript - 有没有办法通过 Angular 2+ 中的内置方法检测 ERR_INTERNET_DISCONNECTED

javascript - 如何在 React 中从父级重置表单

PHP - 检查 $get 变量然后清除 div 并包含 php 文件

javascript - 如何仅将替代深度值分配给 d3js 中的子 Node ?

javascript - 如何将 svg 元素 ID 与 json 键匹配

javascript - 使用 Sinon.js 测试一个函数调用 ES6 模块中的另一个函数

javascript - Node.js 客户端 session 不创建 req.session

csv - D3.js - 从 chrome 加载 csv 文件

javascript - 从 JavaScript 中的对象数组中选择特定值

svg - 有没有办法在 d3 中为饼图添加高亮显示?