Ответ 1
Используйте .arc
для создания кругового хода, а затем используйте .clip()
, чтобы сделать текущую область отсечения.
Затем вы можете использовать .clearRect()
для стирания всего холста, но изменится только обрезанная область.
Кажется, единственный способ очистить область от холста - использовать команду clearRect() - мне нужно очистить круг (я маскирую области из заполненного холста, точечные огни в этом конкретном случае) и, несмотря на все попытки это не представляется возможным.
Я попробовал рисовать круг с альфа-значением 0, но просто ничего не появлялось бы, если альфа не была выше (что противоречит точке: P). Я предполагаю, что contex.fill() рисует его как добавление, а скорее чем замена.
Любые предложения о том, как я могу (быстро) очистить круги для целей маски?
Используйте .arc
для создания кругового хода, а затем используйте .clip()
, чтобы сделать текущую область отсечения.
Затем вы можете использовать .clearRect()
для стирания всего холста, но изменится только обрезанная область.
Если вы делаете игру или что-то там, где сжимаете каждый бит производительности, посмотрите, как я сделал этот ответ: Canvas - Заполните прямоугольник во всех областях, которые полностью прозрачный
В частности, редактирование ответа, которое приводит к этому: http://jsfiddle.net/a2Age/2/
Огромные плюсы здесь:
(1) Я действительно жаловался на это, и resetClip() был помещен в официальную спецификацию из-за этого, но это будет в то время как браузеры реализуют его.
var ctx = document.getElementById('canvas1').getContext('2d'),
ambientLight = 0.1,
intensity = 1,
radius = 100,
amb = 'rgba(0,0,0,' + (1 - ambientLight) + ')';
addLight(ctx, intensity, amb, 200, 200, 0, 200, 200, radius); // First circle
addLight(ctx, intensity, amb, 250, 270, 0, 250, 270, radius); // Second circle
addLight(ctx, intensity, amb, 50, 370, 0, 50, 370, radius, 50); // Third!
ctx.fillStyle = amb;
ctx.globalCompositeOperation = 'xor';
ctx.fillRect(0, 0, 500, 500);
function addLight(ctx, intsy, amb, xStart, yStart, rStart, xEnd, yEnd, rEnd, xOff, yOff) {
xOff = xOff || 0;
yOff = yOff || 0;
var g = ctx.createRadialGradient(xStart, yStart, rStart, xEnd, yEnd, rEnd);
g.addColorStop(1, 'rgba(0,0,0,' + (1 - intsy) + ')');
g.addColorStop(0, amb);
ctx.fillStyle = g;
ctx.fillRect(xStart - rEnd + xOff, yStart - rEnd + yOff, xEnd + rEnd, yEnd + rEnd);
}
canvas {
border: 1px solid black;
background-image: url('http://placekitten.com/500/500');
}
<canvas id="canvas1" width="500" height="500"></canvas>
У вас есть несколько вариантов.
Во-первых, здесь функция, которую мы будем использовать для заполнения круга.
var fillCircle = function(x, y, radius)
{
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
};
clip()
var clearCircle = function(x, y, radius)
{
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.clip();
context.clearRect(x - radius - 1, y - radius - 1,
radius * 2 + 2, radius * 2 + 2);
};
Смотрите на jsFiddle.
globalCompositeOperation
var clearCircle = function(x, y, radius)
{
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
Смотрите на jsFiddle.
Оба дали желаемый результат на экране, однако в моем случае производительность была недостаточной, поскольку я рисовал и очищал много кругов в каждом кадре для эффекта. В конце концов, я нашел другой способ получить аналогичный эффект для того, что я хотел, просто нарисовав более толстые линии на дуге, но приведенное выше может по-прежнему быть полезным для тех, кто имеет разные требования к производительности.
Учитывая требования, эти ответы в порядке. Но давайте говорить, что вы похожи на меня, и у вас есть дополнительные требования:
Для первого требования решение состоит в использовании context.globalCompositeOperation = 'destination-out'
Синяя - первая форма, а красная - вторая. Как вы можете видеть, destination-out
удаляет секцию из первой формы.
Вот пример кода:
explosionCanvasCtx.fillStyle = "red"
drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
Здесь потенциальная проблема с этим: вторая fill()
очистит все под ней, включая фон. Иногда вам нужно только очистить первую фигуру, но вы все равно хотите видеть слои, находящиеся под ней.
Решение этого заключается в том, чтобы нарисовать это на временном холсте, а затем drawImage
, чтобы нарисовать временный холст на ваш основной холст. Код будет выглядеть так:
diameter = projectile.radius * 2
console.log "<canvas width='" + diameter + "' height='" + diameter + "'></canvas>"
explosionCanvas = $("<canvas width='" + diameter + "' height='" + diameter + "'></canvas>")
explosionCanvasCtx = explosionCanvas[0].getContext("2d")
explosionCanvasCtx.fillStyle = "red"
drawCircle(explosionCanvasCtx, projectile.radius, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
explosionCanvasCtx.globalCompositeOperation = 'destination-out' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
durationPercent = (projectile.startDuration - projectile.duration) / projectile.startDuration
drawCircle(explosionCanvasCtx, projectile.radius + 20, projectile.radius, projectile.radius)
explosionCanvasCtx.fill()
explosionCanvasCtx.globalCompositeOperation = 'source-over' #see https://developer.mozilla.org/samples/canvas-tutorial/6_1_canvas_composite.html
ctx.drawImage(explosionCanvas[0], projectile.pos.x - projectile.radius, projectile.pos.y - projectile.radius) #center
Используйте canvas.getContext("2d").arc(...)
, чтобы нарисовать круг над областью с цветом фона?
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.arc(x, y, r, 0, 2*Math.PI, false);
context.fillStyle = "#FFFFFF";
context.fill();
Где x = левая позиция, y = правое положение, r = радиус и ctx = ваш холст:
function clearCircle( x , y , r ){
for( var i = 0 ; i < Math.round( Math.PI * r ) ; i++ ){
var angle = ( i / Math.round( Math.PI * r )) * 360;
ctx.clearRect( x , y , Math.sin( angle * ( Math.PI / 180 )) * r , Math.cos( angle * ( Math.PI / 180 )) * r );
}
}