2011-11-06 13 views
19

Come afferma il titolo. È possibile?Come disegnare segmenti di una ciambella con tela HTML5?

Edit: Quando dico ciambella intendo un top, vista 2D

è l'unica opzione per disegnare un segmento di un cerchio, poi disegnare un segmento di un cerchio più piccolo con la stessa origine e raggio minore sopra le righe, con il colore dello sfondo? Sarebbe una schifezza se così :(

risposta

29

lo si fa facendo un unico percorso con due archi.

Si disegna un cerchio in senso orario, quindi si disegna un secondo cerchio in senso antiorario. Non entrerò nei dettagli di questo, ma il modo in cui i percorsi sono costruiti sa di prendere questo come una ragione per sviare quella parte del percorso. Per maggiori dettagli su ciò che fa puoi this wiki article.

Lo stesso funzionerebbe se steste disegnando un rettangolo "incorniciato". Disegna una casella in un modo (in senso orario), quindi disegna la scatola interna nell'altro senso (in senso antiorario) per ottenere l'effetto.

Ecco il codice per una ciambella:

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

Esempio:

http://jsfiddle.net/Hnw6a/

Disegno solo un "segmento" di esso può essere fatto facendo il percorso più piccola (potrebbe essere necessario usa beziers invece di arc), o usando una regione di clipping. Dipende molto da come esattamente si vuole un "segmento"

Ecco un esempio: 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(); 
+0

aha! questo sembra proprio quello di cui ho bisogno, grazie! –

+1

Invece di riempire e svuotare, perché non accarezzare con una larghezza di grasso? – Phrogz

+0

@Phrogz Potresti volere che il bordo e il riempimento siano colori diversi. –

1
+0

domanda chiarito, volevo dire in 2D dispiace. la tua risposta è ancora valida? –

+0

@AndrewBullock si applica "un po '" - puoi usare anche WebGL con 2D che dovrebbe offrire più opzioni per ciò che vuoi disegnare ... per un semplice esempio 2D in WebGL vedi https://developer.mozilla.org/en/WebGL/Adding_2D_content_to_a_WebGL_context – Yahia

3

È possibile effettuare una 'vista ciambella top' (cerchio con centro vuoto) da accarezzare un arco. Si può vedere un esempio di questo qui: http://phrogz.net/tmp/connections.html

enter image description here

I cerchi (con pennino) sono attratti da linee 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 
1

Date le esigenze, quello che dice @SimonSarris soddisfa le problema. Ma diciamo che sei come me e che invece vuoi "cancellare" una parte di una forma che potrebbe essere parzialmente fuori dai limiti della forma che stai cancellando. Se hai questo requisito, la sua soluzione non ti farà desiderare.Sembrerà il "xor" nell'immagine qui sotto.

enter image description here

La soluzione è quella di utilizzare context.globalCompositeOperation = 'destination-out' Il blu è la prima forma e il rosso è la seconda forma. Come puoi vedere, destination-out rimuove la sezione dalla prima forma. Ecco qualche esempio di codice:

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

Ecco il potenziale problema con questo: la seconda fill() sarà chiaro tutto sotto di esso, compreso il fondo. A volte vorrete solo cancellare la prima forma ma vorrete comunque vedere i livelli sottostanti.

La soluzione è disegnare questo su una tela temporanea e quindi drawImage per disegnare la tela temporanea sulla tela principale. Il codice sarà simile a questa:

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 
2

Sì, ho capito quanti anni questa domanda è :)

Qui sono i miei due centesimi:

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

che aggiungerà un anello funzione"() "simile a" arc() "nel prototipo CanvasRenderingContext2D. Creare il percorso chiuso è utile se si desidera verificare l'inclusione dei punti.

Con questa funzione, si potrebbe fare qualcosa di simile:

var canvas = document.getElementById("canvas1"); 
var ctx = canvas.getContext("2d"); 
ctx.annulus(0, 0, 100, 200, 15, 45); 
ctx.fill(); 

Oppure check this out: https://jsfiddle.net/rj2r0k1z/10/

Grazie!

+0

Grazie. Lo userò molto oggi:) – T4NK3R

0

Adattamento/semplificando la risposta di @Simon Sarris di lavorare facilmente con qualsiasi angolazione dà il qui sotto:

Per creare un segmento di arco si disegna un arco esterno (di n radianti) in una direzione e poi un arco opposto (di lo stesso numero di radianti) a un raggio più piccolo e riempire l'area risultante.

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>

Problemi correlati