--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolkit/exemples/couple/javascript/streamMap.js Thu Apr 10 14:20:23 2014 +0200
@@ -0,0 +1,401 @@
+/**
+ * Creation of an object for streamgraph and treemap connected
+ */
+
+/**
+ * Parameters is the object containing basics initialization parameters
+ */
+function StreamMap(json, parametres) {
+ this.parametres = {
+ hauteurStream: 100,
+ largeurStream: 900,
+ selectorStream: "#streamgraph",
+
+ hauteurTree: 900,
+ largeurTree: 900,
+ selectorTree: "#treemap",
+
+ duree: 50,
+ nbClusters: 10,
+ nbArticles: 1000,
+
+ couleurs: null,
+
+ mx: 0,
+ my: 0,
+
+ onFocus: null,
+ onBlur: null,
+ contenu: 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;
+ }
+ };
+ this.etendre(parametres);
+
+ var object = this;
+ this.treemap = null;
+ this.streamgraph = null;
+ this.dataTreemap = null;
+ this.articles = null;
+ this.dataStreamgraph = null;
+ this.data = null;
+ this.relations = [];
+ this.treemapHtml = null;
+ this.streamgraphHtml = null;
+
+ this.area = d3.svg.area()
+ .x(function(d) {
+ return d.x * object.parametres.largeurStream / object.parametres.mx;
+ })
+ .y0(function(d) {
+ return object.parametres.hauteurStream
+ - d.y0 * object.parametres.hauteurStream / object.parametres.my;
+ })
+ .y1(function(d) {
+ return object.parametres.hauteurStream
+ - (d.y + d.y0) * object.parametres.hauteurStream
+ / object.parametres.my;
+ });
+
+ // Consctructeur des deux graphes
+
+ object.dataJSON = json;
+
+ /* -- Generate arrays for each graph -- */
+
+ object.dataTreemap = object.getDataTreemap(json);
+ object.dataStreamgraph = object.getDataStreamgraph(json);
+ object.articles = object.dataJSON.articles[0];
+// console.log(object.dataTreemap);
+// console.log(object.dataStreamgraph);
+
+ /* -- Create the streamgraph -- */
+
+ if (null==object.parametres.couleurs) {
+ object.parametres.couleurs = d3.scale.category20c();
+ }
+
+ object.parametres.mx = object.dataStreamgraph[0].length - 1;
+ object.parametres.my = d3.max(object.dataStreamgraph, function(d) {
+ return d3.max(d, function(d) {
+ return d.y0 + d.y;
+ });
+ });
+
+ object.streamgraphHtml = d3.select(object.parametres.selectorStream)
+ .style("width", object.parametres.largeurStream + "px")
+ .style("height", object.parametres.hauteurStream + "px")
+ .append("svg:svg");
+
+ object.streamgraphHtml.selectAll("path")
+ .data(object.dataStreamgraph).enter().append("svg:path")
+ .style("fill", function() {
+ return object.parametres.couleurs(Math.random());
+ })
+ .attr("d", object.area)
+ .each(function(datum, index) {
+ var item = d3.select(this).attr("id", index);
+ object.relations.push({
+ name: "cluster_" + index,
+ stream: item,
+ map: null,
+ color: item.style("fill")
+ });
+ });
+
+ /* -- Create the treemap -- */
+
+ object.treemap = d3.layout.treemap()
+ .size([object.parametres.largeurTree, object.parametres.hauteurTree])
+ .sticky(true)
+ .value(function(d) {
+ return object.comptage(d.timeline);
+ });
+
+ object.treemapHtml = d3.select("#treemap").append('div')
+ .style('position', 'relative')
+ .style('width', object.parametres.largeurTree + 'px')
+ .style('height', object.parametres.hauteurTree + 'px')
+ .style('background-color', '#32375F');
+
+ object.treemapHtml.data(object.dataTreemap).selectAll("div")
+ .data(object.treemap.nodes).enter().append("div")
+ .attr('class', 'cell')
+ .call(object.sizeCell)
+ .html(function(d) {
+ return d.children? null: object.getContent(d);
+ })
+ /* .style('background', function(d) {
+ return !d.children? null: object.parametres.couleurs(d.name);
+ })*/
+ .each(function(datum) {
+ var item = d3.select(this);
+ for (var i=0; i<object.parametres.nbClusters; i++) {
+ if (datum.name==object.relations[i].name) {
+ object.relations[i].map = item;
+ // item.style("background", object.relations[i].color);
+ }
+ }
+ });
+
+ /* -- Bind the maps with streams -- */
+ for (var i=0, _end=object.parametres.nbClusters; i<_end; i++) {
+ object.bindMapToStream(
+ object.relations[i].stream, object.relations[i].map);
+ object.bindStreamToMap(
+ object.relations[i].map, object.relations[i].stream);
+ }
+};
+
+StreamMap.prototype = {
+ etendre: function(parametres) {
+ if (null==parametres || "object"!=typeof(parametres)) {
+ return;
+ }
+
+ for (var cle in parametres) {
+ this.parametres[cle] = parametres[cle];
+ }
+ },
+
+ // calcule la taille d'un cluster (somme de tout les articles)
+ comptage : function(timeline, start, end) {
+ var compteursize = 0, idMax = 0, poidsMax = 0;
+
+ var tStart = (start==null || start<0)? 0: start;
+ var tEnd = (end==null || end>timeline.length)?
+ timeline.length: end;
+ var index, endIndex, articleId;
+ for (t=tStart; t<tEnd; t++) { //boucle sur les t de la timeline
+ compteursize+= timeline[t].length;
+ }
+
+ return compteursize;
+ },
+
+ getContent: function(datumCell, start, end) {
+ var compteursize = 0, idMax = 0, poidsMax = 0;
+ var articles = this.articles;
+
+ var tStart = (start==null || start<0)? 0: start;
+ var tEnd = (end==null || end>datumCell.timeline.length)?
+ datumCell.timeline.length: end;
+
+ var index, endIndex, articleId;
+ for (t=tStart; t<tEnd; t++) { //boucle sur les t de la timeline
+ for (index = 0, endIndex = datumCell.timeline[t].length; index<endIndex; ++index) {
+ articleId = datumCell.timeline[t][index];
+ if (articles[articleId].poids > poidsMax) {
+ poidsMax = articles[articleId].poids;
+ idMax = articleId;
+ }
+ }
+ }
+
+ if (null!=this.parametres.contenu) {
+ return this.parametres.contenu(datumCell, articles[idMax]);
+ }
+ else {
+ return articles[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 size = comptage(clusters[i], start, end);
+ var cluster = { name : "cluster_" + clusters[i].numero,
+ timeline : clusters[i].timeline };
+ data.children.push(cluster);
+ }
+
+ return [data];
+ },
+
+ getDataStreamgraph : function(json) {
+ var data = new Array(),
+ clusters = json.clusters,
+ duree = clusters[0].timeline.length;
+
+ var dataCluster, timeline;
+ for (var i=0, end=clusters.length; i<end; i++) {
+ timeline = clusters[i].timeline;
+ dataCluster = [];
+
+ for (var t=0; t<duree; t++) {
+ dataCluster.push({ x: t, y: timeline[t].length });
+ }
+ data.push(dataCluster);
+ }
+
+ // Smooth the data
+
+ return d3.layout.stack().offset("wiggle")(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"; });
+ },
+
+ bindMapToStream: function(stream, map) {
+ var object = this;
+ if (null!=this.parametres.onFocus && null!=this.parametres.onBlur) {
+ stream.on("mouseover", function() {
+ object.parametres.onFocus(stream, map);
+ });
+ stream.on("mouseout", function() {
+ object.parametres.onBlur(stream, map);
+ });
+ }
+ },
+
+ bindStreamToMap: function(map, stream) {
+ var object = this;
+ if (null!=this.parametres.onFocus && null!=this.parametres.onBlur) {
+ map.on("mouseover", function() {
+ object.parametres.onFocus(stream, map);
+ });
+ map.on("mouseout", function() {
+ object.parametres.onBlur(stream, map);
+ });
+ }
+ }
+};
+
+/* -- Draggable window -- */
+
+var selectBars = {
+ focus: function(stream, map) {
+ stream.style("stroke", "black")
+ .transition()
+ .duration(300)
+ .delay(50)
+ .style("opacity", 0.5);
+ map.classed("selected", true)
+ .transition()
+ .duration(150)
+ .delay(50)
+ .style("opacity", 0.5);
+ },
+
+ unfocus: function(stream, map) {
+ stream.style("stroke", "none")
+ .transition()
+ .duration(300)
+ .delay(75)
+ .style("opacity", 1);
+ map.classed("selected", false)
+ .transition()
+ .duration(100)
+ .delay(50)
+ .style("opacity", 1);
+ },
+
+ calculerIndx: function() { //recalcul des valeurs
+ indx[0] = Math.round(parseInt($('#gauche').css("left"))
+ /(streamMap.parametres.largeurStream/streamMap.parametres.duree));
+ indx[1] = Math.round((parseInt($('#droite').css('left'))
+ + parseInt($('#droite').css('width')))
+ /(streamMap.parametres.largeurStream/streamMap.parametres.duree));
+ },
+
+ followcache: function() { //déplacement des caches avec le drag'n'drop
+ d3.select('.cache.gauche').style("width", function() {
+ return $('#gauche').css("left")
+ });
+
+ d3.select('.cache.droite').style("left", function() {
+ var a;
+ a = parseInt($('#droite').css("left")) + 10;
+ a = a + "px";
+ return a;
+ });
+
+ d3.select('.cache.droite').style("width", function() {
+ var a;
+ a = 900 - parseInt($('.cache.droite').css('left'));
+ a = a + "px";
+ return a;
+ });
+ },
+
+
+ contain: function(a) {
+ var ar = [];
+ var lim;
+ //limite pour gauche
+ var lim = parseInt($('.selecteur.droite').css("left"));
+ ar = [0, 0, lim, 300];
+ $('.selecteur.gauche').draggable("option", "containment", ar);
+ //limite pour droite
+ lim = parseInt($('.selecteur.gauche').css("left"))+20;
+ ar = [lim, 0, 900, 300];
+ $('.selecteur.droite').draggable("option", "containment", ar);
+ },
+
+ transitionTree: function(start, end) {
+ streamMap.treemapHtml.selectAll("div")
+ .data(streamMap.treemap.value(function(d) {
+ return streamMap.comptage(d.timeline, start, end);
+ }))
+ .html(function(d) { return d.children? null: streamMap.getContent(d, start, end); })
+ .transition()
+ .duration(1500)
+ .call(streamMap.sizeCell);
+ }
+};
+
+var parametres = {
+ hauteurStream: 300,
+ hauteurTree: 300,
+ onFocus: selectBars.focus,
+ onBlur: selectBars.unfocus
+};
+var streamMap = new StreamMap(json, parametres);
+
+
+var indx = [0, streamMap.parametres.duree];
+/*l'objet indx contient les valeurs d'indexs de la zone correspondant au tree map.
+Il se réactulise lorsqu'on lâche les barres.
+*/
+//méthode draggable de jquery pour drag'n'drop
+$('.selecteur').draggable({
+ axis : 'x',
+ grid: [streamMap.parametres.largeurStream/streamMap.parametres.duree, 1],
+ containment: [60,0,
+ streamMap.parametres.largeurStream,streamMap.parametres.hauteurStream],
+ drag: selectBars.followcache,
+ stop: function(e, ui){
+ selectBars.calculerIndx();
+ selectBars.followcache();
+ selectBars.contain(ui);
+ selectBars.transitionTree(indx[0], indx[1]);
+ }
+});
+
+