2011-02-21 12 views
25

Necesito dibujar arcos concéntricos de varios tamaños usando raphael.js. Traté de entender el código detrás de http://raphaeljs.com/polar-clock.html, que es muy similar a lo que quiero, pero, sin comentarios, es bastante difícil de entender.dibujando arcos centrados en raphael js

Idealmente, necesitaría una función que creara una ruta que está a una distancia dada de algún punto central, comienza en un cierto ángulo y termina en algún otro ángulo.

Respuesta

53

Esa respuesta es aceptable, pero no puedo ser animada. Saqué las cosas importantes del reloj polar para ti. Aquí hay un arco rojo que anima a crecer. disfrutar.

// Custom Arc Attribute, position x&y, value portion of total, total value, Radius 
var archtype = Raphael("canvas", 200, 100); 
archtype.customAttributes.arc = function (xloc, yloc, value, total, R) { 
    var alpha = 360/total * value, 
     a = (90 - alpha) * Math.PI/180, 
     x = xloc + R * Math.cos(a), 
     y = yloc - R * Math.sin(a), 
     path; 
    if (total == value) { 
     path = [ 
      ["M", xloc, yloc - R], 
      ["A", R, R, 0, 1, 1, xloc - 0.01, yloc - R] 
     ]; 
    } else { 
     path = [ 
      ["M", xloc, yloc - R], 
      ["A", R, R, 0, +(alpha > 180), 1, x, y] 
     ]; 
    } 
    return { 
     path: path 
    }; 
}; 

//make an arc at 50,50 with a radius of 30 that grows from 0 to 40 of 100 with a bounce 
var my_arc = archtype.path().attr({ 
    "stroke": "#f00", 
    "stroke-width": 14, 
    arc: [50, 50, 0, 100, 30] 
}); 

my_arc.animate({ 
    arc: [50, 50, 40, 100, 30] 
}, 1500, "bounce"); 
+9

Por conveniencia, aquí está esta respuesta como un jsfiddle donde puede ingresar cuánto del círculo dibujar: http://jsfiddle.net/Bzdnm/2/ – user568458

+0

Al igual que con este y el ejemplo del Reloj Polar, ¿Alguien sabe cómo modificar esto para que el punto de inicio no sea siempre a las 12 en punto? Supuse que el valor inicial de 100 haría eso, pero parece que no funciona. – daxiang28

+0

Usa el método de rotación. CÓDIGO {my_arc.rotate (-90, 50, 50) .animate ({ arco: [50, 50, cantidad, 100, 30] }, 1500, "rebote"); } Puedes encontrar más sobre esto en los documentos de Raphael. – genkilabs

7

En realidad encontré la respuesta yo mismo. Primero pensé en algo lujoso que implica curvas de bezier, pero esto simplemente funciona.

-> crea un trazado utilizando sintaxis de ruta SVG, que funciona como es con Raphael

function arc(center, radius, startAngle, endAngle) { 
    angle = startAngle; 
    coords = toCoords(center, radius, angle); 
    path = "M " + coords[0] + " " + coords[1]; 
    while(angle<=endAngle) { 
     coords = toCoords(center, radius, angle); 
     path += " L " + coords[0] + " " + coords[1]; 
     angle += 1; 
    } 
    return path; 
} 

function toCoords(center, radius, angle) { 
    var radians = (angle/180) * Math.PI; 
    var x = center[0] + Math.cos(radians) * radius; 
    var y = center[1] + Math.sin(radians) * radius; 
    return [x, y]; 
} 
+0

