Mathscript

Premetto che è solo da qualche mese che utilizzo il linguaggio Javascript, anche se è dal 1983 che mi occupo di programmazione. Non potrò mai dimenticare il primo programma che implementai, con il mitico Commodore 64: la risoluzione di equazioni di secondo grado. Poi all'università (1990) un docente particolarmente illuminato svolse un corso di programmazione in Basic finalizzato alla realizzazione di una simulazione grafica di alcuni argomenti della disciplina (Meccanica Superiore: ovvero studio del movimento dei corpi). Io scelsi di trattare le leggi di Keplero e la loro applicazione nella determinazione analitica e grafica delle orbite dei corpi celesti, date le loro condizioni iniziali (sarà arduo, ma credo che sarà il mio prossimo script!).
Solo da un anno ho "messo le mani" su Internet e, come già detto, da qualche mese su Javascript e debbo assicurare che ho trovato tale linguaggio, nella sua estrema semplicità, potente e versatile nel campo delle implementazioni matematiche. Non mi ritengo un "classico" esperto di Javascript perché, se darete un'occhiata ai file sorgenti dei miei script, noterete una certa approssimazione formale.

Con il primo script, che ho implementato per Internet Explorer e che poi è sfociato in GeoSript, ho cercato di risolvere la gestione dei pixel in Javascript. Problema non indifferente per tracciare, per esempio, una curva nel piano cartesiano e che nei linguaggi "tradizionali" (persino in Java!) viene risolto con i banali point, line, circle ecc. In Javascript: niente! Così ho pensato che l'unico strumento che poteva consentirmi di gestire i punti dello schermo (e quindi di una curva da tracciare) era il tag HTML <DIV>. Ecco cosa ne è uscito:


<SCRIPT language="JavaScript">
var i=-400;
var x;
var y;
colore="black";
x0=400;
y0=300;
di=0.2;
while (i>=-400 && i<=400 )
{
x=i+x0;
y=-(i*i)+y0;
document.write("<DIV style='background-color:"+colore+"; position:absolute; left:"+x+"; top:"+y+"; width:1px; height:1px;'><img SRC='punto.gif' border=0 width=1 height=1></DIV>");
i=i+di;
}
</SCRIPT>

Quello che si ottiene è il grafico della parabola y=x2.
Osservate che la definizione dello stile per il tag <DIV> non ha valore puramente estetico ma è necessaria per gestire la dimensione e la posizione del punto da tracciare.
Il valore delle costanti x0 e y0, così come il segno negativo di y=-(x*x)+y0, credo che si possa intuire: trasformare l'orientamento delle coordinate assolute (0,0)-(800,600) dello schermo (ho utilizzato una risoluzione video 800x600) nelle coordinate cartesiane (-400,300)-(400,-300).

Dopo aver risolto questo problema fondamentale, ho sviluppato lo script per tracciare il grafico di qualsiasi retta, parabola o circonferenza con la possibilità, attraverso un campo <FORM>, di introdurre i coefficienti delle equazioni. Ho inoltre creato una pagina con tre frames che consentivano di utilizzare un'interfaccia utente funzionale. Vediamo come è strutturata la funzione grafico() che lo script utilizza per tracciare le rette:


function grafico()
{
indice=document.dati.colori.selectedIndex;
colore=document.dati.colori.options[indice].value;
scala=36;
ar=document.dati.a1.value;
br=document.dati.b1.value;
cr=document.dati.c1.value;
y=0;
x=0;
a=ar;
b=br;
c=cr*scala; //per rendere il grafico proporzionato
i=-range;
while (i>=-range && i<=range ){
if (b == 0) //controlla quando la retta è parallela all'asse y
{
x=-c/a+x0;
y=-i+y0;
}
else
{
x=i+x0;
y=-(-i*a/b-c/b)+y0
}
if( y<=2*y0 && y>=0) //controlla che il grafico non venga tracciato fuori dallo schermo
{
parent.destro.document.write("<DIV style='background-color :"+colore+"; position:absolute; left:"+x+"; top:"+y+"; width:1px; height:1px;'><img SRC='punto.gif' border=0 width=1 height=1></DIV>");
i=i+di;
}
else
{
i=i+5;
}
}
}

Alcune variabili e funzioni, comuni a tutti gli script, sono state dichiarate in un file esterno .js

