Saltar al contenido

Cómo calcular la ruta SVG para un arco (de un círculo)

Te recomendamos que pruebes esta resolución en un ambiente controlado antes de enviarlo a producción, un saludo.

Solución:

Ampliando la gran respuesta de @wdebeaum, aquí hay un método para generar una ruta arqueada:

function polarToCartesian(centerX, centerY, radius, angleInDegrees) 
  var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

  return 
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  ;


function describeArc(x, y, radius, startAngle, endAngle)

    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);

    var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
    ].join(" ");

    return d;       

usar

document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 180));

y en tu html


Demo en vivo

Quieres usar la elíptica Acomando rc. Desafortunadamente para usted, esto requiere que especifique las coordenadas cartesianas (x, y) de los puntos inicial y final en lugar de las coordenadas polares (radio, ángulo) que tiene, por lo que debe hacer algunos cálculos. Aquí hay una función de JavaScript que debería funcionar (aunque no la he probado), y que espero que se explique por sí misma:

function polarToCartesian(centerX, centerY, radius, angleInDegrees) 
  var angleInRadians = angleInDegrees * Math.PI / 180.0;
  var x = centerX + radius * Math.cos(angleInRadians);
  var y = centerY + radius * Math.sin(angleInRadians);
  return [x,y];

Qué ángulos corresponden a qué posiciones del reloj dependerán del sistema de coordenadas; simplemente intercambie y/o niegue los términos sin/cos según sea necesario.

El comando arc tiene estos parámetros:

rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y

Para tu primer ejemplo:

rx=ry=25 y x-axis-rotation=0, ya que quieres un círculo y no una elipse. Puede calcular tanto las coordenadas iniciales (que debe Move to) y coordenadas finales (x, y) usando la función anterior, produciendo (200, 175) y aproximadamente (182.322, 217.678), respectivamente. Dadas estas restricciones hasta el momento, en realidad hay cuatro arcos que se pueden dibujar, por lo que las dos banderas seleccionan uno de ellos. Supongo que probablemente quieras dibujar un pequeño arco (es decir, large-arc-flag=0), en la dirección del ángulo decreciente (es decir sweep-flag=0). En conjunto, la ruta SVG es:

M 200 175 A 25 25 0 0 0 182.322 217.678

Para el segundo ejemplo (suponiendo que te refieres a ir en la misma dirección y, por lo tanto, a un arco grande), la ruta SVG es:

M 200 175 A 25 25 0 1 0 217.678 217.678

Una vez más, no he probado estos.

(editar 2016-06-01) Si, como @clocksmith, se pregunta por qué eligieron esta API, eche un vistazo a las notas de implementación. Describen dos posibles parametrizaciones de arco, "parametrización de punto final" (la que eligieron) y "parametrización central" (que es como lo que usa la pregunta). En la descripción de "parametrización de punto final" dicen:

Una de las ventajas de la parametrización de punto final es que permite una sintaxis de ruta consistente en la que todos los comandos de ruta terminan en las coordenadas del nuevo "punto actual".

Básicamente, es un efecto secundario de que los arcos se consideren parte de una ruta más grande en lugar de su propio objeto separado. Supongo que si su renderizador SVG está incompleto, podría omitir cualquier componente de ruta que no sepa cómo renderizar, siempre que sepa cuántos argumentos toman. O tal vez permita la representación paralela de diferentes partes de una ruta con muchos componentes. O tal vez lo hicieron para asegurarse de que no se acumularan errores de redondeo a lo largo de una ruta compleja.

Las notas de implementación también son útiles para la pregunta original, ya que tienen más pseudocódigo matemático para convertir entre las dos parametrizaciones (que no me di cuenta cuando escribí esta respuesta por primera vez).

Modifiqué ligeramente la respuesta de opsb e hice un relleno de soporte para el sector del círculo. http://codepen.io/anon/pen/AkoGx

JS

function polarToCartesian(centerX, centerY, radius, angleInDegrees) 
  var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

  return 
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  ;


function describeArc(x, y, radius, startAngle, endAngle)

    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);

    var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";

    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, arcSweep, 0, end.x, end.y,
        "L", x,y,
        "L", start.x, start.y
    ].join(" ");

    return d;       


document.getElementById("arc1").setAttribute("d", describeArc(200, 400, 100, 0, 220));

HTML


  

Si tienes algún recelo o disposición de ascender nuestro ensayo te proponemos añadir una anotación y con gusto lo ojearemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *