如何在我们想要完全显示的图像周围“解开”或绘制动态弧(圆形倒计时)

时间:2013-09-20 09:49:53

标签: canvas html5-canvas

我正在尝试在图片周围绘制一个圆形倒计时(arc会将其end angle降低到另一个arc以上,这仍然是静态的。

在绘制静态和动态弧以将图像绘制到其中之后,我必须clip。 但问题是,图像正在进入动态弧(所以我们没有完全看到它)。

这是代码和JsFiddle:

<canvas id="test" width="230px", height="230px"></canvas>    
var ctx = document.getElementById('test').getContext("2d");
var img = new Image();
img.addEventListener('load', function(e) {
    ctx.beginPath();
    ctx.arc(115, 115, 100, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.lineWidth = 15; 
    ctx.strokeStyle = 'back'; 
    ctx.stroke();

    ctx.beginPath();
    ctx.arc(115, 115, 100, 0, 1*Math.PI, true);
    ctx.closePath();
    ctx.lineWidth = 15; 
    ctx.strokeStyle = 'red'; 
    ctx.stroke();

    ctx.clip();

    ctx.drawImage(this, 15, 15, 200, 200);
}, true);
img.src="https://si0.twimg.com/profile_images/3309741408/eff94615a3653c01a9d5a178ced7fbb5.jpeg";

JsFiddle

更新 以下是我正在寻找的内容非常接近:JsFiddle updated,除了红色arc以非常糟糕的方式出现...

3 个答案:

答案 0 :(得分:3)

订单重要

你非常亲密,只需要改变一些事情的命令(我希望我理解你的意图正确):

我建议首先用一个完整的圆圈进行裁剪,因为这不会遮挡在它上面绘制的内容(如果你以后剪辑,你也可以剪切圆弧 - 除非你想这样做)。

设置并重置剪贴蒙版

重置剪贴蒙版结果有点“不稳定”,即。设置一个新路径和一个覆盖整个画布的矩形。因此,目前在这种情况下更好的选择是依靠save / restore方法重置它:

/// backup current state of canvas
ctx.save();

/// create clipping mask, a full circle
ctx.beginPath();
ctx.arc(115, 115, 100, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();

/// then draw the image that you want to clip
ctx.drawImage(this, 15, 15, 200, 200);

/// remove clipping by restoring canvas state to previous
ctx.restore();

未绑定的叠加层

现在将图像剪切成圆形,您可以绘制圆弧,而不考虑或重新计算与图像相关的线宽等,因为它们不受剪裁限制:

/// draw the arcs on top
ctx.beginPath();
ctx.arc(115, 115, 100, 0, Math.PI * 2, true);
ctx.lineWidth = 15; 
ctx.strokeStyle = 'red'; 
ctx.stroke();

ctx.beginPath();
ctx.arc(115, 115, 100, 0, 1*Math.PI, true);
ctx.lineWidth = 15; 
ctx.strokeStyle = 'blue'; 
ctx.stroke();

<强> MODIFIED FIDDLE HERE

答案 1 :(得分:2)

您可以使用context.save / context.restore来控制裁剪活动

enter image description here enter image description here

这是一种方法:

// Outer circle
ctx.beginPath();
ctx.arc(150, 150, 40, 0, 2 * PI, false);
ctx.closePath();
ctx.lineWidth=20;
ctx.strokeStyle="black";
ctx.stroke();

// Inner sweeping arc
ctx.beginPath();
ctx.arc(150, 150, 40, startRadians, endRadians, false);
ctx.lineWidth = 10;
ctx.strokeStyle = 'red';
ctx.stroke();

// Clipped avatar
ctx.save();
ctx.beginPath();
ctx.arc(150, 150, 30, 0, 2 * PI, false);
ctx.closePath();
ctx.clip();
ctx.drawImage(avatar, 0, 0, avatar.width, avatar.height, 150-40, 150-40, 80, 80);
ctx.restore();

这是代码和小提琴:http://jsfiddle.net/m1erickson/j96yy/

$(function() {
  var avatarUrl = 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/avatar.jpg';
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var fps = 60;

  window.requestAnimFrame = (function(callback) {
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
      function(callback) {
        window.setTimeout(callback, 1000 / fps);
      };
  })();


  // Set context styles
  ctx.strokeStyle = '#ff9944';
  ctx.lineCap = 'round';

  // Set var's to control arc
  var PI = Math.PI;
  var startRadians = -PI / 2;
  var endRadians = -PI / 2;
  var tickRadians = 2 * PI / 60 / 2; // 60 ticks per circle
  var continue_animation = true;

  // Load avatar image, then animate
  var avatar = loadImage(avatarUrl, animate);
  
  // Compute size and location of the avatar.
  var centerX = canvas.width / 2;
  var centerY = canvas.height / 2;
  var radius  = canvas.width * 0.33;

  // Animate an arc inside a circle
  function animate() {
    // Update
    endRadians += tickRadians;
    if (endRadians > 2 * PI) {
      continue_animation = false;
    }

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // Outer circle
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, 0, 2 * PI, false);
    ctx.closePath();
    ctx.lineWidth = radius / 2;
    ctx.strokeStyle = '#444444';
    ctx.stroke();

    // Inner sweeping arc
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, startRadians, endRadians, false);
    ctx.lineWidth = radius / 4;
    ctx.strokeStyle = calcArcStateColor(endRadians);
    ctx.stroke();

    // Clipped avatar
    ctx.save();
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius * 0.75, 0, 2 * PI, false);
    ctx.closePath();
    ctx.clip();
    ctx.drawImage(avatar, 0, 0, avatar.width, avatar.height, centerX - radius, centerY - radius, radius * 2, radius * 2);
    ctx.restore();

    // Request new frame
    if (continue_animation) {
      requestAnimFrame(animate);
    }
  }

  $('#go').click(function() {
    endRadians = -PI / 2;
    continue_animation = true;
    animate();
  });

  animate();
});

function loadImage(url, callback) {
  var img = new Image();
  img.onload = function() {
    if (callback) callback();
  };
  img.src = url;
  return img;
}

function calcArcStateColor(radians) {
  if      (radians > Math.PI * 1.75) return '#00DD44';
  else if (radians > Math.PI * 1.00) return '#FFDD44';
  else if (radians > Math.PI * 0.25) return '#FF8844';
  else                               return '#FF4444';
}
body {
  background-color: ivory;
  padding: 20px;
}
canvas {
  border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css" rel="stylesheet" />

<button id="go">Animate</button><br />
<canvas id="canvas" width="180" height="180"></canvas>

答案 2 :(得分:0)

在剪辑之前保存您的上下文,并在您想要取消剪辑所需的时间使用恢复方法