canvas2d:cancelAnimationFrame 不起作用

问题

一旦蜂窝的每个项目移动到其结束位置(动画从点击六边形开始),它就会触发 stop()。到目前为止,这有效。问题是 stop() 是在无限循环中调用的(请参阅控制台日志记录 stop),在我看来,cancelAnimationFrame 并不像 const canvas = document.querySelector('canvas'); const ctx = canvas.getcontext("2d"); const hexagonArray = []; var raf; const items = [ { heading: "Lorem Ipsum",subheading: "dolor sit amet",},{ heading: "Lorem Ipsum",]; class Hexagon { constructor(heading,subheading,idx) { this.idx = idx; this.sixtyDeg = Math.PI * 2 / 6; this.radius = 80; this.gap = 1.9; this.fromX = canvas.width / 2; this.fromY = canvas.height / 2; this.toX = this.fromX + this.gap * this.radius * Math.sin(this.sixtyDeg * idx); this.toY = this.fromY + this.gap * this.radius * Math.cos(this.sixtyDeg * idx); this.x = this.fromX; this.y = this.fromY; this.frames = 100; this.frame = 0; this.speedX = this.toX / this.frames; this.speedY = this.toY / this.frames; this.isCurrent = false; this.heading = heading; this.subheading = subheading; } draw() { const { sixtyDeg,radius,x,y,idx } = this; // ctx.fillStyle = "red"; // ctx.fillText(`no.${idx}`,y); ctx.beginPath(); for (let i = 0; i < 6; i++) { ctx.lineTo( x + radius * Math.cos(sixtyDeg * i),y + radius * Math.sin(sixtyDeg * i) ); } ctx.closePath(); ctx.fill(); } update(shouldOpen) { this.x = expeaseinout( this.frame,this.fromX,this.toX - this.fromX,this.frames ); this.y = expeaseinout( this.frame,this.fromY,this.toY - this.fromY,this.frames ); if ( (shouldOpen ? this.frame < this.frames : this.frame > this.frames) && this.idx !== 0 ) { this.frame = shouldOpen ? this.frame + 1 // open : this.frame - 1; // close } else if (this.idx !== 0) { stop(); } this.draw(); } toggle() { let toggle = false; this.update(!toggle); toggle = !toggle; } } function animate() { ctx.clearRect(0,canvas.width,canvas.height); hexagonArray.forEach((hexagon) => { hexagon.toggle(); }); raf = window.requestAnimationFrame(animate); } function stop() { console.log('stop'); window.cancelAnimationFrame(raf); } canvas.addEventListener('click',function (event) { const { clientX,clientY } = event; hexagonArray.some((hexagon) => { const isInRange = ( inRange(clientX,hexagon.x - hexagon.radius,hexagon.x + hexagon.radius) && inRange(clientY,hexagon.y - hexagon.radius,hexagon.y + hexagon.radius) ); if (isInRange) { raf = window.requestAnimationFrame(animate); return true; } }); }); function init() { items.forEach(({ heading,subheading },idx) => { hexagonArray.push(new Hexagon(heading,idx)); }); hexagonArray.forEach((hexagon) => { hexagon.draw(); }); } init(); /** -------------------------------------------------------------------------------- */ /** -------------------------------------------------------------------------------- */ /** -------------------------------------------------------------------------------- */ window.addEventListener('resize',function() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; ctx.clearRect(0,canvas.height); init(); }); function expeaseinout(frame,initPos,distance,frames) { frame /= frames / 2; if (frame < 1) return distance/2 * Math.pow( 2,10 * (frame - 1) ) + initPos; frame--; return distance/2 * ( -Math.pow( 2,-10 * frame) + 2 ) + initPos; }; function inRange(n,min,max) { return ((n-min)*(n-max) <= 0); } 那样工作。

目标

一旦蜂窝的每个项目移动到其结束位置,动画就应该停止,因为无论如何都没有任何移动。再次单击后,每个项目都会再次折叠到中间(与开场动画完全相反),有点像切换。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <script async src="index.js"></script>
  <title>canvas2d</title>
</head>
<body>
  <style>
    body {
      min-width: 100vw;
      min-height: 100vh;
      background-color: lightgray;
    }

    canvas {
      background-color: gray;
    }
  </style>
  <canvas
    width="440"
    height="440"
  ></canvas>
</body>
</html>

#Python 3.7.9#
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,NavigationToolbar2Tk)
import numpy as np




figure = Figure(figsize = (5,5),dpi = 100)
ax = figure.add_subplot(111)


def plot():
    

    x = np.random.rand(1,10)
    y = np.random.rand(1,10)
    
    ax.scatter(x,y)
 
    
 
    
root = tk.Tk()


canvas = FigureCanvasTkAgg(figure,root)
canvas.draw()
canvas.get_tk_widget().pack(pady = 10)

toolbar = NavigationToolbar2Tk(canvas,root)
toolbar.update()
canvas.get_tk_widget().pack()


button = tk.Button(root,text = "Graph It",command = plot)
button.pack()


root.mainloop()

huyang1644 回答:canvas2d:cancelAnimationFrame 不起作用

实际上的问题是您在之后立即再次调用 requestAnimationFrame 因此它继续循环。

function animate() {

  ctx.clearRect(0,canvas.width,canvas.height);

  // You're updating the 6 hexagons & calling "cancelAnimationFrame" in here
  hexagonArray.forEach((hexagon) => {
    hexagon.toggle();
  });

  // BUT... you call the animation again just after,so it keeps looping
  raf = window.requestAnimationFrame(animate);
}

如果在更新逻辑和绘图之前调用动画,它不会循环

function animate() {
  raf = window.requestAnimationFrame(animate);
  ctx.clearRect(0,canvas.height);
  hexagonArray.forEach((hexagon) => {
    hexagon.toggle();
  });
}

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext("2d");
const hexagonArray = [];

let raf;

const items = [
  {
    heading: "Lorem Ipsum",subheading: "dolor sit amet",},{
    heading: "Lorem Ipsum",];

class Hexagon {
  constructor(heading,subheading,idx) {
    this.idx = idx;
    this.sixtyDeg = Math.PI * 2 / 6;
    this.radius = 80;
    this.gap = 1.9;
    this.fromX = canvas.width / 2;
    this.fromY = canvas.height / 2;
    this.toX = this.fromX + this.gap * this.radius * Math.sin(this.sixtyDeg * idx);
    this.toY = this.fromY + this.gap * this.radius * Math.cos(this.sixtyDeg * idx);
    this.x = this.fromX;
    this.y = this.fromY;
    this.frames = 100;
    this.frame = 0;
    this.speedX = this.toX / this.frames;
    this.speedY = this.toY / this.frames;
    this.isCurrent = false;
    this.heading = heading;
    this.subheading = subheading;
  }

  draw() {
    const { sixtyDeg,radius,x,y,idx } = this;
    // ctx.fillStyle = "red";
    // ctx.fillText(`no.${idx}`,y);
    ctx.beginPath();
    for (let i = 0; i < 6; i++) {
      ctx.lineTo(
        x + radius * Math.cos(sixtyDeg * i),y + radius * Math.sin(sixtyDeg * i)
      );
    }
    ctx.closePath();
    ctx.fill();
  }

  update(shouldOpen) {
    this.x = expEaseInOut(
      this.frame,this.fromX,this.toX - this.fromX,this.frames  
    );

    this.y = expEaseInOut(
      this.frame,this.fromY,this.toY - this.fromY,this.frames  
    );

    if (
      (shouldOpen ? this.frame < this.frames : this.frame > this.frames)
      && this.idx !== 0
    ) {
      this.frame = shouldOpen
        ? this.frame + 1  // open
        : this.frame - 1; // close
    } else if (this.idx !== 0) {
      stop();
    }

    this.draw();
  }

  toggle() {
    let toggle = false;
    this.update(!toggle);
    toggle = !toggle;
  }
}

function animate() {
  raf = window.requestAnimationFrame(animate);
  ctx.clearRect(0,canvas.height);
  hexagonArray.forEach((hexagon) => {
    hexagon.toggle();
  });
}

function stop() {
  console.log('stop');
  window.cancelAnimationFrame(raf);
}

canvas.addEventListener('click',function (event) {
  const {
    clientX,clientY
  } = event;

  hexagonArray.some((hexagon) => {
    const isInRange = (
      inRange(clientX,hexagon.x - hexagon.radius,hexagon.x + hexagon.radius)
      && inRange(clientY,hexagon.y - hexagon.radius,hexagon.y + hexagon.radius)
    );
    if (isInRange) {
      raf = window.requestAnimationFrame(animate);
      return true;
    }
  });
});

function init() {
  items.forEach(({ heading,subheading },idx) => {
    hexagonArray.push(new Hexagon(heading,idx));
  });
  hexagonArray.forEach((hexagon) => {
    hexagon.draw();
  });
}

init();

/** -------------------------------------------------------------------------------- */
/** -------------------------------------------------------------------------------- */
/** -------------------------------------------------------------------------------- */

window.addEventListener('resize',function() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  ctx.clearRect(0,canvas.height);
  init();
});

function expEaseInOut(frame,initPos,distance,frames) {
  frame /= frames / 2;
  if (frame < 1) return distance/2 * Math.pow( 2,10 * (frame - 1) ) + initPos;
  frame--;
  return distance/2 * ( -Math.pow( 2,-10 * frame) + 2 ) + initPos;
};

function inRange(n,min,max) {
  return ((n-min)*(n-max) <= 0);
}
body {
  min-width: 100vw;
  min-height: 100vh;
  background-color: lightgray;
}

canvas {
  background-color: gray;
}
<canvas width="440" height="440"></canvas>

本文链接:https://www.f2er.com/819.html

大家都在问