Canvas 使用 clearRect 和 AudioContext 清除路径

Canvas clear path with clearRect and AudioContext

我有这个可视化工具,一切正常。唯一的问题是,当您使用 clean 功能清除 canvas,然后单击 changeSrc 时,您总是可以看到上一首歌曲的可视化效果。我可以摆脱这个吗?

您可能需要 运行 在 js fiddle 上 fiddle。

https://jsfiddle.net/t87wyzgd/6/

var renderVizualitationID,
  canvas, ctx, center_x, center_y, radius, bars,
  x_end, y_end, bar_height, bar_width,
  frequency_array,
  wrap, source;



wrap = $('.w')



canvas = document.getElementById("renderer");
ctx = canvas.getContext("2d");

bars = 200;
bar_width = 2;
multiplier = 0.7;



audio = new Audio();
audio.crossOrigin = "anonymous";

context = new(window.AudioContext || window.webkitAudioContext)();
analyser = context.createAnalyser();

audio.src = "https://api.soundcloud.com/tracks/42328219/stream?client_id=b1495e39071bd7081a74093816f77ddb"; // the source path
audio.loop = true;
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);

frequency_array = new Uint8Array(analyser.frequencyBinCount);

audio.play();
animationLooper();







function animationLooper() {

  // set to the size of device

  canvas.width = wrap.width();
  canvas.height = wrap.height();


  // find the center of the window
  center_x = canvas.width / 2;
  center_y = canvas.height / 2;
  radius = canvas.height / 6;

  //draw a circle
  ctx.beginPath();
  ctx.arc(center_x, center_y, radius, 0, 2 * Math.PI);
  ctx.stroke();

  analyser.getByteFrequencyData(frequency_array);
  var i;
  for (i = 0; i < bars; i++) {

    //divide a circle into equal parts
    rads = Math.PI * 2 / bars;

    bar_height = frequency_array[i] * multiplier;

    // set coordinates
    x = center_x + Math.cos(rads * i) * (radius);
    y = center_y + Math.sin(rads * i) * (radius);
    x_end = center_x + Math.cos(rads * i) * (radius + bar_height);
    y_end = center_y + Math.sin(rads * i) * (radius + bar_height);

    //draw a bar
    var lineColor = "rgb(" + frequency_array[i] + ", " + frequency_array[i] + ", " + 205 + ")";

    ctx.strokeStyle = lineColor;
    ctx.lineWidth = bar_width;
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x_end, y_end);
    ctx.stroke();

  }

  renderVizualitationID = requestAnimationFrame(animationLooper);
}

$('#clean').on('click',function() {
  if (renderVizualitationID) cancelAnimationFrame(renderVizualitationID);

  audio.pause();
  audio.src = '';

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

});

$('#changeSrc').on('click',function() {

 audio.src = "https://api.soundcloud.com/tracks/693365626/stream?client_id=r4wruADPCq7iqJomagvYpdehvILa2bgE"; // the source path

  audio.play();
  animationLooper();

});
.w {
  position: relative;
  top: 0;
  left: 0;
  width: 400px;
  height: 400px;
  background: #ccc;
}

#renderer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #111;

  background: #1D4350;

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="w">
  <canvas id="renderer"></canvas>
</div>

<a id="clean" href="#" >clean</a>
<a id="changeSrc" href="#" >changeSrc</a>

发生这种情况是因为您的 AudioAnalyser 通过缓冲数据来工作,它只是随着时间的推移取消移动新数据。所以当你暂停你的音频时,它仍然会包含一些数据。

为避免这种情况,您只需在 clean 函数

中创建一个新的 AudioAnalyser

var renderVizualitationID,
  canvas, ctx, center_x, center_y, radius, bars,
  x_end, y_end, bar_height, bar_width,
  frequency_array,
  wrap, source;



wrap = $('.w')



canvas = document.getElementById("renderer");
ctx = canvas.getContext("2d");

bars = 200;
bar_width = 2;
multiplier = 0.7;



audio = new Audio();
audio.crossOrigin = "anonymous";

context = new(window.AudioContext || window.webkitAudioContext)();
analyser = context.createAnalyser();

audio.src = "https://api.soundcloud.com/tracks/42328219/stream?client_id=b1495e39071bd7081a74093816f77ddb"; // the source path
audio.loop = true;
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);

frequency_array = new Uint8Array(analyser.frequencyBinCount);

audio.play();
animationLooper();





// do not change the size of your canvas when you are drawing on it
// that will reset the whole canvas and require anew pixel buffer
// so do it only when really required
window.onresize = function() {
  // set to the size of device

  canvas.width = wrap.width();
  canvas.height = wrap.height();
};
window.onresize();

function animationLooper() {

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

  // find the center of the window
  center_x = canvas.width / 2;
  center_y = canvas.height / 2;
  radius = canvas.height / 6;

  //draw a circle
  ctx.beginPath();
  ctx.arc(center_x, center_y, radius, 0, 2 * Math.PI);
  ctx.stroke();

  analyser.getByteFrequencyData(frequency_array);
  var i;
  for (i = 0; i < bars; i++) {

    //divide a circle into equal parts
    rads = Math.PI * 2 / bars;

    bar_height = frequency_array[i] * multiplier;

    // set coordinates
    x = center_x + Math.cos(rads * i) * (radius);
    y = center_y + Math.sin(rads * i) * (radius);
    x_end = center_x + Math.cos(rads * i) * (radius + bar_height);
    y_end = center_y + Math.sin(rads * i) * (radius + bar_height);

    //draw a bar
    var lineColor = "rgb(" + frequency_array[i] + ", " + frequency_array[i] + ", " + 205 + ")";

    ctx.strokeStyle = lineColor;
    ctx.lineWidth = bar_width;
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x_end, y_end);
    ctx.stroke();

  }

  renderVizualitationID = requestAnimationFrame(animationLooper);
}

$('#clean').on('click',function() {
  if (renderVizualitationID) cancelAnimationFrame(renderVizualitationID);

  audio.pause();
  audio.src = '';
  frequency_array.fill( 0 );
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // kill the previous one
  analyser.disconnect();
  // create a new analyser
  analyser = context.createAnalyser();
  source.connect( analyser );
  analyser.connect(context.destination);
});

$('#changeSrc').on('click',function() {

 audio.src = "https://api.soundcloud.com/tracks/693365626/stream?client_id=r4wruADPCq7iqJomagvYpdehvILa2bgE"; // the source path
  audio.play();
  animationLooper();  
});
.w {
  position: relative;
  top: 0;
  left: 0;
  width: 400px;
  height: 400px;
  background: #ccc;
}

#renderer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: #111;

  background: #1D4350;

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="w">
  <canvas id="renderer"></canvas>
</div>

<a id="clean" href="#" >clean</a>
<a id="changeSrc" href="#" >changeSrc</a>