根据for循环的索引查找小数指数

问题描述 投票:2回答:4

用户选择一个数字,然后d3.js应显示多个圆圈。我有一个用于为圆圈指定颜色的数组:

var color =["red","blue", "yellow", "orange",....., ] 

●如果用户选择593,则前500个圆圈应为红色(color[0]),接下来的90个应为蓝色(color[1]),最后3个圆圈(color[2])应为黄色因为

593= 500+90+3 = 5*10^2+9*10^1+3*10^0 

或者

var number = 593
var number_as_array = number.toString().split(''); 

然后

593 = 5*number_as_array[0]*10^number_as_array.length-0-1 + 9*number_as_array[1]*10^number_as_array.length-1-1+ 3*number_as_array[2]*10^number_as_array.length-2-1

●如果用户选择4168,则前4000个圆圈应为红色,下一个100应为蓝色,下一个为60黄色,最后一个为橙色

要为每个圆圈指定颜色,我用它来创建一个带有for循环的JS对象构建数组

var data=[]
for (index =0; index< number; index++){
circle= {};
        circle.cx = circle_x;
        circle.cy = circle_y;
        circle.color = color[????]
        data.push(circle);

如何根据上述条件将颜色分配给circle.color

javascript arrays for-loop d3.js decimal
4个回答
2
投票

不要从其他答案中减少,这是另一种方法。

取一个给定的总圈数,它会检查总数中需要多少有效数字(向下舍入),以便任何给定的索引小于舍入总数。

我不确定这是否完全合理,所以我将使用一个例子:

如果共有132个圈子:

  • 索引0到99将小于100(132向下舍入,有一个有效数字)。
  • 索引100到129将小于130(132向下舍入,有两位有效数字)。
  • 索引130和131将小于132(132具有所有有效数字)。

这是一个快速演示(行数为50个圆圈):

var svg = d3.select("body")
  .append("svg")
  .attr("width",510)
  .attr("height",510);
  
var n = 377;

var color = d3.scaleOrdinal()
.range(["steelblue","orange","crimson","lawngreen","pink"])

var digits = Math.floor(Math.log10(n));

var circles = svg.selectAll("circle")
  .data(d3.range(n))
  .enter()
  .append("circle")
  .attr("cx",function(d,i) { return i%50 * 10 + 5 })
  .attr("cy",function(d,i) { return Math.floor(i/50) * 10 + 5 })
  .attr("r",5)
  .attr("fill", function(d,i) {
    var exp = digits;
    while (i < Math.floor(n/Math.pow(10,digits-exp))*Math.pow(10,digits-exp)) {
      exp--;
    }
    return color(exp);
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

2
投票
var color = ["red","orange", "yellow", "green", "blue", "indigo", "violet"];
var circleCount = "4192"; // use string
var length = circleCount.length;
var counter = [];
for (var i = 0; i < length; i++) {
    var digit = circleCount.substring(i, i+1);
    var exponent = length - i - 1;
    var number = digit * Math.pow(10, exponent);
    counter.push(number); // might have to use .unshift instead of .push
}
console.log(counter);
for (var i = 0; i < counter.length; i++) {
    for (var j = 0; j < counter[i]; j++) {
        drawCircle(color[i]);
    }
}

2
投票

这是使用D3的Threshold Scales的完美案例:你给它N个数字,你想要颜色之间的中断,N + 1颜色返回任何输入值。以下是文档中的示例:

var color = d3.scaleThreshold()
    .domain([0, 1])
    .range(["red", "white", "green"]);

color(-1);   // "red"
color(0);    // "white"
color(0.5);  // "white"
color(1);    // "green"
color(1000); // "green"

因此,您的案例的挑战是如何将(例如)593的示例输入转换为两个数字[500,590]的数组:

var sinput = 593 + ""; // make the input a string
var digits = sinput.split("").slice(0, -1); // use all digits but the last one
var breaks = digits.map((d, i, a) =>
    +(a.slice(0, i+1).join("")) * Math.pow(10, a.length-i)
);

var colors = ["red", "blue", "yellow", "orange"];
var tScale = d3.scaleThreshold()
    .domain(breaks)
    .range(colors);

任何<500映射到“红色”,从500 - 589映射到“蓝色”,并且≥590映射到“黄色”。除非使用4位数字作为输入,否则不使用附加范围颜色(“橙色”)。

注意:此逻辑假定输入数字至少为2位数。

您现在可以在创建圆圈时指定颜色 - 而不是使用.attr("color", (d, i) => tScale(i))之类的语法在数据数组中预先填充颜色


1
投票

其他方法似乎过于复杂。您可以将数字拆分为数字,然后根据索引创建所需的10 ^ digitIndex圆圈颜色。我已经包含一行来检查数字是不是太大了。

function mapColors(num) {
  var color =['red','blue', 'yellow', 'orange'];
  
  // If the number is longer than the color array, return undefined
  if ((''+num).length > color.length) return;
  
  return (''+num).split('').reduce(function (acc, n, i, arr) {
    for (var j=n*Math.pow(10, arr.length-i-1); j; --j) {
      acc.push({'color':color[i]});
      // Add more circle properties here
    }
    return acc;
  }, []);
}

console.log(mapColors(23));
© www.soinside.com 2019 - 2024. All rights reserved.