pensé que iba a hacer una [versión de php] (http://ideone.com/m4fMU) por si alguien está interesado. –

+0

No necesita aproximar un círculo usted mismo. SVG ya ofrece rutas elípticas – Cuadue

7

Sólo para eliminar algunas conjeturas de la respuesta de user592699, este es el código completo que funciona:

<script src="raphael.js"></script> 
<script> 

    var paper = Raphael(20, 20, 320, 320); 

    function arc(center, radius, startAngle, endAngle) { 
     angle = startAngle; 
     coords = toCoords(center, radius, angle); 
     path = "M " + coords[0] + " " + coords[1]; 
     while(angle<=endAngle) { 
      coords = toCoords(center, radius, angle); 
      path += " L " + coords[0] + " " + coords[1]; 
      angle += 1; 
     } 
     return path; 
    } 

    function toCoords(center, radius, angle) { 
     var radians = (angle/180) * Math.PI; 
     var x = center[0] + Math.cos(radians) * radius; 
     var y = center[1] + Math.sin(radians) * radius; 
     return [x, y]; 
    } 

    paper.path(arc([100, 100], 80, 0, 270)); // draw an arc 
              // centered at (100, 100), 
              // radius 80, starting at degree 0, 
              // beginning at coordinate (80, 0) 
              // which is relative to the center 
              // of the circle, 
              // going clockwise, until 270 degree 

</script> 
+1

http://jsfiddle.net/pajtai/9LKEu/ –

+0

¡Gracias por la limpieza! – plang

10

Así es como lo he hecho. El siguiente código le permite especificar un ángulo de inicio y final, así como un radio interno y externo (útil para hacer los gráficos circulares de moda estilo rosquilla). La solución no se basa en aproximar una curva con segmentos de línea y puede animarse según el ejemplo de reloj mencionado en la pregunta original.

Primero crea tu área de dibujo de Rafael; la siguiente asume un div con id "raphael_paper" en el archivo HTML:

var paper = Raphael("raphael_paper", 800, 800); 

a este objeto Raphael añadimos una costumbre arc atributo, una función que toma el centro de un círculo (x, y coordenadas y), una iniciar ángulo, un ángulo final, un radio interior y un radio exterior:

paper.customAttributes.arc = function (centerX, centerY, startAngle, endAngle, innerR, outerR) { 
    var radians = Math.PI/180, 
     largeArc = +(endAngle - startAngle > 180); 
     // calculate the start and end points for both inner and outer edges of the arc segment 
     // the -90s are about starting the angle measurement from the top get rid of these if this doesn't suit your needs 
     outerX1 = centerX + outerR * Math.cos((startAngle-90) * radians), 
     outerY1 = centerY + outerR * Math.sin((startAngle-90) * radians), 
     outerX2 = centerX + outerR * Math.cos((endAngle-90) * radians), 
     outerY2 = centerY + outerR * Math.sin((endAngle-90) * radians), 
     innerX1 = centerX + innerR * Math.cos((endAngle-90) * radians), 
     innerY1 = centerY + innerR * Math.sin((endAngle-90) * radians), 
     innerX2 = centerX + innerR * Math.cos((startAngle-90) * radians), 
     innerY2 = centerY + innerR * Math.sin((startAngle-90) * radians); 

    // build the path array 
    var path = [ 
     ["M", outerX1, outerY1], //move to the start point 
     ["A", outerR, outerR, 0, largeArc, 1, outerX2, outerY2], //draw the outer edge of the arc 
     ["L", innerX1, innerY1], //draw a line inwards to the start of the inner edge of the arc 
     ["A", innerR, innerR, 0, largeArc, 0, innerX2, innerY2], //draw the inner arc 
     ["z"] //close the path 
    ];     
    return {path: path}; 
}; 

ahora podemos usar esto para dibujar arcos de un espesor especificado, empezando y terminando dondequiera que los queremos por ejemplo.

var redParams = {stroke: "#f00", "stroke-width": 1, fill:"#eee"}, 
    greenParams = {stroke: "#0f0", "stroke-width": 1, fill:"#eee"}, 
    blueParams = {stroke: "#00f", "stroke-width": 1, fill:"#eee"}, 
    cx = 300, cy = 300, innerRadius = 100, outerRadius = 250, 

var red = paper.path().attr(redParams).attr({arc: [cx, cy, 0, 90, innerRadius, outerRadius]}); 
var green = paper.path().attr(greenParams).attr({arc: [cx, cy, 270, 320, innerRadius, outerRadius]}); 
var blue = paper.path().attr(blueParams).attr({arc: [cx, cy, 95, 220, innerRadius, outerRadius]}); 

Esto debería producir tres segmentos de arco gris con bordes de 1px rojo, azul y verde.

+0

¡Estaba tratando de aumentar las cartas de donas en Rafael y esto era exactamente lo que necesitaba! –

1

También puede hacerlo sin tener que usar bucles. Lo siguiente lo logra y también trabaja con ángulos negativos.

Pase en un objeto de Raphael como r. Los ángulos comienzan con 0 grados, que es la parte superior del círculo en lugar del derecho, como se mencionó en algunas otras soluciones.

 function drawArc(r, centerX, centerY, radius, startAngle, endAngle) { 
      var startX = centerX+radius*Math.cos((90-startAngle)*Math.PI/180); 
      var startY = centerY-radius*Math.sin((90-startAngle)*Math.PI/180); 
      var endX = centerX+radius*Math.cos((90-endAngle)*Math.PI/180); 
      var endY = centerY-radius*Math.sin((90-endAngle)*Math.PI/180); 
      var flg1 = 0; 

      if (startAngle>endAngle) 
       flg1 = 1; 
      else if (startAngle<180 && endAngle<180) 
       flg1 = 0; 
      else if (startAngle>180 && endAngle>180) 
       flg1 = 0; 
      else if (startAngle<180 && endAngle>180) 
       flg1 = 0; // edited for bugfix here, previously this was 1 
      else if (startAngle>180 && endAngle<180) 
       flg1 = 1; 

      return r.path([['M',startX, startY],['A',radius,radius,0,flg1,1,endX,endY]]); 
     }; 
2

Para aquellos que quieren que el arco se pueden hacer con trayectoria cerrada y no se derrame cerebral, he ampliado genkilabs responden a hacer una solución. En los casos en que necesite dar un golpe externo a su arco, esto podría ayudar.

// Custom Arc Attribute, position x&y, value portion of total, total value, Radius, width 
var archtype = Raphael("canvas", 200, 100); 
archtype.customAttributes.arc = function (xloc, yloc, value, total, R, width) { 
    if(!width) width = R * 0.4; 
    var alpha = 360/total * value, 
     a = (90 - alpha) * Math.PI/180, 
     w = width/2, 
     r1 = R + w, 
     r2 = R - w, 
     x1 = xloc + r1 * Math.cos(a), 
     y1 = yloc - r1 * Math.sin(a), 
     x2 = xloc + r2 * Math.cos(a), 
     y2 = yloc - r2 * Math.sin(a), 
     path; 
    if (total == value) { 
     path = [ 
      ["M", xloc, yloc - r1], 
      ["A", r1, r1, 0, 1, 1, xloc - 0.01, yloc - r1], 
      ["Z"], 
      ["M", xloc - 0.01, yloc - r2], 
      ["A", r2, r2, 0, 1, 0, xloc, yloc - r2], 
      ["Z"] 
     ]; 
    } else { 
     path = [ 
      ["M", xloc, yloc - r1], 
      ["A", r1, r1, 0, +(alpha > 180), 1, x1, y1], 
      ["L", x2, y2], 
      ["A", r2, r2, 0, +(alpha > 180), 0, xloc, yloc - r2], 
      ["L", xloc, yloc - r1], 
      ["Z"] 
     ]; 
    } 
    return { 
     path: path 
    }; 
}; 

//make an arc at 50,50 with a radius of 30 that grows from 0 to 40 of 100 with a bounce 
var my_arc = archtype.path().attr({ 
    "fill": "#00f", 
    "stroke": "#f00", 
    "stroke-width": 5, 
    arc: [50, 50, 0, 100, 30] 
}); 

my_arc.animate({ 
    arc: [50, 50, 40, 100, 30] 
}, 1500, "bounce"); 

JSFiddle

1

He adaptado genkilabs respuesta para que incluya capacidades de rotación y de inversión.Además, la cantidad del anillo que se llena se cambió a un porcentaje de un solo número. (La inversión se adaptó de this post). Espero que sea útil!

paper.customAttributes.arc = function (xloc, yloc, percent, rad, rot, invert) { 
    var alpha = 3.6 * percent, 
    a = (90 - alpha) * Math.PI/180, 
    x = xloc + rad * Math.cos(a), 
    y = yloc - rad * Math.sin(a), 
    path; 

    if (invert) { 
     x = xloc - rad * Math.cos(a); 
    } 

    if (percent >= 100) { 
     path = [ 
      ["M", xloc, yloc - rad], 
      ["A", rad, rad, 0, 1, 1, xloc - 0.01, yloc - rad] 
     ]; 
    } else { 
     path = [ 
      ["M", xloc, yloc - rad], 
      ["A", rad, rad, 0, +(alpha > 180), +(!invert), x, y] 
     ]; 
     } 
    return { 
     path: path, 
     transform: "r"+rot+","+xloc+","+yloc, 
    }; 
}; 
Cuestiones relacionadas