2012-10-11 32 views
11

Estoy tratando de trazar una línea que comienza como una línea delgada y luego se ensancha hasta el final. Necesito dibujar curvas semilisas (compuesta de varias líneas rectas) y tengo problemas para encontrar una manera de resolver esta tarea.Dibujar líneas con un ancho de línea que varía continuamente en el lienzo HTML

Este violín muestra mi problema:

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

Cuando se llama accidente cerebrovascular(), el conjunto actualmente anchoLinea se utiliza para acariciar toda la línea. Mi primer pensamiento fue dibujar cada línea individualmente, pero por supuesto, esto deja huecos notables en la línea en las esquinas.

¿Cuál es mi mejor opción aquí? ¿Debo recurrir a dibujar polígonos (trapezoides) para obtener las esquinas correctamente?

¿Hay alguna manera más fácil?

(Edit: Tenga en cuenta que no estoy tratando de llamar la realidad elipses o cualquier otro tipo de formas básicas, estoy tratando de trazar funciones matemáticas, usando el grosor de línea para representar la velocidad)

+4

Su mejor opción es probablemente va a ser el uso de '' bezierCurveTo' o quadraticCurveTo' y 'fill' en lugar de' stroke', complicará las matemáticas, pero es probable que sea la única forma de obtener el resultado deseado. Pude lograr un efecto similar pero diferente dibujando múltiples elipses y desplazándolos/reduciéndolos en cada paso: http://jsfiddle.net/Shmiddty/ZvuQG/3/ – Shmiddty

Respuesta

4

Para los interesados, he encontrado dos soluciones para mi problema.

La primera idea fue dibujar cada punto como una esquina, utilizando un lienzo para dibujar un ángulo ordenado. Una demostración se puede ver en:

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

El segundo y mucho más bonita solución, según lo sugerido por Shmiddty, es utilizar bezier curvas. Esto resultó ser una gran solución:

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

Adición de remates de las líneas redondeadas y una cuadrática curva hace que todo parezca mucho más ordenado.

Véase here por ejemplo.

+0

Esta es una buena solución, y debería haber funcionado, de acuerdo a los parámetros que especifiqué en mi pregunta. Sin embargo, no dije que quería controlar la opacidad de la línea, en cuyo caso las esquinas redondeadas no se ven tan bien: http://jsfiddle.net/X2Vm7/ – Valdemar

0

Otra forma en que puede resolver esto es considerar que cada uno de los puntos de la trama es un círculo de un radio determinado por la velocidad.

trazar caminos que unan los bordes de perfil de estos círculos (rectos o curvos, a su elección), primero sobre la parte superior, alrededor del último y de nuevo al inicio en la parte inferior. Luego llena el camino al final.

Esto debería proporcionarle una línea suave que se expande y contrae a medida que se aproxima a los 'círculos' del punto de trazado.

Cuestiones relacionadas