2012-10-11 17 views
11

Próbuję narysować linię, która zaczyna się cienką linią, a następnie rozszerza się do końca. Muszę narysować pół-gładkie krzywe (kompozyt z kilku prostych linii) i mam problemy ze znalezieniem sposobu rozwiązania tego zadania.Rysowanie linii o ciągle zmieniającej się szerokości linii na kanwie HTML

Ten skrzypce pokazuje mój problem:

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

Po wywołaniu udaru(), aktualnie ustawiony linewidth służy do udaru całej linii. Moją pierwszą myślą było narysowanie każdej linii osobno, ale oczywiście pozostawia zauważalne luki w linii w rogach.

Jaka jest moja najlepsza opcja? Czy powinienem uciekać się do rysowania wielokątów (trapezów), aby uzyskać rogi w prawo?

Czy jest łatwiejszy sposób?

(Edit: Zauważ, że ja nie próbuję faktycznie rysowania elips lub innych podstawowych kształtów; Próbuję wykreślić funkcje matematyczne, używając grubość linii do reprezentowania prędkość)

+4

Najlepszym rozwiązaniem jest zapewne będzie za pomocą 'bezierCurveTo' lub' 'fill' quadraticCurveTo' i zamiast' stroke', to skomplikuje matematykę, ale jest to prawdopodobnie jedyny sposób uzyskania pożądanego rezultatu. Udało mi się osiągnąć podobny, ale inny efekt, rysując wiele elips i przesuwając/pomniejszając je na każdym kroku: http://jsfiddle.net/Shmiddty/ZvuQG/3/ – Shmiddty

Odpowiedz

4

Dla zainteresowanych, znalazłem dwa rozwiązania mojego problemu.

Pierwszym pomysłem było narysowanie każdego punktu jako narożnika, za pomocą kanwy, aby narysować zgrabny kąt. Demo można zobaczyć pod adresem:

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

Drugim i dużo ładniejsza rozwiązanie, zgodnie z sugestią Shmiddty, jest użycie krzywych Beziera. To okazało się być doskonałym rozwiązaniem:

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

Dodawanie zaokrąglone czapki liniowe i kwadratowe krzywa sprawia, że ​​całość wygląda dużo porządniej.

Patrz na przykład: here.

+0

To jest dobre rozwiązanie i powinno działać, zgodnie do parametrów określonych w moim pytaniu. Nie stwierdziłem jednak, że chcę kontrolować nieprzezroczystość linii, w którym to przypadku zaokrąglone rogi nie wyglądają tak dobrze: http://jsfiddle.net/X2Vm7/ – Valdemar

0

Innym sposobem rozwiązania tego problemu jest rozważenie każdego z punktów wykresu jako okręgu o promieniu określonym przez prędkość.

ścieżki wydruku łączące krawędzie profilu tych okręgów (proste lub zakrzywione, do wyboru), najpierw nad górą, zaokrąglając ostatnią i z powrotem do początku na spodzie. Następnie wypełnij ścieżkę na końcu.

Powinno to zapewnić gładką linię rozszerzającą się i kurczącą, gdy zbliża się do ciebie punkt "koła".

Powiązane problemy