首页 > 解决方案 > Javascript 中的丢球,不是一个一个丢,而是所有的球一次丢。(必须与“迭代器”相关)

问题描述

我尝试使用 D3 进行钟形曲线可视化。具体来说,我想一一展示每一个球的下落动作。

我在 Observable 中看到了一个例子。因为我正在学习 D3,所以我尝试在我的 javascript 代码中运行一些东西。原始 Observable 代码如下:
https ://observablehq.com/@cbuie/pachinko-simulator

我在javascript中转换了代码,如下所示。

var random = d3.randomNormal() // Try randomUniform?

const n = 2000
const width = window.innerWidth;
const height = 400
const radius = 2
const dodge = dodger(radius * 2 + 1);
const margin = ({
  top: 0,
  right: 10,
  bottom: 20,
  left: 10
});
const values = Float64Array.from({
  length: n
}, random);
const x = d3.scaleLinear(d3.extent(values), [margin.left, width - margin.right]);
const svg = d3.select('body').append('svg').attr('width', width).attr('height', height).style('overflow', 'visible')
// var fillScale = d3.scaleSequentialLog(chroma.interpolateSinebow)

svg.append("g")
  .attr("transform", `translate(0,${height - margin.bottom})`)
  .call(d3.axisBottom(x));


function dodger(radius) {
  const radius2 = radius ** 2;
  const bisect = d3.bisector(d => d.x);
  const circles = [];


  return function(x) {
    const l = bisect.left(circles, x - radius);
    const r = bisect.right(circles, x + radius);
    let y = 0;
    for (let i = l; i < r; ++i) {
      const {
        x: xi,
        y: yi
      } = circles[i];
      const x2 = (xi - x) ** 2;
      const y2 = (yi - y) ** 2;
      if (radius2 > x2 + y2) {
        y = yi + Math.sqrt(radius2 - x2) + 1e-6;
        i = l - 1;
        continue;
      }
    }
    circles.splice(bisect.left(circles, x, l, r), 0, {
      x,
      y
    }); //what is this?
    return y;
  };


}



for (let i = 0; i < n; ++i) {
  if (i % 5 === 0)
    svg.node();
  const cx = x(values[i]); // x(values[i]);->what is this?
  const cy = height - margin.bottom - dodge(cx) - radius - 1;

  svg.append("circle")
    .attr("cx", cx)
    .attr("cy", -400)
    .attr("r", radius)
    .attr('fill', 'red')
    // .attr("fill","#9e0dd7") //purple
    .transition()
    .duration(650)
    .ease(d3.easeBounce)
    .attr("cy", cy);
}

svg.node();
<script src="https://d3js.org/d3.v5.min.js"></script>

最终结果是一样的,但我的代码没有显示球的运动,而只是像“baam!”一样立即显示了球的最终分布。我很确定它与“生成器”或“迭代器”等有关。

谁能让我知道如何解决它,以便我可以像“沙漏”一样将球从顶部到底部一一移动?

标签: javascriptd3.js

解决方案


我相信这就是您要寻找的东西,是的,它与生成器功能有关,加上有一个间隔计时器来获取下一个生成器值。

function* gen() {
  var random = d3.randomNormal(); // Try randomUniform?

  const n = 2000;
  const width = window.innerWidth;
  const height = 400;
  const radius = 2;
  const dodge = dodger(radius * 2 + 1);
  const margin = { top: 0, right: 10, bottom: 20, left: 10 };

  const values = Float64Array.from({ length: n }, random);

  const x = d3.scaleLinear(d3.extent(values), [
    margin.left,
    width - margin.right
  ]);
  const svg = d3
    .select("body")
    .append("svg")
    .attr("width", width)
    .attr("height", height)
    .style("overflow", "visible");

  // var fillScale = d3.scaleSequentialLog(chroma.interpolateSinebow)

  svg
    .append("g")
    .attr("transform", `translate(0,${height - margin.bottom})`)
    .call(d3.axisBottom(x));

  function dodger(radius) {
    const radius2 = radius ** 2;
    const bisect = d3.bisector(d => d.x);
    const circles = [];

    return function(x) {
      const l = bisect.left(circles, x - radius);
      const r = bisect.right(circles, x + radius);
      let y = 0;
      for (let i = l; i < r; ++i) {
        const { x: xi, y: yi } = circles[i];
        const x2 = (xi - x) ** 2;
        const y2 = (yi - y) ** 2;
        if (radius2 > x2 + y2) {
          y = yi + Math.sqrt(radius2 - x2) + 1e-6;
          i = l - 1;
          continue;
        }
      }
      circles.splice(bisect.left(circles, x, l, r), 0, { x, y }); //what is this?
      return y;
    };
  }

  for (let i = 0; i < n; ++i) {
    if (i % 5 === 0) yield svg.node();
    const cx = x(values[i]); // x(values[i]);->what is this?
    const cy = height - margin.bottom - dodge(cx) - radius - 1;

    svg
      .append("circle")
      .attr("cx", cx)
      .attr("cy", -400)
      .attr("r", radius)
      .attr("fill", "red")
      .attr("fill", "#9e0dd7") //purple
      .transition()
      .duration(650)
      .ease(d3.easeBounce)
      .attr("cy", cy);
  }

  yield svg.node();
}


const genratorAnimation = gen(); 

let result = genratorAnimation.next();
//genratorAnimation.next();
let interval = setInterval(function(){
   if(!result.done) {
     genratorAnimation.next();
   }
   else {
    clearInterval(interval)
   }
}, 50);
<script src="https://d3js.org/d3.v5.min.js"></script>


推荐阅读