1

我正在尝试在图像周围绘制一个圆形倒计时(一个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 更新,除了红色arc以非常糟糕的方式出现......

4

3 回答 3

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();

修改后的小提琴在这里

于 2013-09-20T16:11:10.207 回答
2

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

在此处输入图像描述在此处输入图像描述

这是一种方法:

// 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>

于 2013-09-20T16:34:49.530 回答
0

在剪辑之前保存您的上下文并在需要取消剪辑的任何地方使用恢复方法

于 2017-06-27T10:04:11.810 回答