278 lines
10 KiB
JavaScript
278 lines
10 KiB
JavaScript
/*
|
|
Dipendenze:
|
|
NodoGrafico
|
|
|
|
Eredita:
|
|
alberoBase
|
|
|
|
Descrizione: Disegna un albero con elementi di tipo nodoGrafico in modo tale che:
|
|
tutti i nodi ad un certo livello siano allineati
|
|
I nodi del livello superiore siano centrati rispetto ai nodi del propprio sottoalbero, ma solo se > 2
|
|
|
|
Metodi:
|
|
creaFigli,
|
|
creaRadiceClassico.
|
|
|
|
Membri:
|
|
this.inheritFrom. Riferimento alla superclasse
|
|
*/
|
|
/* exported alberoClassico */
|
|
function alberoClassico() {
|
|
// chiamata al costruttore della super classe alberoBase
|
|
this.inheritFrom = alberoBase;
|
|
this.inheritFrom();
|
|
var _treeObj, _firstIndex;
|
|
var index = 0;
|
|
/*
|
|
* Disegna un albero classico, dove ogni nodo padre e' diviso a meta'
|
|
* dall'ipotetico asse di simmetria passante per il sottoalbero profondita,
|
|
* a che profondita si e' figli, sono i nodi da disegnare, sono dati in
|
|
* formato JSON padre e' il padre dei figli ed e' di tipo NodoGrafico canvas
|
|
* e' l'oggetto di tipo RaphaelAdapter da passare agli oggetti di tipo
|
|
* nodoGrafico offset, e' la coordinata minima x a cui si può disegnare un
|
|
* nodo di quel livello. all'ultima iterazione diventa lo spazio occupato in
|
|
* x dal livello nodiCreati, array con i riferimenti a tutti i nodi creati.
|
|
* N.B. Non sarebbe indispensabile, ma senza quando si tratta di
|
|
* "correggere" la profondita' dei vari livelli la complessita' algoritmica
|
|
* aumenta troppo. dimspostamento: la dimensione con cui devo spostare lungo
|
|
* lo stesso livello return: lo spazio occupato sull'asse per il disegno da
|
|
* tutti i nodi più i fratelli
|
|
*/
|
|
this.creaFigli = function(profondita, figli, padre, canvas, offset,
|
|
nodiCreati, dimSpostamento) {
|
|
var coord = padre.getPuntoY() + padre.getAltezza() * 1.6;
|
|
// altezza, non viene mai alterata
|
|
|
|
var noFigliBrother = false; // viene messa a false se il nodo non ha
|
|
// figli, all'iterazione successiva il fratello destro controlla se
|
|
// il fratello sinistro non ha figli.
|
|
var spostatoBrother = false; // viene messo a true se il nodo viene
|
|
// spostato, all'iterazione successiva il fratello destro controllera'
|
|
// se il fratello sinistro e' stato spostato
|
|
var halfSpostatoBrother = false; // viene messo a true se il nodo
|
|
// viene spostato ma a meta', non della dimensione di un nodo
|
|
if (!nodiCreati[profondita]) {
|
|
nodiCreati[profondita] = new Array();
|
|
}
|
|
for ( var i = 0; i < figli.length; ++i) {
|
|
|
|
var arrKeyProp = this.rimuoviNonInformazioni(figli[i]);
|
|
|
|
// creo un array con i valori delle proprieta non eliminate
|
|
var arrValueProp = [];
|
|
for ( var j = 0; j < arrKeyProp.length; ++j) {
|
|
arrValueProp.push(figli[i][arrKeyProp[j]]);
|
|
}
|
|
|
|
// c'e' almeno un nodo dello stesso livello gia' creato
|
|
if (nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
&& i > 0) {
|
|
if ((nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.getHowManyChild() > 1)
|
|
&& !(figli[i].figli && figli[i].figli.length > 0)) {
|
|
// il fratello ha due o più figli e questo nodo non ha figli,
|
|
// posso spostarmi
|
|
|
|
if (nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.getHowManyChild() > 2) { // se ne ha come minimo
|
|
// 3 posso spostarmi dell'intera grandezza del nodo
|
|
offset = offset
|
|
- (dimSpostamento + this._spazioStandard);
|
|
halfSpostatoBrother = false;
|
|
spostatoBrother = true;
|
|
} else { // altrimenti meta', il fratello ha 2 figli (se
|
|
// no sarei nel ramo else del secondo if
|
|
offset = offset
|
|
- (dimSpostamento + this._spazioStandard) / 2;
|
|
halfSpostatoBrother = true;
|
|
spostatoBrother = false;
|
|
}
|
|
|
|
} else if (!(figli[i].figli && figli[i].figli.length > 0)) {
|
|
// non sono andato nel ramo if non perché il nodo non ha figli,
|
|
// ma perché il fratello non ha 2 o più figli
|
|
spostatoBrother = false;
|
|
halfSpostatoBrother = false;
|
|
}
|
|
}
|
|
// creo nodo
|
|
nodiCreati[profondita].push(new NodoGrafico());
|
|
// la differenza tra le due chiamate e' che l'offset e' passato come
|
|
// punto x nel primo caso e punto y nel secondo
|
|
index++;
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1].init(
|
|
figli[i].nome, figli[i].color, arrValueProp, arrKeyProp,
|
|
offset, coord, this._lunghezzaNodoStandard,
|
|
this._altezzaNodoStandard, canvas, padre, index
|
|
+ _firstIndex);
|
|
|
|
padre
|
|
.addFiglio(nodiCreati[profondita][nodiCreati[profondita].length - 1]);
|
|
|
|
// chiamate ricorsive sui figli se ci sono e lo spazio occupato dal
|
|
// proprio sottoalbero e' >= dello spazio occupato dal nodo
|
|
// console.log(index+_firstIndex)
|
|
if (figli[i].figli && figli[i].figli.length > 0
|
|
&& !_treeObj[index + _firstIndex].hiddenChild) { // &&
|
|
// !figli[i].hideChild)
|
|
// {
|
|
/*
|
|
* ramo if: il fratello non aveva figli, c'e' più spazio per un
|
|
* nodo che ha più di due figli, inoltre i fratello non e' stato
|
|
* spostato e quindi lo spazio c'e'
|
|
*/
|
|
if (figli[i].figli.length > 2 && noFigliBrother
|
|
&& !spostatoBrother) {
|
|
if (halfSpostatoBrother) { // stabilisco se il fratello si
|
|
// e' spostato di meta' o no.
|
|
offset = this
|
|
.creaFigli(
|
|
profondita + 1,
|
|
figli[i].figli,
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1],
|
|
canvas,
|
|
offset
|
|
- (dimSpostamento + this._spazioStandard)
|
|
/ 2, nodiCreati, dimSpostamento);
|
|
} else {
|
|
offset = this
|
|
.creaFigli(
|
|
profondita + 1,
|
|
figli[i].figli,
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1],
|
|
canvas,
|
|
offset
|
|
- (dimSpostamento + this._spazioStandard),
|
|
nodiCreati, dimSpostamento);
|
|
}
|
|
} /*
|
|
* ramo else if : il fratello non aveva figli per cui ho
|
|
* meta' grandezza nodo per i figli (il nodo ha due figli,
|
|
* se fossero tre sarebbe nel primo ramo se non ne avesse
|
|
* nel terzo)
|
|
*/
|
|
else if (figli[i].figli.length > 1 && noFigliBrother
|
|
&& !spostatoBrother) {
|
|
offset = this
|
|
.creaFigli(
|
|
profondita + 1,
|
|
figli[i].figli,
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1],
|
|
canvas,
|
|
offset
|
|
- ((dimSpostamento + this._spazioStandard) / 2),
|
|
nodiCreati, dimSpostamento);
|
|
} else {
|
|
// ho almeno un figlio, ma se sono più di due non posso
|
|
// sfruttare dello spazio perché anche il fratello sinistro
|
|
// aveva figli, oppure e' il primo nodo del livello
|
|
offset = this
|
|
.creaFigli(
|
|
profondita + 1,
|
|
figli[i].figli,
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1],
|
|
canvas, offset, nodiCreati, dimSpostamento);
|
|
}
|
|
noFigliBrother = false; // il nodo in questione ha dei figli
|
|
spostatoBrother = false; // un nodo con figli non può essere
|
|
// spostato
|
|
} else if (figli[i].figli && figli[i].figli.length > 0
|
|
&& _treeObj[index + _firstIndex].hiddenChild) {
|
|
noFigliBrother = false;
|
|
offset += dimSpostamento + this._spazioStandard;
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.addIconShowChild();
|
|
index += _treeObj[index + _firstIndex].allChild;
|
|
} else { // non ci sono figli
|
|
noFigliBrother = true; // non ha figli
|
|
offset += dimSpostamento + this._spazioStandard;
|
|
}
|
|
|
|
// quando sono qui il nodo e i suoi figli sono stati disegnati
|
|
if (nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.getHowManyChild() > 0) { // ho più di due figli, centro
|
|
// il nodo
|
|
var puntoXfiglioLeft = nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.getFiglio(0).getPuntoX();
|
|
var puntoXfiglioRight = nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.getFiglio(
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.getHowManyChild() - 1).getPuntoX()
|
|
+ this._lunghezzaNodoStandard + this._spazioStandard;
|
|
// sposto il nodo in modo tale che l'ipotetico asse di simmetria
|
|
// del nodo dividi esattamente a meta' il sottoalbero
|
|
nodiCreati[profondita][nodiCreati[profondita].length - 1]
|
|
.setX(puntoXfiglioLeft
|
|
+ (puntoXfiglioRight - puntoXfiglioLeft)/ 2
|
|
- (this._lunghezzaNodoStandard + this._spazioStandard)/ 2);
|
|
}
|
|
}
|
|
return offset;
|
|
};
|
|
|
|
var _padre;
|
|
|
|
// primo step, disegno radice
|
|
this.creaRadice = function(Json, canvas, lunghezza, altezza, spazioTraNodi,
|
|
treeObj, firstIndex) {
|
|
if (!Json) { // Json vuoto
|
|
return;
|
|
}
|
|
this._lunghezzaNodoStandard = lunghezza;
|
|
this._altezzaNodoStandard = altezza;
|
|
this._spazioStandard = spazioTraNodi;
|
|
_treeObj = treeObj;
|
|
_firstIndex = firstIndex;
|
|
var arrKeyProp = this.rimuoviNonInformazioni(Json);
|
|
// creo un array con i valori delle proprieta non eliminate
|
|
var arrValueProp = [];
|
|
for ( var i = 0; i < arrKeyProp.length; ++i) {
|
|
arrValueProp.push(Json[arrKeyProp[i]]);
|
|
}
|
|
|
|
this._padre = new NodoGrafico();
|
|
this._padre.init(Json.nome, Json.color, arrValueProp, arrKeyProp, 10,
|
|
10, this._lunghezzaNodoStandard, this._altezzaNodoStandard,
|
|
canvas, null, _firstIndex);
|
|
if (_firstIndex != 0)
|
|
this._padre.addIconShowAncestors();
|
|
if (Json.figli) { // ci sono figli
|
|
var allNode = [];
|
|
this.creaFigli(0, Json.figli, this._padre, canvas, this._padre
|
|
.getPuntoX(), allNode, this._lunghezzaNodoStandard);
|
|
|
|
// correggo la posizione della radice considerando la posizione del
|
|
// figlio più a destra e quello più a sinistra. Infine sistemo la
|
|
// dimensione del canvas
|
|
var puntoXfiglioLeft = this._padre.getFiglio(0).getPuntoX();
|
|
var puntoXfiglioRight = this._padre.getFiglio(
|
|
this._padre.getHowManyChild() - 1).getPuntoX()
|
|
+ this._lunghezzaNodoStandard + this._spazioStandard;
|
|
this._padre.setX(puntoXfiglioLeft
|
|
+ (puntoXfiglioRight - puntoXfiglioLeft) / 2
|
|
- (this._lunghezzaNodoStandard + this._spazioStandard) / 2);
|
|
}
|
|
//sistemo la dimensione del canvas se non supporta SVG
|
|
if (!document.implementation.hasFeature(
|
|
"http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) {
|
|
canvas.resizeCanvas(this._padre.getLarghezzaSubTree() + 5,
|
|
this._padre.getAltezzaSubTree() + 5);
|
|
}
|
|
_padre = this._padre;
|
|
};
|
|
|
|
this.getSize = function() {
|
|
return [ _padre.getLarghezzaSubTree() - 5,
|
|
this._padre.getAltezzaSubTree() - 5 ];
|
|
};
|
|
|
|
this.getPosizione = function() {
|
|
return [ _padre.getPuntoX(), _padre.getPuntoY() ];
|
|
};
|
|
|
|
this.getRadice = function() {
|
|
return _padre;
|
|
};
|
|
|
|
}
|