Someone who knows CanvasRenderingContext2D in React, please help :)

Viewed 129

When I click on the spin button, I want the value to be highlighted one by one in the canvas. Here you can see the whole code: https://codesandbox.io/s/spinning-wheel-react-forked-s528m


  renderWheel() {
    // determine number/size of sectors that need to created
    let numOptions = this.state.list.length;
    let arcSize = (2 * Math.PI) / numOptions;
    this.setState({
      angle: arcSize
    });

    // dynamically generate sectors from state list
    let angle = 0;
    for (let i = 0; i < numOptions; i++) {
      let text = this.state.list[i];
      this.renderSector(i + 1, text, angle, arcSize);
      angle += arcSize;
    }
  }

  renderSector(index, text, start, arc) {
    // create canvas arc for each list element
    let canvas = document.getElementById("wheel");
    let ctx = canvas.getContext("2d");
    let x = canvas.width / 2;
    let y = canvas.height / 2;
    let radius = 200;
    let startAngle = start;
    let endAngle = start + arc - 0.02;
    let angle = index * arc;
    let baseSize = radius * 1.25;
    let textRadius = baseSize - 48;

    ctx.beginPath();
    ctx.arc(x, y, radius, startAngle, endAngle, false);
    ctx.lineWidth = radius * 0.25;
    ctx.strokeStyle = "white";

    ctx.font = "25px Arial";
    ctx.fillStyle = "blue";

    ctx.stroke();

    ctx.save();
    ctx.translate(
      baseSize + Math.cos(angle - arc / 2) * textRadius,
      baseSize + Math.sin(angle - arc / 2) * textRadius
    );
    ctx.rotate(0);
    ctx.fillText(text, -ctx.measureText(text).width / 2, 7);
    ctx.restore();
  }

When I click on the spin button, this spin () method is executed. The iteration ends between two and five seconds as written in the setTimeout method.


spin = () => {
    var index = 0;
    let timer = setInterval(() => {
      index = (index) % this.state.list.length + 1;
      console.log(index)
    }, 150);
  
    // calcalute result after wheel stops spinning
    setTimeout(() => {
     clearInterval(timer);

      this.setState({
        hasFinishedLoading: true,
        display: this.state.list[index]
      });
    }, Math.floor(Math.random() * 5000 + 2000));

    this.setState({
      spinning: true
    });
  };



1 Answers

Remember: In canvas you cannot access a particular object, so the solution is always to erase and redraw. Don't worry about performance, this is pretty great. I leave you an idea with your code and at the end some suggestions. Try this code, the only thing I did is clean the canvas and redraw without the setTimeOut index

spin = () => {
  let canvas = document.getElementById("wheel");
  let ctx = canvas.getContext("2d");
  var index = 0;
  index = (index % this.state.list.length) + 1;
  let angle = 0;
  let numOptions = this.state.list.length;
  let arcSize = (2 * Math.PI) / numOptions;
  let timer = setInterval(() => {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  this.setState({
    angle: arcSize
  });
  for (let i = 0; i < numOptions; i++) {
    if (i !== index) {
      let text = this.state.list[i];
      this.renderSector(i + 1, text, angle, arcSize);
      angle += arcSize;
    } else {
    }
  }
}, 150);

// calcalute result after wheel stops spinning
setTimeout(() => {
  clearInterval(timer);

  this.setState({
    hasFinishedLoading: true,
    display: this.state.list[index]
  });
}, Math.floor(Math.random() * 5000 + 2000));

this.setState({
  spinning: true
});
};
  • Don't use "getElementById" in react, it's dangerous. Use a reference.
Related