tutorial - ¿Cómo dibujar el segmento de un donut con lienzo HTML5?
como dibujar una dona paso a paso (6)
Adaptar / simplificar la respuesta de @Simon Sarris para trabajar fácilmente con cualquier ángulo da lo siguiente:
Para crear un segmento de arco, dibuje un arco exterior (de n radianes) en una dirección y luego un arco opuesto (del mismo número de radianes) en un radio menor y rellene el área resultante.
var can = document.getElementById(''canvas1'');
var ctx = can.getContext(''2d'');
var angle = (Math.PI*2)/8;
var outer_arc_radius = 100;
var inner_arc_radius = 50.;
ctx.beginPath()
//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
ctx.arc(100,100,outer_arc_radius,0,angle, false); // outer (filled)
// the tip of the "pen is now at 0,100
ctx.arc(100,100,inner_arc_radius,angle,0, true); // outer (unfills it)
ctx.fill();
<canvas id="canvas1" width="200" height="200"></canvas>
Como lo indica el título. es posible?
Edit: cuando digo donut me refiero a una vista superior, 2D
¿Es la única opción para dibujar un segmento de un círculo y luego dibujar un segmento de un círculo más pequeño con el mismo origen y un radio más pequeño en la parte superior, con el color del fondo? Eso sería una mierda si es así :(
Con WebGL (uno de los contextos del lienzo HTML5) es posible. Incluso hay algunas bibliotecas JS para navegadores que aún no lo soportan / implementan, echa un vistazo a estos enlaces:
- http://sixrevisions.com/web-development/how-to-create-an-html5-3d-engine/
- http://slides.html5rocks.com/#landing-slide
- http://sebleedelisle.com/2009/09/simple-3d-in-html5-canvas/
- http://www.khronos.org/webgl/
- http://webdesign.about.com/od/html5tutorials/f/is-there-a-3d-context-for-html5-canvas.htm
- http://code.google.com/p/html-gl/
Dados los requisitos, lo que dice @SimonSarris satisface el problema. Pero digamos que eres como yo y que, en cambio, quieres "borrar" una parte de una forma que puede estar parcialmente fuera de los límites de la forma que estás despejando. Si tienes ese requisito, su solución no te hará querer lo que quieres. Se verá como el "xor" en la imagen de abajo.
La solución es usar context.globalCompositeOperation = ''destination-out''
El azul es la primera forma y el rojo es la segunda forma. Como puede ver, destination-out
elimina la sección de la primera forma. Aquí hay un código de ejemplo:
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()
Aquí está el problema potencial con esto: el segundo fill()
borrará todo lo que hay debajo, incluido el fondo. A veces, solo querrá borrar la primera forma, pero igual querrá ver las capas que se encuentran debajo.
La solución a eso es dibujar esto en un lienzo temporal y luego drawImage
para dibujar el lienzo temporal en su lienzo principal. El código se verá así:
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
Lo haces haciendo un solo camino con dos arcos.
Dibuja un círculo en el sentido de las agujas del reloj, luego dibuja un segundo círculo que va en sentido contrario a las agujas del reloj. No voy a entrar en detalles, pero la forma en que se construyen los caminos sabe tomar esto como una razón para desmarcar esa parte del camino. Para más detalles de lo que está haciendo, puedes leer este artículo wiki .
Lo mismo funcionaría si estuvieras dibujando un rectángulo "enmarcado". Dibuja un cuadro de una manera (en el sentido de las agujas del reloj), luego dibuja el cuadro interno de la otra manera (en sentido contrario a las agujas del reloj) para obtener el efecto.
Aquí está el código para una dona:
var can = document.getElementById(''canvas1'');
var ctx = can.getContext(''2d'');
// Pay attention to my last argument!
//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI*2, false); // outer (filled)
ctx.arc(100,100,55,0,Math.PI*2, true); // inner (unfills it)
ctx.fill();
Ejemplo:
Se puede dibujar solo un "segmento" de él haciendo que la ruta sea más pequeña (es posible que necesite usar beziers en lugar de arco), o usando una región de recorte. Realmente depende de cómo exactamente quieres un "segmento"
Aquí hay un ejemplo: http://jsfiddle.net/Hnw6a/8/
// half doughnut
ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI, false); // outer (filled)
ctx.arc(100,100,55,Math.PI,Math.PI*2, true); // outer (unfills it)
ctx.fill();
Puede hacer una ''vista superior'' (círculo con un centro hueco) al acariciar un arco. Puedes ver un ejemplo de esto aquí: http://phrogz.net/tmp/connections.html
Los círculos (con punta) están dibujados por las líneas 239-245:
ctx.lineWidth = half*0.2; // set a nice fat line width
var r = half*0.65; // calculate the radius
ctx.arc(0,0,r,0,Math.PI*2,false); // create the circle part of the path
// ... some commands for the nib
ctx.stroke(); // actually draw the path
Sí, entiendo cuántos años tiene esta pregunta :)
Aquí están mis dos centavos:
(function(){
var annulus = function(centerX, centerY,
innerRadius, outerRadius,
startAngle, endAngle,
anticlockwise) {
var th1 = startAngle*Math.PI/180;
var th2 = endAngle*Math.PI/180;
var startOfOuterArcX = outerRadius*Math.cos(th2) + centerX;
var startOfOuterArcY = outerRadius*Math.sin(th2) + centerY;
this.beginPath();
this.arc(centerX, centerY, innerRadius, th1, th2, anticlockwise);
this.lineTo(startOfOuterArcX, startOfOuterArcY);
this.arc(centerX, centerY, outerRadius, th2, th1, !anticlockwise);
this.closePath();
}
CanvasRenderingContext2D.prototype.annulus = annulus;
})();
Lo que agregará una función "annulus ()" similar a "arc ()" en el prototipo CanvasRenderingContext2D. Hacer el camino cerrado es útil si desea verificar la inclusión de puntos.
Con esta función, podrías hacer algo como:
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
ctx.annulus(0, 0, 100, 200, 15, 45);
ctx.fill();
O mira esto: https://jsfiddle.net/rj2r0k1z/10/
¡Gracias!