Credevo di aver fatto un buon lavoro fino a quando un amico, cui avevo fatto provare gli script, non mi mise la pulce nell'orecchio: perché non provare a implementare uno script che consenta di tracciare QUALSIASI FUNZIONE?
In fondo lo script che avevo implementato non era molto versatile e consentiva di tracciare curve già predefinite e con la semplice introduzione di coefficienti numerici. Lui mi disse che in rete aveva trovato dei siti, soprattutto uno francese, che facevano miracoli. Mi accorsi che tutti utilizzavano degli applet Java oppure programmi CGI (ovviamente nessuno era implementato in Javascript!). Accettai la sfida.
Nel frattempo ero anche riuscito a trovare un manuale di Javascript su carta: M. Moncur, Imparare Javascript 1.3 in 24 ore, Tecniche Nuove.
Per prima cosa mi occorreva una funzione Javascript che "leggesse" la funzione matematica introdotta dall'esterno (ovviamente con una precisa sintassi) e un'altra che la "trasformasse" in una espressione compatibile con l'oggetto Math di Javascript.


function init()
{
immessa=document.dati.input.value;
lunghezza=immessa.length;
if(lunghezza < 1)
{
window.alert("Non è stata inserita nessuna funzione.");
return;
}
for (t=0; t<lunghezza; t++)
{
ch[t]=immessa.charAt(t);
}
scan();
if(ok)
{
convalida();
}
else
{
simbolica="";
ok=true;
return;
}
}
.......
.......
function scan()
{
simbolica = "";
variabile="(i/scala)"
arc=false;
j=0;

do
{
switch(ch[j])
{
case "x" : simbolica +=variabile;
break;
case "s" : if (ch[j+1]=="i" && ch[j+2]=="n")
{
if (arc)
{
simbolica += "Math.asin";
arc=false;
j=j+2;
}
else
{
simbolica += "Math.sin";
j=j+2;
arc=false;
}
}
else
{
sconosciuta();
}
break;
……
……

case "p" : simbolica +="Math.PI";
break;

case "(" : simbolica +="(";
break;
case ")" : simbolica +=")";
break;
case "+" : simbolica +="+";
break;
case "-" : simbolica +="-";
break;
case "*" : simbolica +="*";
break;
case "/" : simbolica +="/";
break;

default : window.alert("Carattere "+ch[j]+" sconosciuto!");
ok=false;
return false;

}
j=j+1
}
while (j<lunghezza)
}

Per esempio introducendo la stringa p*sin(x)/arcsin(x), essa viene trasformata in Math.PI*Math.sin(i/scala)/Math.asin(i/scala)
A questo mi mancava il passaggio dalla stringa simbolica alla funzione numerica. Quasi per caso riuscii a scoprire che il metodo eval() faceva al caso mio. Ecco il risultato:


function fun(valore)
{
this.valore=valore;
}

funzione=new fun();

function traccia()
{
indice=document.dati.colori.selectedIndex;
colore=document.dati.colori.options[indice].value;
i=inf;
while (i>=inf && i<=sup)
{
funzione.valore = eval(simbolica);
if (funzione.valore && funzione.valore*scala>y0-460 && funzione.valore*scala<y0)
{
grafico();
}
else
{
i=i+di;
}
}
info.style.visibility="hidden";
info2.style.visibility="visible";
return;
}

function grafico()
{
i=i+di;
x=i+x0;
y=-funzione.valore*scala+y0;
parent.destro.document.write("<DIV style='background-color :"+colore+"; position:absolute; left:"+x+"; top:"+y+"; width:1px; height:1px;'><img SRC='punto.gif' border=0 width=1 height=1></DIV>");
}

Dopo di che lo script era quasi completo.

Successivamente ho elaborato lo stesso script per Netscape (solo qualche cambiamento) e ho aggiunto, solo nella versione per Internet Explorer, qualche piccolo particolare: la scala di rappresentazione, le coordinate del puntatore del mouse, la possibilità di spostare il grafico, tutta la parte grafica (pulsanti con effetti rollover, la calcolatrice, ecc.)
Con qualche piccola modifica, ho poi utilizzato lo stesso script per implementare quelli riguardanti il calcolo di derivata e integrale, le curve in coordinate parametriche e polari.

Ecco come è nato Mathscript.

Torna indietro