--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolkit/javascript/nco/treemap.js Thu Apr 10 14:20:23 2014 +0200
@@ -0,0 +1,285 @@
+/**
+ * Creation of a treemap
+ */
+
+/**
+ * Parameters is the object containing basics initialization parameters
+ */
+function Treemap(json, parametres) {
+ this.parametres = {
+ name: null,
+ hauteur: 300,
+ largeur: 500,
+ selector: "#treemap",
+
+ couleurs: null,
+ relations: null,
+
+ contenu: null,
+ template: null,
+
+ transitionDuration: 1000
+ };
+
+ this.etendre(parametres);
+
+ /* -- Gestion des valeurs par défaut -- */
+ if (null==this.parametres.name) {
+ this.parametres.name = this.parametres.selector;
+ }
+ if (null==this.parametres.contenu) {
+ if (null!=this.parametres.template) {
+ this.template = jQuery(this.parametres.template.selector);
+ this.template.remove();
+ this.parametres.contenu = this.renderContenu;
+
+ // Check for forgotten values
+ this.setDefaultValue(this.parametres.template.maxTextSpace, 50);
+ this.setDefaultValue(this.parametres.template.minFontSize, 1);
+ }
+ else {
+ this.parametres.contenu = this.defaultContent;
+ }
+ }
+
+ /* -- Initialisation d'attributs -- */
+ var object = this;
+ this.treemap = null;
+ this.dataTreemap = null;
+ this.articles = null;
+ this.treemapHtml = null;
+
+ this.dataJSON = json;
+ this.dataTreemap = this.getDataTreemap(json);
+ this.articles = this.dataJSON.articles[0];
+
+ this.duree = this.dataJSON.clusters[0].timeline.length;
+ this.nbClusters = this.dataJSON.clusters.length;
+ this.nbArticles = this.articles.length;
+
+ /* -- Create the treemap -- */
+
+ if (null==this.parametres.couleurs) {
+ this.parametres.couleurs = new Couleurs(this.nbClusters);
+ }
+
+ this.treemap = d3.layout.treemap()
+ .size([this.parametres.largeur, this.parametres.hauteur])
+ .sticky(true)
+ .value(function(d) {
+ return object.comptage(d);
+ });
+
+ this.treemapHtml = d3.select("#treemap").append('div')
+ .style('position', 'relative')
+ .style('width', this.parametres.largeur + 'px')
+ .style('height', this.parametres.hauteur + 'px')
+ .style('background-color', '#32375F');
+
+ this.treemapHtml.data(this.dataTreemap).selectAll("div")
+ .data(this.treemap.nodes).enter().append("div")
+ .attr('class', 'cell')
+ .style('background-color', function(datum) {
+ return d.children? null: object.parametres.couleurs.get(datum.id);
+ })
+ .call(this.sizeCell)
+ .html(function(d) {
+ return d.children? null: object.getContent(d);
+ })
+ .attr("datetime", function(d) {
+ return d.children? 0: object.articles[d.idMax].date;
+ });
+
+ /* -- Register items in relations -- */
+
+ if (null!=this.parametres.relations) {
+ this.parametres.relations.add(this.parametres.name, this);
+
+ this.treemapHtml.selectAll("div")
+ .each(function(datum) {
+ var item = d3.select(this);
+ datum["relationName"] = object.parametres.name +'.'+ datum.name;
+ object.parametres.relations.add(datum.relationName, item);
+ });
+ }
+};
+
+Treemap.prototype = {
+ constructor: Treemap,
+
+ etendre: function(parametres) {
+ if (null==parametres || "object"!=typeof(parametres)) {
+ return;
+ }
+
+ for (var cle in parametres) {
+ this.parametres[cle] = parametres[cle];
+ }
+ },
+
+ setDefaultValue: function(attribute, value) {
+ if (undefined==attribute || null==attribute) {
+ attribute = value;
+ }
+ },
+
+ // calcule la taille d'un cluster (somme de tout les articles)
+ // et l'élément de poids maximal
+ comptage : function(datumCell, start, end) {
+ var compteursize = 0, idMax = 0, poidsMax = 0;
+ var timeline = datumCell.timeline;
+
+ var tStart = (start==null || start<0)? 0: start;
+ var tEnd = (end==null || end>timeline.length)?
+ timeline.length: end;
+ var index, endIndex, articleId;
+ for (var t=tStart; t<tEnd; t++) { //boucle sur les t de la timeline
+ compteursize+= timeline[t].length;
+ for (index = 0, endIndex = timeline[t].length;
+ index < endIndex; ++index) {
+ articleId = timeline[t][index];
+ if (this.articles[articleId].poids > poidsMax) {
+ poidsMax = this.articles[articleId].poids;
+ idMax = articleId;
+ }
+ }
+ }
+
+ datumCell.poidsMax = poidsMax;
+ datumCell.idMax = idMax;
+ return compteursize;
+ },
+
+ getContent: function(datumCell, start, end) {
+ if (null!=this.parametres.contenu) {
+ return this.parametres.contenu.call(
+ this, datumCell, this.articles[datumCell.idMax]);
+ }
+ else {
+ return this.articles[datumCell.idMax].titre;
+ }
+ },
+
+ getDataTreemap : function(json, start, end) {
+ var data = { name : "data", children : []};
+ var clusters = json.clusters;
+
+ for (var i=0, _end=clusters.length; i<_end; i++) { // parcours les differents clusters
+ var cluster = { id: clusters[i].numero, name : "cluster." + clusters[i].numero, timeline : clusters[i].timeline };
+ data.children.push(cluster);
+ }
+
+ return [data];
+ },
+
+ sizeCell: function() {
+ this.style("left", function(d) { return d.x + "px"; })
+ .style("top", function(d) { return d.y + "px"; })
+ .style("width", function(d) { return d.dx - 1 + "px"; })
+ .style("height", function(d) { return d.dy - 1 + "px"; });
+ },
+
+ focus: function(map) {
+ map.classed("selected", true)
+ .transition()
+ .duration(150)
+ .delay(50)
+ .style("opacity", 0.5);
+ },
+
+ blur: function(map) {
+ map.classed("selected", false)
+ .transition()
+ .duration(100)
+ .delay(50)
+ .style("opacity", 1);
+ },
+
+ transition: function(start, end) {
+ var object = this;
+ // To avoid conflicts while elements are hovered, lock the actions
+
+ this.treemapHtml.selectAll("div")
+ .each(function(datum) {
+ object.parametres.relations.get(datum.relationName)
+ .lock();
+ })
+ .data(this.treemap.value(function(d) {
+ return object.comptage(d, start, end);
+ }))
+ .attr("datetime", function(d) {
+ return d.children? 0: object.articles[d.idMax].date;
+ })
+ .html(function(d) { return d.children? null: object.getContent(d, start, end); })
+ .transition()
+ .duration(this.parametres.transitionDuration)
+ .call(this.sizeCell)
+ // Free the lock
+ .each("end", function(datum) {
+ object.parametres.relations.get(datum.relationName)
+ .unlock();
+ });
+ },
+
+ defaultContent: function(cellule, article) {
+ var html;
+ var img = article.image;
+ var wi, hi, wc, hc, w, h, r;
+
+ wi = img.largeur;
+ hi = img.hauteur;
+ wc = cellule.dx - 1;
+ hc = cellule.dy - 1;
+ r = Math.min(hi/hc, wi/wc);
+ w = wi/r;
+ h = hi/r;
+
+ var posx, posy;
+ posx = -(w-wc)/2;
+ posy = -(h-hc)/2;
+
+ html = "<img class = 'img' src = \"" + img.url + "\" style=\" width:"+ w + "px; height:" +h + "px; margin-top:" + posy + "px; margin-left:" + posx + "px;\" />";
+ html += "<p class = 'title' style = \" width:" + wc + "px;\" >" + article.titre + "</p>";
+
+ return html;
+ },
+
+ renderContenu: function(cellule, article) {
+ var image = article.image;
+
+ var wi = image.largeur,
+ hi = image.hauteur,
+ wc = cellule.dx - 1,
+ hc = cellule.dy - 1,
+ r = Math.min(hi/hc, wi/wc),
+ w = wi/r,
+ h = hi/r,
+ posx = -(w-wc)/2,
+ posy = -(h-hc)/2;
+
+ var data = {
+ 'urlImage': image.url,
+ 'widhtImage': w +"px",
+ 'heightImage': h +"px",
+ 'cssOffsetImage': "margin-top: "+ posy +"px; margin-left: "+posx +"px;",
+ 'titreArticle': article.titre,
+ 'dateArticle': article.date,
+ 'widthArticle': wc +"px",
+ 'heightArticle': hc +"px",
+ 'cssWidthArticle': "width:" +wc +"px;",
+ 'cssHeightArticle': "height:" +hc +"px;",
+ 'cssDimensionsArticle': "width:" +wc +"px;height:" +hc +"px;",
+ 'dateArticle': article.date
+ };
+
+ return this.template
+ .render(data, this.parametres.template.directives).html();
+ },
+
+ on: function(event, action) {
+ switch(event) {
+ default:
+ this.treemapHtml.on(event, action);
+ }
+ }
+};