Yin y Yang con path

facebook-svg gplus-svg twitter-svg

El yin y yang son dos conceptos del taoísmo, cuyo significado y origen es en este momento irrelevante. Sin embargo nos interesa saber como dibujar una representación gráfica de estos. Lo que queremos conseguir es algo así:

A continuación dibujaremos esta imagen utilizando el elemento <path> y el comando  arco elípticoelliptical Arc ) A o a como instrucción de control ( commands ). También utilizaremos el elemento <circle>.

Un poco de JavaScript

Para crear dinámicamente un nuevo elemento en SVG utilizamos el método createElementNS() donde NS viene de Namespaces ( espacio de nombres ). No olvidemos que SVG define gráficos en formato XML.
Para establecer, determinar o modificar el valor de un atributo podemos utilizar el método setAttributeNS() o setAttribute().
Los elementos creados dinámicamente y dotados con atributos ( o no ) pueden ser insertados en el documento utilizando uno de los métodos appendChild() o insertBefore(), utilizando el nodo padre ( parent node ) como argumento. Veamos un ejemplo.

Empezamos dibujando un círculo blanco ( fill="#fff" ) con un borde fino negro ( stroke="#000" ).
Definimos algunas variables necesarias: las coordenadas cx e cy del centro y el radio R del yin y yang:

var cx = 125, cy = 100;
var R = 80;

Utilizando el método createElementNS, creamos un nuevo elemento <circle> y lo almacenamos dentro de una variable ( var circulo ).

var circulo = document.createElementNS("http://www.w3.org/2000/svg","circle");

Utilizamos el método setAttributeNS para establecer los atributos necesarios del nuevo elemento: ( cx, cy, r, fill y stroke).

circulo.setAttributeNS(null,"cx", cx);
circulo.setAttributeNS(null,"cy", cy);
etc . . .

Al final adjuntamos el elemento circulo al contenedor SVG.

var contenedor = document.getElementById("contenedor");
contenedor.appendChild(circulo);



No te olvides: siempre que sea posible, pon el JavaScript dentro del <body>, justo antes de su cierre: los estilos arriba, los scripts al fondo.


var cx = 125, cy = 100;
var R = 80;
// crea un circulo blanco con borde negro
var circulo = document.createElementNS("http:\/\/www.w3.org/2000/svg","circle");   
            
circulo.setAttributeNS(null,"cx", cx);
circulo.setAttributeNS(null,"cy", cy);
circulo.setAttributeNS(null,"r", R);
circulo.setAttributeNS(null,"fill", "#fff");
circulo.setAttributeNS(null,"stroke","#000");

var contenedor = document.getElementById("contenedor");
contenedor.appendChild(circulo);

El Yin es la parte negra del yin y yang, y para dibujarla necesitamos juntar tres semicírculos ( arcos elípticos ) en un trazado ( <path> ).
Exactamente como en el caso del <circle>, creamos un nuevo elemento <path> utilizando el método createElementNS(), y después, utilizando setAttributeNS establecemos el único atributo necesario: d, el atributo que define el trazado a dibujar.

Calcular el parámetro d para Yin

1. Empezamos moviendo el lápiz en el punto cx,cy ( el centro del círculo ). Para esto el atributo d de <path> empieza con el comando M ( moveto ) seguido del valor de las variables cx y cy.

var dYin = "M"+cx+", "+cy+" A"+R/2+ ","+R/2 +"0 0,1"+ (cx+R) +","+cy

2. A continuación  dibujamos hacia la derecha y en el sentido del reloj un semicírculo cuyo diámetro es igual al radio de yin y yang, y por lo tanto su radio r = R/2. El comando A comunica al <path> que el trazado que queremos dibujar es un arco eliptico.

var dYin = "M"+cx+", "+cy+" A"+R/2 + ","+ R/2 +"0 0,1"+ (cx+R) +","+cy

No queremos girar la elipse ( x-axis-rotation = 0 ),

var dYin = "M"+cx+", "+cy+" A"+R/2+ ","+R/2 +"0 0,1"+ (cx+R) +","+cy

y ya que se trata de un semicírculo el valor del parámetro large-arc-flag puede ser tanto 0 como 1.

