toolkit/javascript/nco/treemap.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 /**
       
     2  * Creation of a treemap
       
     3  */
       
     4 
       
     5 /**
       
     6  * Parameters is the object containing basics initialization parameters
       
     7  */
       
     8 function Treemap(json, parametres) {
       
     9 	this.parametres = {
       
    10 		name: null,
       
    11 		hauteur: 300,
       
    12 		largeur: 500,
       
    13 		selector: "#treemap",
       
    14 		
       
    15 		couleurs: null,
       
    16 		relations: null,
       
    17 		
       
    18 		contenu: null,
       
    19 		template: null,
       
    20 	
       
    21 		transitionDuration: 1000
       
    22 	};
       
    23 	
       
    24 	this.etendre(parametres);
       
    25 	
       
    26 	/* -- Gestion des valeurs par défaut -- */
       
    27 	if (null==this.parametres.name) {
       
    28 		this.parametres.name = this.parametres.selector;
       
    29 	}
       
    30 	if (null==this.parametres.contenu) {
       
    31 		if (null!=this.parametres.template) {
       
    32 			this.template = jQuery(this.parametres.template.selector);
       
    33 			this.template.remove();
       
    34 			this.parametres.contenu = this.renderContenu;
       
    35 			
       
    36 			// Check for forgotten values
       
    37 			this.setDefaultValue(this.parametres.template.maxTextSpace, 50);
       
    38 			this.setDefaultValue(this.parametres.template.minFontSize, 1);
       
    39 		}
       
    40 		else {
       
    41 			this.parametres.contenu = this.defaultContent;
       
    42 		}
       
    43 	}
       
    44 	
       
    45 	/* -- Initialisation d'attributs -- */
       
    46 	var object = this;
       
    47 	this.treemap = null;
       
    48 	this.dataTreemap = null;
       
    49 	this.articles = null;
       
    50 	this.treemapHtml = null;
       
    51 
       
    52 	this.dataJSON = json;	
       
    53 	this.dataTreemap = this.getDataTreemap(json);
       
    54 	this.articles = this.dataJSON.articles[0];
       
    55 	
       
    56 	this.duree = this.dataJSON.clusters[0].timeline.length;
       
    57 	this.nbClusters = this.dataJSON.clusters.length;
       
    58 	this.nbArticles = this.articles.length;
       
    59 	
       
    60 	/* -- Create the treemap -- */
       
    61 	
       
    62 	if (null==this.parametres.couleurs) {
       
    63 		this.parametres.couleurs = new Couleurs(this.nbClusters);
       
    64 	}
       
    65 	
       
    66 	this.treemap = d3.layout.treemap()
       
    67 		.size([this.parametres.largeur, this.parametres.hauteur])
       
    68 		.sticky(true)
       
    69 		.value(function(d) { 
       
    70 			return object.comptage(d); 
       
    71 		});
       
    72 		
       
    73 	this.treemapHtml = d3.select("#treemap").append('div')
       
    74 		.style('position', 'relative')
       
    75 		.style('width', this.parametres.largeur + 'px')
       
    76 		.style('height', this.parametres.hauteur + 'px')
       
    77 		.style('background-color', '#32375F');
       
    78 		
       
    79 	this.treemapHtml.data(this.dataTreemap).selectAll("div")
       
    80 		.data(this.treemap.nodes).enter().append("div")
       
    81 			.attr('class', 'cell')
       
    82 			.style('background-color', function(datum) {
       
    83 				return d.children? null: object.parametres.couleurs.get(datum.id);
       
    84 			})
       
    85 			.call(this.sizeCell)
       
    86 			.html(function(d) { 
       
    87 				return d.children? null: object.getContent(d); 
       
    88 			})
       
    89 			.attr("datetime", function(d) {
       
    90 				return d.children? 0: object.articles[d.idMax].date;
       
    91 			});
       
    92 	
       
    93 	/* -- Register items in relations -- */
       
    94 	
       
    95 	if (null!=this.parametres.relations) {
       
    96 		this.parametres.relations.add(this.parametres.name, this);
       
    97 		
       
    98 		this.treemapHtml.selectAll("div")
       
    99 			.each(function(datum) {
       
   100 				var item = d3.select(this);
       
   101 				datum["relationName"] = object.parametres.name +'.'+ datum.name;
       
   102 				object.parametres.relations.add(datum.relationName, item);
       
   103 			});
       
   104 	}
       
   105 };
       
   106 
       
   107 Treemap.prototype = {
       
   108 	constructor: Treemap,
       
   109 	
       
   110 	etendre: function(parametres) {
       
   111 		if (null==parametres || "object"!=typeof(parametres)) {
       
   112 			return;
       
   113 		}
       
   114 		
       
   115 		for (var cle in parametres) {
       
   116 			this.parametres[cle] = parametres[cle];
       
   117 		}
       
   118 	},
       
   119 	
       
   120 	setDefaultValue: function(attribute, value) {
       
   121 		if (undefined==attribute || null==attribute) {
       
   122 			attribute = value;
       
   123 		}
       
   124 	},
       
   125 	
       
   126 	// calcule la taille d'un cluster (somme de tout les articles)
       
   127 	// et l'élément de poids maximal
       
   128 	comptage : function(datumCell, start, end) {
       
   129 		var compteursize = 0, idMax = 0, poidsMax = 0;
       
   130 		var timeline = datumCell.timeline;
       
   131 		
       
   132 		var tStart = (start==null || start<0)? 0: start;
       
   133 		var tEnd = (end==null || end>timeline.length)? 
       
   134 				timeline.length: end;
       
   135 		var index, endIndex, articleId;
       
   136 		for (var t=tStart; t<tEnd; t++) { //boucle sur les t de la timeline
       
   137 			compteursize+= timeline[t].length;
       
   138 			for (index = 0, endIndex = timeline[t].length; 
       
   139 				index < endIndex; ++index) {
       
   140 				articleId = timeline[t][index];
       
   141 				if (this.articles[articleId].poids > poidsMax) {
       
   142 					poidsMax = this.articles[articleId].poids;
       
   143 					idMax = articleId;
       
   144 				}
       
   145 			}
       
   146 		}
       
   147 		
       
   148 		datumCell.poidsMax = poidsMax;
       
   149 		datumCell.idMax = idMax;
       
   150 		return compteursize;
       
   151 	},
       
   152 	
       
   153 	getContent: function(datumCell, start, end) {
       
   154 		if (null!=this.parametres.contenu) {
       
   155 			return this.parametres.contenu.call(
       
   156 				this, datumCell, this.articles[datumCell.idMax]);
       
   157 		}
       
   158 		else {
       
   159 			return this.articles[datumCell.idMax].titre;
       
   160 		}
       
   161 	},
       
   162 
       
   163 	getDataTreemap : function(json, start, end) {
       
   164 		var data = { name : "data", children : []};
       
   165 		var clusters = json.clusters;
       
   166 		
       
   167 		for (var i=0, _end=clusters.length; i<_end; i++) { // parcours les differents clusters
       
   168 			var cluster = { id: clusters[i].numero, name : "cluster." + clusters[i].numero, timeline : clusters[i].timeline };
       
   169 			data.children.push(cluster);
       
   170 		}
       
   171 		
       
   172 		return [data];
       
   173 	},
       
   174 
       
   175 	sizeCell: function() {
       
   176 		this.style("left", function(d) { return d.x + "px"; })
       
   177 			.style("top", function(d) { return d.y + "px"; })
       
   178 			.style("width", function(d) { return d.dx - 1 + "px"; })
       
   179 			.style("height", function(d) { return d.dy - 1 + "px"; });
       
   180 	},
       
   181 	
       
   182 	focus: function(map) {
       
   183 		map.classed("selected", true)
       
   184 			.transition()
       
   185 			.duration(150)
       
   186 			.delay(50)
       
   187 			.style("opacity", 0.5);
       
   188 	},
       
   189 	
       
   190 	blur: function(map) {
       
   191 		map.classed("selected", false)
       
   192 			.transition()
       
   193 			.duration(100)
       
   194 			.delay(50)
       
   195 			.style("opacity", 1);
       
   196 	},
       
   197 	
       
   198 	transition: function(start, end) {
       
   199 		var object = this;
       
   200 		// To avoid conflicts while elements are hovered, lock the actions
       
   201 		
       
   202 		this.treemapHtml.selectAll("div")
       
   203 			.each(function(datum) {
       
   204 				object.parametres.relations.get(datum.relationName)
       
   205 						.lock();
       
   206 			})
       
   207 			.data(this.treemap.value(function(d) {
       
   208 				return object.comptage(d, start, end); 
       
   209 			}))
       
   210 			.attr("datetime", function(d) {
       
   211 				return d.children? 0: object.articles[d.idMax].date;
       
   212 			})
       
   213 			.html(function(d) { return d.children? null: object.getContent(d, start, end); })
       
   214 			.transition()
       
   215 				.duration(this.parametres.transitionDuration)
       
   216 				.call(this.sizeCell)
       
   217 				// Free the lock
       
   218 				.each("end", function(datum) {
       
   219 					object.parametres.relations.get(datum.relationName)
       
   220 						.unlock();
       
   221 				});
       
   222 	},
       
   223 	
       
   224 	defaultContent: function(cellule, article) {
       
   225 		var html;
       
   226 		var img = article.image;
       
   227 		var wi, hi, wc, hc, w, h, r;
       
   228 		
       
   229 		wi = img.largeur;
       
   230 		hi = img.hauteur;
       
   231 		wc = cellule.dx - 1;
       
   232 		hc = cellule.dy - 1;
       
   233 		r = Math.min(hi/hc, wi/wc);
       
   234 		w = wi/r;
       
   235 		h = hi/r;
       
   236 		
       
   237 		var posx, posy;
       
   238 		posx = -(w-wc)/2;
       
   239 		posy = -(h-hc)/2;
       
   240 		
       
   241 		html = "<img class = 'img' src = \"" + img.url + "\" style=\" width:"+ w + "px; height:" +h + "px; margin-top:" + posy + "px; margin-left:" + posx + "px;\" />";
       
   242 		html += "<p class = 'title' style = \" width:" + wc + "px;\" >" + article.titre + "</p>";
       
   243 		
       
   244 		return html;
       
   245 	},
       
   246 	
       
   247 	renderContenu: function(cellule, article) {
       
   248 		var image = article.image;
       
   249 		
       
   250 		var wi = image.largeur,
       
   251 			hi = image.hauteur,
       
   252 			wc = cellule.dx - 1,
       
   253 			hc = cellule.dy - 1,
       
   254 			r = Math.min(hi/hc, wi/wc),
       
   255 			w = wi/r,
       
   256 			h = hi/r,
       
   257 			posx = -(w-wc)/2,
       
   258 			posy = -(h-hc)/2;
       
   259 		
       
   260 		var data = {
       
   261 			'urlImage': image.url,
       
   262 			'widhtImage': w +"px",
       
   263 			'heightImage': h +"px",
       
   264 			'cssOffsetImage': "margin-top: "+ posy +"px; margin-left: "+posx +"px;",
       
   265 			'titreArticle': article.titre,
       
   266 			'dateArticle': article.date,
       
   267 			'widthArticle': wc +"px",
       
   268 			'heightArticle': hc +"px",
       
   269 			'cssWidthArticle': "width:" +wc +"px;",
       
   270 			'cssHeightArticle': "height:" +hc +"px;",
       
   271 			'cssDimensionsArticle': "width:" +wc +"px;height:" +hc +"px;",
       
   272 			'dateArticle': article.date
       
   273 		};
       
   274 		
       
   275 		return this.template
       
   276 			.render(data, this.parametres.template.directives).html();
       
   277 	},
       
   278 	
       
   279 	on: function(event, action) {
       
   280 		switch(event) {
       
   281 		default:
       
   282 			this.treemapHtml.on(event, action);
       
   283 		}
       
   284 	}
       
   285 };