Hola qué tal:
Estuve trasteando con SVG hace poco y se me ocurrió hacer una libreria grafica sencilla para poder crear graficos con javascript y modificarlos dinamicamente (con DOM).
Lo primero que hice fue crear las funciones para crear rectas
Código PHP:
<g id="contenedor"></g>
Código PHP:
var contend= document.getElementById('contenedor');
function recta(x1,y1,x2,y2,color) {
this.x1=x1; this.y1=y1; this.x2=x2; this.y2=y2; this.color=color;
var r=document.createElement("line");
r.setAttribute("x1", x1); r.setAttribute("y1", y1);
r.setAttribute("x2", x2); r.setAttribute("y2", y2);
r.setAttribute("style", "stroke:"+color);
this.setId=function(cual) {
this.setAttribute("id",cual);
}
return contend.appendChild(r);
}
alargarlas hasta una longitud bastante practica
Código PHP:
function alargar(idr) {
x1=parseInt(getAtr(idr,"x1")); x2=parseInt(getAtr(idr,"x2")); y1=parseInt(getAtr(idr,"y1")); y2=parseInt(getAtr(idr,"y2"));
avanzaX=x2-x1; avanzaY=y2-y1;
n=1000;
recta(x1-avanzaX*n, y1-avanzaY*n, x2+avanzaX*n, y2+avanzaY*n);
}
y crear circulos:
Código PHP:
function circulo(cx,cy,r,color,fill,op) {
var c=document.createElement("circle");
c.setAttribute("cx", cx);
c.setAttribute("cy", cy);
c.setAttribute("r", r);
c.setAttribute("style", "stroke: "+(color?color:"black")+"; fill:"+(fill?fill:"none")+"; opacity: "+(op==null?1:op));
return contend.appendChild(c);
}
Y por ultimo marcar puntos con un aspa:
Código PHP:
function pto(x, y, color) {
var point1= document.createElement('line'); var point2= document.createElement('line');
point1.setAttribute('x1', x-5); point2.setAttribute('x1', x-5);
point1.setAttribute('y1', y-5); point2.setAttribute('y1', y+5);
point1.setAttribute('x2', x+5); point2.setAttribute('x2', x+5);
point1.setAttribute('y2', y+5); point2.setAttribute('y2', y-5);
point1.setAttribute("stroke-width","1"); point2.setAttribute("stroke-width","1");
point1.setAttribute("style", "stroke:"+color); point2.setAttribute("style", "stroke:"+color);
contend.appendChild(point1); contend.appendChild(point2);
return [x,y];
}
Visto esto parecia que podia crear cualquier forma SVG con javascript. Ahora viene lo mas complicado.
Me supuse que podia obtener la intersección de dos rectas que tenia dibujadas, y marcarlas por un punto. Eso no fue complicado, es un poquito de matematicas. Extrayendo la ecuacion de la recta que pasa por dos puntos de la forma y=Mx+N por cada recta, y luego tomando las y ó las x iguales se resuelve un sistema de dos incognitas y dos ecuaciones. El punto sale perfecto. Por cierto, defini cuatro funciones tontas para auxiliarme:
Código PHP:
function getAtr(id,atr) { return document.getElementById(id).getAttribute(atr); }
function setAtr(id,atr,val) { document.getElementById(id).setAttribute(atr,val); }
function p(x,n) { return Math.pow(x,n) }
function cuad(x) { return p(x,2); }
Código PHP:
function i_r_r(id1,id2) {
var x,y,x1,x2,y1,y2,X1,X2,Y1,Y2;
x1=parseInt(getAtr(id1,"x1")); x2=parseInt(getAtr(id1,"x2")); y1=parseInt(getAtr(id1,"y1")); y2=parseInt(getAtr(id1,"y2"));
X1=parseInt(getAtr(id2,"x1")); X2=parseInt(getAtr(id2,"x2")); Y1=parseInt(getAtr(id2,"y1")); Y2=parseInt(getAtr(id2,"y2"));
x = (Y1*X2 - Y2*X1)/((X2-X1)*((y2-y1)/(x2-x1) - (Y2-Y1)/(X2-X1))) - (y1*x2 - y2*x1)/((x2-x1)*((y2-y1)/(x2-x1) - (Y2-Y1)/(X2-X1)));
y = ((y2-y1)/(x2-x1))*x + (y1*x2 - y2*x1)/(x2-x1);
return [x,y];
}
El punto de intersección se marca perfecto. Podemos hacer:
Código PHP:
rec=recta(200,300,800,500, "orange");
rec2=recta(500,200,400,600, "blue");
rec.setId("recta1");
rec2.setId("recta2");
elPto=i_r_r("recta1","recta2");
pto(elPto[0],elPto[1],"red");
Es sencillo. Creamos una recta (rec) y otra (rec2). Necesitaremos ponerles id's para pasarselo a la funcion i_r_r, asi que se los ponemos. elPto es una matriz con el punto de interseccion (elPto[0] es el X y elPto[1] es el Y). Luego dibujamos el punto.
Hasta ahí todo bien...
Ahora quería hacer lo mismo un poco mas complicado, intersección de recta y circunferencia.
Según las matematicas (hasta donde yo sé):
Código:
RECTA:
((y2-y1)/(x2-x1))*x + (y1*x2 - y2*x1)/(x2-x1) = y
CIRCUNFERENCIA:
(x-X1)²+(y-Y1)²=R²
x²+y²+Dx+Ey+F=0
siendo D=-2*X1; E=-2*Y1; F=X1²+Y1²-R²
y como las y=Y y x=X sustituimos una en otra...
x²+(((y2-y1)/(x2-x1))*x + (y1*x2 - y2*x1)/(x2-x1))²+Dx+E*(((y2-y1)/(x2-x1))*x + (y1*x2 - y2*x1)/(x2-x1))+F=0
ahora solo tenemos que resolver esa ecuacion, sacando unas x que satisfagan la ec:
M=(y2-y1)/(x2-x1);
N=(y1*x2 - y2*x1)/(x2-x1);
x²+(M*x + N)²+Dx+E*(M*x + N)+F=0
x²+M²*x²+2*M*x*N+N²+Dx+E*M*x+E*N+F=0
(M²+1)*x² + (2*M*N+D+E*M)*x + (N²+E*N+F) = 0
ecuacion de 2º grado, 2 soluciones:
A=(M²+1);
B=(2*M*N+D+E*M);
C=(N²+E*N+F);
x=(-B+-sqrt(B²-4AC))/2A:
x_1=(-B+sqrt(B²-4AC))/2A; x_2=(-B-sqrt(B²-4AC))/2A;
y las y que correspondan ser. A x_1 le corresponde una y_1 y a x_2 le corresponde y_2 de
((y2-y1)/(x2-x1))*x + (y1*x2 - y2*x1)/(x2-x1) = y
Así que en teoría es sencillo. Bueno pues en mi funcion (i_r_c) no funciona, da dos puntos bastante alejados del circulo (eso sí, pertenecen a la recta).
Código PHP:
function i_r_c(idr,idc) {
var x1,x2,y1,y2,X1,Y1,R, A,B,C,D,E,F,M,N, x_1, x_2, y_1, y_2;
x1=parseInt(getAtr(idr,"x1")); x2=parseInt(getAtr(idr,"x2")); y1=parseInt(getAtr(idr,"y1")); y2=parseInt(getAtr(idr,"y2"));
X1=parseInt(getAtr(idc,"cx")); Y1=parseInt(getAtr(idc,"cy")); R=parseInt(getAtr(idc,"r"));
//C
D=-2*X1;
E=-2*Y1;
F=Math.sqrt( cuad(X1)+cuad(Y1)-cuad(R) );
//R
M=(y2-y1)/(x2-x1); //if(x2-x1==0) M=0;
N=(y1*x2 - y2*x1)/(x2-x1); //if(x2-x1==0) N=0;
// ec grad 2
A=1+cuad(M);
B=2*M*N+E*M+D;
C=cuad(N)+E*N+F;
// resolucion:
x_1= (-B+Math.sqrt(cuad(B)-4*A*C))/(2*A);
y_1=M*x_1 + N;
pto( x_1, y_1, "red");
x_2= (-B-Math.sqrt(cuad(B)-4*A*C))/(2*A);
y_2=M*x_2 + N;
pto( x_2, y_2, "red");
}
No es tan complicada la funcion, pero he utilizado muchas letras, se hace mucho mas legible.
Pero el problema es que no da donde tiene que dar, da mucho mas lejos, haga lo que haga.
ejemplo:
Código PHP:
circ=circulo(300,300,150);
pto(300,300,"blue");
rec=recta(300,300,200,105, "orange");
circ.setAttribute("id","miCirc");
rec.setAttribute("id","miRec");
alargar("miRec");
var choque=i_r_c("miRec","miCirc");
Espero que hayan entendido todo, alguna duda me comentan, y si encuentran la solución, algún método alternativo, o algo que me pueda interesar ya saben.
Un saludo y gracias.