var dYin = "M"+cx+", "+cy+" A"+R/2+ ","+R/2 +"0 0,1"+ (cx+R) +","+cy

Dibujamos el arco en el sentido del reloj ( sweep-flag = 1 ).

var dYin = "M"+cx+", "+cy+" A"+R/2+ ","+R/2 +"0 0,1"+ (cx+R) +","+cy

El arco acaba en el punto de coordinadas cx + R, cy.

var dYin = "M"+cx+", "+cy+" A"+R/2+ ","+R/2 +"0 0,1"+ (cx+R) +","+cy

3. Desde este punto ( cx + R, cy ) dibujamos otro arco de círculo, también en el sentido del reloj ( sweep-flag = 1 ) , pero hacia la izquierda y abajo. El radio de este segundo arco es R. El arco acaba en el punto de coordinadas cx - R, cy.

var dYin =
"M" + cx + ", " + cy+
" A"+ R/2 +","+ R/2 +" 0 0,1 "+ (cx+R) +","+cy+
" A"+ R +","+ R +" 0 0,1 -"+ (cx-R) +","+cy;

4. Desde el punto donde se acabó el arco anterior ( cx - R, cy ) dibujamos otro arco de circulo cuyo diámetro es igual al radio de yin y yang ( r = R/2 ). Esta vez dibujamos hacia abajo y la derecha, o sea en el sentido contrario del reloj ( sweep-flag = 0 ). El arco acaba en el centro de la imagen.

var dYin ="M" + cx + ", " + cy+
" A"+ R/2 +","+ R/2 +" 0 0,1 "+ (cx+R) +","+cy+
" A"+ R +","+ R +" 0 0,1 "+ (cx-R) +","+cy+
" A"+ R/2 +","+ R/2 +" 0 0,0 "+cx+","+cy

En el JavaScript creamos con createElementNS() un nuevo elemento <path>. Utilizando el metodo setAttributeNS() atribuimos al nuevo elemento <path> el atributo d ( el valor del atributo d = dYin ).
Al final insertamos el nuevo elemento <path> en el documento utilizando el método appendChild().

Ya tenemos el yin.

Finalmente, creamos también los dos círculos rojos.




var cx = 125, cy = 100;
var R = 80;
var r = R/10; // el radio de los circulos rojos

var dYin = "M" + cx + ", " + cy+
            " A"+ R/2 +","+ R/2 +" 0 0,1 "+ (cx+R) +","+cy+
            " A"+ R +","+ R +" 0 0,1 "+ (cx-R) +","+cy+
            " A"+ R/2 +","+ R/2 +" 0 0,0 "+cx+","+cy;
            
var contenedorSVG = document.getElementById("contenedorSVG"); 
// declara el espacio de nombre
var svgNS = "http:\/\/www.w3.org/2000/svg"

// crea un circulo blanco con borde negro
var circulo=document.createElementNS(svgNS,"circle");   
            
circulo.setAttributeNS(null,"cx", cx);
circulo.setAttributeNS(null,"cy", cy);
circulo.setAttributeNS(null,"r", R);
circulo.setAttributeNS(null,"fill", "#fff");
circulo.setAttributeNS(null,"stroke","#000");
contenedorSVG.appendChild(circulo);
      
// crea el yin               
var Yin=document.createElementNS(svgNS,"path");   
Yin.setAttributeNS(null,"d", dYin);


contenedorSVG.appendChild(Yin);

// crea un circulo rojo encima de yin
var circleYin = document.createElementNS(svgNS,"circle");
circleYin.setAttributeNS(null,"cx", cx-R/2);
circleYin.setAttributeNS(null,"cy", cy);
circleYin.setAttributeNS(null,"r", r);
circleYin.setAttributeNS(null,"fill", "#f00");

contenedorSVG.appendChild(circleYin);

// crea un circulo rojo encima de yang
var circleYang = document.createElementNS(svgNS,"circle");
circleYang.setAttributeNS(null,"cx", cx+R/2);
circleYang.setAttributeNS(null,"cy", cy);
circleYang.setAttributeNS(null,"r", r);
circleYang.setAttributeNS(null,"fill", "#f00");

contenedorSVG.appendChild(circleYang);