2012-10-11 11 views
11

Sto provando a disegnare una linea che inizia come una linea sottile e quindi si allarga a mano fino alla fine. Devo disegnare curve semi-levigate (composte da più linee diritte) e ho difficoltà a trovare un modo per risolvere questo compito.Disegno di linee con larghezza di riga variabile in continuo su tela HTML

Questo violino mostra il mio problema:

http://jsfiddle.net/ZvuQG/1/

Quando si chiama ictus(), attualmente impostato lineWidth viene utilizzato per accarezzare l'intera linea. Il mio primo pensiero è stato quello di disegnare ogni singola linea individualmente, ma ovviamente questo lascia evidenti vuoti nella linea agli angoli.

Qual è la mia migliore opzione qui? Dovrei ricorrere a disegnare poligoni (trapezi) per ottenere gli angoli giusti?

C'è un modo più semplice?

(Edit: Si noti che non sto cercando di disegnare ellissi in realtà o qualsiasi altre forme di base; sto cercando di tracciare funzioni matematiche, utilizzando spessore della linea per rappresentare la velocità)

+4

La migliore opzione è destinata probabilmente ad essere utilizzando 'bezierCurveTo' o' 'quadraticCurveTo' e fill' invece di' stroke', complicherà la matematica, ma è probabilmente l'unico modo per ottenere il risultato desiderato. Sono stato in grado di ottenere un effetto simile ma diverso disegnando più ellissi e sfalsandole/riducendole ogni passaggio: http://jsfiddle.net/Shmiddty/ZvuQG/3/ – Shmiddty

risposta

4

Per chi fosse interessato, ho trovato due soluzioni al mio problema.

La prima idea era di disegnare ogni punto come un angolo, usando la tela per disegnare un angolo pulito. Una demo può essere visto:

http://jsfiddle.net/7BkyK/2/

var ctx = document.getElementById('canvas1').getContext('2d'); 
var points = [null, null, null]; 

for(var i=0; i<24; i++) 
{ 
    var width = 0.5 + i/2; 

    var m = 200; 

    var x = Math.cos(i/4) * 180; 
    var y = Math.sin(i/4) * 140; 

    points[0] = points[1]; 
    points[1] = points[2]; 
    points[2] = { X:x, Y:y}; 

    if(points[0] == null) 
     continue; 

    var px0 = (points[0].X + points[1].X)/2; 
    var py0 = (points[0].Y + points[1].Y)/2; 

    var px1 = (points[1].X + points[2].X)/2; 
    var py1 = (points[1].Y + points[2].Y)/2; 

    ctx.beginPath(); 
    ctx.lineWidth = width; 
    ctx.strokeStyle = "rgba(0,0,0,0.5)"; 
    ctx.moveTo(m+px0,m+py0); 
    ctx.lineTo(m+points[1].X,m+points[1].Y); 
    ctx.lineTo(m+px1,m+py1); 
    ctx.stroke(); 
} 
​ 

La seconda e molto più bella soluzione, come suggerito da Shmiddty, è quello di utilizzare bezier curve. Questo si è rivelato essere una grande soluzione:

http://jsfiddle.net/Ssrv9/1/

// 1. 
// Varying line width, stroking each piece of line separately 
var ctx = document.getElementById('canvas1').getContext('2d'); 
var points = [null, null, null, null]; 

for(var i=-1; i<25; i = i +1) 
{ 
    var width = 0.5 + i/2; 

    var m = 200; 


    var x = Math.cos(i/4) * 180; 
    var y = Math.sin(i/4) * 140; 

    points[0] = points[1]; 
    points[1] = points[2]; 
    points[2] = { X:x, Y:y}; 

    if(points[0] == null) 
     continue; 


    var p0 = points[0]; 
    var p1 = points[1]; 
    var p2 = points[2]; 

    var x0 = (p0.X + p1.X)/2; 
    var y0 = (p0.Y + p1.Y)/2; 

    var x1 = (p1.X + p2.X)/2; 
    var y1 = (p1.Y + p2.Y)/2; 

    ctx.beginPath(); 
    ctx.lineWidth = width; 
    ctx.strokeStyle = "black"; 

    ctx.moveTo(m+x0, m+y0); 
    ctx.quadraticCurveTo(m+p1.X, m+p1.Y, m+x1, m+y1); 
    ctx.stroke(); 
} 

2

Aggiunta di tappi linea arrotondata e un quadratica la curva rende il tutto molto più ordinato.

Vedere here ad esempio.

+0

Questa è una buona soluzione, e avrebbe dovuto funzionare, secondo ai parametri che ho specificato nella mia domanda. Tuttavia, non ho dichiarato che volevo controllare l'opacità della linea, nel qual caso gli angoli arrotondati non sembrano così grandi: http://jsfiddle.net/X2Vm7/ – Valdemar

0

Un altro modo per risolvere questo è considerare ognuno dei punti di trama come un cerchio di un raggio determinato dalla velocità.

percorsi di tracciamento che si uniscono ai bordi del profilo di questi cerchi (diritti o curvi, a scelta), prima sopra la parte superiore, intorno all'ultima e di nuovo all'inizio sulla parte inferiore. Quindi riempire il percorso alla fine.

Questo dovrebbe darvi una linea morbida che si espande e si contrae quando ci si avvicina al punto del diagramma 'cerchi'.