--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/toolkit/javascript/nco/cartographie.js Thu Apr 10 14:20:23 2014 +0200
@@ -0,0 +1,1090 @@
+function Carte(parametres, articles, links) {
+
+ var object = this;
+
+ this.parametres = {
+
+ isPositions: false,
+
+ width: 1440,
+ height: 800,
+ top: 50,
+ left: -240,
+ boxID: "box",
+ selectorID: "carto",
+ canvasID: "canvas",
+ info: "infos",
+
+ couleurs: null,
+ relations: null,
+
+ charge: -30,
+ gravity: .13,
+ theta: 3,
+
+ nodeSizeInterval: [3, 15],
+ nodeGrowth: "linear", //value "linear", "log", or "exp"
+ layerStyle: {
+ opacity: 0.6
+ },
+ handle_len_rate: 2.2,
+ maxDistance: 35,
+
+ scaleInterval: [0.5, 10],
+ activerZoom: true,
+
+ infobulleHtml: function(node) {
+ return node.titre + "<p>cluster: " + node.group +"</p>";
+ },
+
+ infoDisplay: "hover", //valeur "hover" ou "click"
+ occlusionMgmt: false,
+ nodeHighlight: "darken", //valeur "darken" ou "grow"
+
+ zoomNode: true,
+ logZoomNode: true,
+ logZoomNodeParameter: 2,
+ selection: true,
+ clustering: false
+ };
+
+ this.beginDate = new Date();
+ this.etendre(parametres);
+
+ //création du contenant sur la page, si inexistant
+
+
+
+ if (null == (document.getElementById(this.parametres.boxID))) {
+ d3.select('.content').append('div')
+ .attr("id", this.parametres.boxID)
+ .classed("gallery", true)
+ .style("position", "absolute")
+ .style("border", "1 px dashed");
+ }
+ d3.select('#' + this.parametres.boxID)
+ .style("width", this.parametres.width)
+ .style("height", this.parametres.height)
+ .style("position", "absolute")
+ .style("top", this.parametres.top)
+ .style("left", this.parametres.left)
+ .style("overflow", "hidden")
+ .style('z-index', 0);
+
+
+ if (null == (document.getElementById(this.parametres.selectorID))) {
+ d3.select('.gallery').append('div')
+ .attr("id", this.parametres.selectorID);
+ }
+ d3.select('#' + this.parametres.selectorID)
+ .attr("width", this.parametres.width)
+ .attr("height", this.parametres.height)
+ .style("position", "absolute")
+ .style('z-index', 2);
+
+ this.drag = d3.behavior.drag()
+ .on("dragstart", function(d, i) {object.dragstart(d, i, object);})
+ .on("drag", object.dragmove)
+ .on("dragend", function(d, i) {object.dragend(d, i, object);});
+
+ this.static = false;
+
+
+ this.nodeMouseover = function(d) {
+
+ if (object.parametres.nodeHighlight == "darken") {
+ object.colorBrighten(d3.select(this));
+ }
+ else if (object.parametres.nodeHighlight == "grow") {
+ scale = object.getScale(object.rect);
+ object.grow(this, scale);
+ }
+ if (object.parametres.infoDisplay == "hover") {
+ object.highlight(d);
+ }
+ };
+
+ this.nodeMouseout = function(d) {
+
+ if (object.parametres.nodeHighlight == "darken") {
+ object.colorDarken(d3.select(this));
+ }
+ else if (object.parametres.nodeHighlight == "grow") {
+ scale = object.getScale(object.rect);
+ object.shrink(object.radius(d.scaledPoids), this);
+ }
+ if (object.parametres.infoDisplay == "hover") {
+ object.blur();
+ }
+
+ };
+
+ this.nodeClick = function(d) {
+ if (object.parametres.infoDisplay == "click") {
+ object.highlight(d);
+ }
+ if (object.parametres.occlusionMgmt) {
+ object.replaceAll();
+ object.noOcclusions(d, d3.select(this));
+ }
+ object.displayInfos(d, d3.select(this));
+ }
+
+ if (this.parametres.infoDisplay == "click") {
+
+ this.infoClick = function(d) {
+ object.blur();
+ };
+ }
+
+ //création de l'infobulle, si inexistante
+ if (null == (this.infoBulle = d3.select('#' + this.parametres.info)[0][0])) {
+ this.infoBulle = d3.select('#' + this.parametres.selectorID).append('div')
+ .attr("id", this.parametres.info)
+ .style("top", this.parametres.height)
+ .style("opacity", 0)
+ .style("z-index", 1);
+ }
+ this.infoBulle.on("click", this.infoClick);
+
+ //création du canvas sur la page, si inexistant
+ if (null == (this.canvas = document.getElementById(this.parametres.canvasID))) {
+ d3.select('.gallery').insert('canvas', '#' + this.parametres.selectorID)
+ .attr("id", this.parametres.canvasID)
+ .attr("resize", false);
+ this.canvas = document.getElementById(this.parametres.canvasID);
+ }
+ d3.select('#' + this.parametres.canvasID)
+ .attr("width", d3.select('#' + this.parametres.selectorID).attr("width"))
+ .attr("height", d3.select('#' + this.parametres.selectorID).attr("height"))
+ .style("position", "absolute")
+ .style("z-index", 1);
+
+ //initialisation du drag'n'drop
+ object.mouse = {};
+ object.isDown = false;
+ object.drag2 = false;
+ this.svg = d3.select('#' + this.parametres.selectorID).append('svg')
+ .attr("width", this.parametres.width)
+ .attr("height", this.parametres.height)
+ .on("mousedown", function() {object.mouseDown(event);})
+ .on("mousemove", function() {object.mouseMove(event);})
+ .on("mouseup", function() {object.mouseUp(event);});
+
+ paper.setup(this.canvas);
+ paper.view.viewSize = new paper.Size(object.parametres.width, object.parametres.height);
+
+ this.clusters = articles.clusters;
+
+ //génération d'une palette de couleurs
+ if (null == this.parametres.couleurs) {
+ this.parametres.couleurs = this.selectColors(this.clusters.length);
+ }
+
+ //initialisation du panneau d'informations latéral
+ this.lateral = d3.select("#infosLaterales");
+ this.lateral.select("button.close").on("click", function() {object.hideLateral();});
+
+ //initialisation du panneau de sélection de clusters
+ if (this.parametres.selection) {
+ this.choice = d3.select("#choixLateral");
+ this.choice.left = this.parametres.width + 50;
+ d3.select("h1 button.select").on("click", function() {object.displayChoice();});
+ this.fillChoices();
+ this.choice.select("button.spread").on("click", function() {object.spread();});
+ }
+ else {
+ d3.select("h1 button.select").style("opacity", 0);
+ }
+
+ console.log("Environnement OK.");
+
+ this.data = {};
+ this.zones = [];
+
+ //affichage des points pré-calculés
+ if (this.parametres.isPositions) {
+ this.data.nodes = this.generateNodes(articles, this.parametres.isPositions);
+ this.length = articles.nbItems;
+ this.display(true);
+
+ }
+
+ //initialisation du Force Directed Graph
+ else {
+ this.data.nodes = this.generateNodes(articles, this.parametres.isPositions);
+ this.data.links = this.generateLinks(links, this.data.nodes);
+
+ this.force = d3.layout.force()
+ .charge(this.parametres.charge) //-20
+ .nodes(this.data.nodes)
+ .links(this.data.links)
+ .linkDistance(function(link) {return link.linkDistance;}) //20
+ .linkStrength(function(link) {return link.linkStrength;})
+ .size([this.parametres.width, this.parametres.height])
+ .gravity(this.parametres.gravity) //.1
+ .theta(this.parametres.theta)
+ .start();
+
+ console.log("Graphe en cours de stabilisation . . .");
+
+ this.force.on("tick", function() {
+ console.log("Stabilisation OK.");
+ object.display(true);
+ });
+
+ }
+
+
+};
+
+
+
+Carte.prototype = {
+
+ //gestion des paramètres
+ etendre: function(parametres) {
+ if (null==parametres || "object"!=typeof(parametres)) {
+ return;
+ }
+
+ for (var cle in parametres) {
+ this.parametres[cle] = parametres[cle];
+ }
+ },
+
+ display: function (init) {
+
+ if (this.parametres.clustering) {
+ this.clusterData = this.clusterize(this.data.nodes, this.clusters.length);
+ this.showNodes(this.clusterData);
+ }
+ else {
+ this.showNodes(this.data.nodes);
+ }
+
+ if (this.parametres.activerZoom && init) {
+ this.activateZoom();
+ }
+ paper.setup(this.canvas);
+ paper.view.viewSize = new paper.Size(this.parametres.width, this.parametres.height);
+
+ this.createBackground();
+
+ },
+
+ clusterize: function(data, nb) {
+ clusterd = [];
+ for (var i = 0 ; i<nb; ++i) {
+ clusterd.push({group: i, titre: "Cluster numéro " + i, poids: 0, x:0, y:0, count: 0, type: "cluster"});
+ }
+ for (var i = 0; i < data.length; i++) {
+ if (clusterd[data[i].group]) {
+ clusterd[data[i].group]["poids"] += parseFloat(data[i].poids);
+ clusterd[data[i].group]["x"] += parseFloat(data[i].x);
+ clusterd[data[i].group]["y"] += parseFloat(data[i].y);
+ clusterd[data[i].group]["count"] += 1;
+ }
+ }
+ for (var i = 0 ; i<nb; ++i) {
+ if (clusterd[i]["count"]) {
+ clusterd[i]["poids"] = clusterd[i]["poids"]/10;
+ clusterd[i]["scaledPoids"] = clusterd[i]["poids"];
+ clusterd[i]["x"] /= parseFloat(clusterd[i]["count"]);
+ clusterd[i]["y"] /= parseFloat(clusterd[i]["count"]);
+ }
+ }
+
+ return clusterd;
+ },
+
+
+ activateZoom: function() {
+ this.rect = this.svg.selectAll("rect")
+ .data([{
+ x: this.parametres.width*(1 - this.parametres.scaleInterval[0])/(this.parametres.scaleInterval[1] - this.parametres.scaleInterval[0]),
+ y: 0
+ }])
+ .enter().append("rect")
+ .attr("x", function(d) { return d.x; })
+ .attr("y", function(d) { return d.y; })
+ .attr("width", 15)
+ .attr("height", 15)
+ .style("stroke", "black")
+ .style("fill", "#00f")
+ .style("z-index", 2)
+ .call(this.drag);
+ },
+
+ //génération d'une palette de couleurs
+ selectColors: function(nbClusters) {
+ var colors = colorbrewer;
+ var sets = ["BrBG", "PiYG", "PRGn", "PuOr", "RdBu", "RdYlBu", "RdYlGn"];
+ var selectorID, finalColors = [];
+
+ while (finalColors.length < nbClusters) {
+ selectorID = Math.floor(Math.random()*7);
+ selectorID2 = Math.floor(Math.random()*11);
+ color = new paper.RgbColor(colors[sets[selectorID]][11][selectorID2]);
+
+ var available = true;
+ for (var i = 0; i < finalColors.length; i++) {
+ if (Math.floor(finalColors[i].hue) == Math.floor(color.hue)) {
+ available = false;
+ }
+ }
+
+ if (color.brightness < 0.9 && available) {
+ finalColors.push(color.toCssString());
+ }
+ }
+
+ return finalColors;
+ },
+
+ //génération des noeuds à partir du json
+ generateNodes: function(items, isPos) {
+
+ var nodes = [];
+ var poidsMin = 100000, poidsMax = 0;
+
+ // on crée les noeuds
+ for (var i = 0 ; i<items.nbItems; ++i) {
+ nodes.push({index: i, titre: "Titre numero " + i, type: "article"});
+ }
+
+ // on donne à chaque noeud son poids et couleurs
+ // on traite identiquement core et agregated
+ // pour les clusters
+ var nbClusters = items.clusters.length;
+ for (var i =0; i< nbClusters; ++i) {
+ var cluster = items.clusters[i],
+ clusterId = cluster.id,
+ groups = [];
+ if (cluster.items) {
+ groups.push("items");
+ }
+ else {
+ groups.push("core");
+ groups.push("agregated");
+ }
+ for (var a in groups) {
+ var group = cluster[groups[a]];
+ for (var j =0; j<group.length; ++j) {
+ var item = group[j], poids = parseFloat(item.value);
+ nodes[item.key]["poids"] = poids;
+ nodes[item.key]["scaledPoids"] = poids;
+ nodes[item.key]["group"] = clusterId;
+ nodes[item.key]["key"] = item.key;
+ var core;
+ nodes[item.key]["core"] = (groups[a] == "core");
+
+ if (isPos) {
+ nodes[item.key]["x"] = parseFloat(item.x);
+ nodes[item.key]["y"] = parseFloat(item.y);
+ }
+ else {
+ nodes[item.key]["x"] = this.parametres.width/2*(1 + Math.cos(i*Math.Pi/nbClusters));
+ nodes[item.key]["y"] = this.parametres.height/2*(1 + Math.sin(i*Math.Pi/nbClusters));
+ }
+ if (null != this.parametres.relations) {
+ this.parametres.relations.add(this.parametres.selectorID + ".node." + item.key, nodes[item.key]);
+ }
+ if (poids>poidsMax) {
+ poidsMax = poids;
+ }
+ else if (poids<poidsMin) {
+ poidsMin = poids;
+ }
+ }
+ }
+ }
+
+ this.poidsMin = poidsMin;
+ this.poidsMax = poidsMax;
+
+ // pour les unclustered
+ var unclusteredId = items.clusters.length;
+ var unclusteredItems = (items.unclustered.items)?
+ items.unclustered.items: items.unclustered;
+ for (var i =0; i< unclusteredItems.length; ++i) {
+ var item = unclusteredItems[i];
+ nodes[item.key]["poids"] = poidsMin;
+ nodes[item.key]["scaledPoids"] = poids;
+ nodes[item.key]["group"] = unclusteredId;
+ nodes[item.key]["key"] = item.key;
+ nodes[item.key]["type"] = "article";
+ if (isPos) {
+ nodes[item.key]["x"] = parseFloat(item.x);
+ nodes[item.key]["y"] = parseFloat(item.y);
+ }
+ else {
+ nodes[item.key]["x"] = this.parametres.width/2;
+ nodes[item.key]["y"] = this.parametres.height/2;
+ }
+ }
+
+ console.log("Data articles extraites.");
+ return nodes;
+ },
+
+ //génération des liens à partir du json
+ generateLinks: function(liens, nodes) {
+ //var linkMax = 0, linkMin = 500;
+ var links = [];
+
+ for (var i = 0; i< liens.images.length; ++i) {
+ var item = liens.images[i];
+ for (var j = 0; j < 20 && j < item.v.length; ++j) {
+ var voisin = item.v[j];
+
+ var linkDistance = 200/Math.max(voisin.d, 4), linkStrength;
+
+ if (nodes[item.id]["group"] == nodes[voisin.id]["group"]) {
+ linkStrength = 1;
+ linkDistance *= 0.5;
+ }
+ else {
+ linkStrength = 0.5;
+ }
+
+ links.push({source: item.id, target: voisin.id, value: voisin.d, linkDistance: linkDistance, linkStrength: linkStrength});
+ }
+ }
+
+ console.log("Data liens extraites.");
+ return links;
+ },
+
+ //calcul du rayon
+ radius: function(poids) {
+
+ var diff = this.parametres.nodeSizeInterval[1] - this.parametres.nodeSizeInterval[0];
+ var scale = this.getScale(this.rect);
+
+ if (this.parametres.nodeGrowth == "log") {
+ return this.parametres.nodeSizeInterval[0] + Math.log(poids/(this.poidsMin*scale))*diff/Math.log(this.poidsMax/this.poidsMin);
+
+ }
+ else if (this.parametres.nodeGrowth == "exp") {
+ return this.parametres.nodeSizeInterval[0]*Math.exp(Math.log(this.parametres.nodeSizeInterval[1]/this.parametres.nodeSizeInterval[0])*(poids-(this.poidsMin*scale))/(scale*(this.poidsMax - this.poidsMin)));
+ }
+ else if (this.parametres.nodeGrowth == "linear"){
+ return scale*((this.parametres.nodeSizeInterval[0] + diff*(poids - scale*this.poidsMin)/(scale*(this.poidsMax - this.poidsMin))));
+ }
+ else {
+ alert("Wrong nodeGrowth argument!");
+ }
+ },
+
+ //affichages des noeuds
+ showNodes: function(data) {
+ var object = this;
+ var node = this.svg.selectAll("circle.node")
+ .data(data)
+ .enter().append("circle")
+ .attr("class", "node")
+ .attr("cx", function(d) { return d.x; })
+ .attr("cy", function(d) { return d.y; })
+ .attr("z-index", 0)
+ .attr("r", function(d) {return object.radius(d.poids);})
+ .style("fill", function(d) { return object.parametres.couleurs[d.group]; })
+ .on("mouseover", this.nodeMouseover)
+ .on("mouseout", this.nodeMouseout);
+
+ node.append("p")
+ .text(function(d) { return d.titre; });
+ node.on('click', this.nodeClick);
+ console.log("Noeuds OK.");
+ },
+
+ //génération du fond de la carte
+ createBackground: function() {
+ var circlePaths = {};
+ scale = this.getScale(this.rect);
+ object = this;
+
+ this.svg.selectAll('circle.node').each(function(d) {
+ if (d.type != "cluster") {
+ var node = d3.select(this);
+ var circle = new paper.Path.Circle(
+ new paper.Point(d.x, d.y), object.radius(d.scaledPoids)*2);
+ circle.fillColor = node.style("fill");
+ circlePaths[d.key] = circle;
+ }
+ });
+
+ console.log("Fond des noeuds OK.");
+
+ this.generateConnections(circlePaths);
+
+ paper.view.draw();
+ /*var endDate = new Date();
+ var timer = endDate.getTime() - beginDate.getTime();
+ console.log(timer);*/
+ },
+
+ //generate background connections between nodes of a same cluster
+ generateConnections: function(paths) {
+ for (var c=0; c<this.clusters.length; ++c) {
+ var cluster = this.clusters[c];
+
+ // définir les données suivant le type passé
+ var group = cluster.items;
+ if (undefined==group) {
+ group = cluster.core.concat(cluster.agregated);
+ }
+
+ var layer = new paper.Layer();
+
+ // Donner un design au fond
+ for (var attr in this.parametres.layerStyle) {
+ if (layer[attr]) {
+ layer[attr] = this.parametres.layerStyle[attr];
+ }
+ else {
+ layer.style[attr] = this.parametres.layerStyle[attr];
+ }
+ }
+
+ var maxDistance = this.scale(this.rect[0][0].getAttribute("x"))*this.parametres.maxDistance,
+ handle = this.parametres.handle_len_rate;
+ for (var i = 1; i<group.length; ++i) {
+ if (paths[group[i].key]) {
+ var circle = paths[group[i].key];
+ if ((circle.position.x + maxDistance > 0) && (circle.position.x < this.parametres.width + maxDistance) && (circle.position.y + maxDistance > 0) && (circle.position.y < this.parametres.height + maxDistance)) {
+ layer.appendTop(circle);
+ for (var j = 0; j<i; ++j) {
+ var path = this.connect(circle, paths[group[j].key], 0.5, handle, maxDistance);
+ if (null!=path) {
+ layer.appendTop(path);
+ }
+ }
+ }
+ }
+ }
+
+ this.zones[c] = layer;
+ if (null != this.parametres.relations) {
+ this.parametres.relations.add(this.parametres.selectorID + ".layer." + c, layer);
+ }
+
+ }
+ paper.project.layers[0].remove();
+ console.log("Connexions OK.");
+ },
+
+ /*
+ * Create a connection between two balls
+ */
+ connect: function(ball1, ball2, v, handle_len_rate, maxDistance) {
+ var center1 = ball1.position;
+ var center2 = ball2.position;
+ var radius1 = ball1.bounds.width / 2;
+ var radius2 = ball2.bounds.width / 2;
+ var pi2 = Math.PI / 2;
+ var d = center1.getDistance(center2);
+ var u1, u2;
+
+ if (radius1 == 0 || radius2 == 0) {
+ return null;
+ }
+
+ if (d > maxDistance || d <= Math.abs(radius1 - radius2)) {
+ return;
+ } else if (d < radius1 + radius2) { // case circles are overlapping
+ return null;
+ } else {
+ u1 = 0;
+ u2 = 0;
+ }
+
+ var center3 = center2.clone();
+ center3.x = center2.x - center1.x;
+ center3.y = center2.y - center1.y;
+
+ var angle1 = center3.getAngleInRadians();
+ var angle2 = Math.acos((radius1 - radius2) / d);
+ var angle1a = angle1 + u1 + (angle2 - u1) * v;
+ var angle1b = angle1 - u1 - (angle2 - u1) * v;
+ var angle2a = angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v;
+ var angle2b = angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v;
+ var p1a = center1.add(this.getVector(angle1a, radius1));
+ var p1b = center1.add(this.getVector(angle1b, radius1));
+ var p2a = center2.add(this.getVector(angle2a, radius2));
+ var p2b = center2.add(this.getVector(angle2b, radius2));
+
+ // define handle length by the distance between
+ // both ends of the curve to draw
+ var totalRadius = (radius1 + radius2);
+ var p3a = p2a.clone();
+ p3a.x = p1a.x - p2a.x;
+ p3a.y = p1a.y - p2a.y;
+ var d2 = Math.min(v * handle_len_rate, p3a.length / totalRadius);
+
+ // case circles are overlapping:
+ d2 *= Math.min(1, d * 2 / (radius1 + radius2));
+
+ radius1 *= d2;
+ radius2 *= d2;
+
+ var path = new paper.Path([p1a, p2a, p2b, p1b]);
+ path.style = ball1.style;
+ path.closed = true;
+ var segments = path.segments;
+ segments[0].handleOut = this.getVector(angle1a - pi2, radius1);
+ segments[1].handleIn = this.getVector(angle2a + pi2, radius2);
+ segments[2].handleOut = this.getVector(angle2b - pi2, radius2);
+ segments[3].handleIn = this.getVector(angle1b + pi2, radius1);
+ return path;
+ },
+
+ // ------------------------------------------------
+ getVector: function(radians, length) {
+ var angle = radians * 180 / Math.PI;
+ return new paper.Point({"angle": angle,
+ "length": length
+ });
+ },
+
+ //apparition de l'infoBulle
+ highlight: function(node) {
+ scale = this.parametres.activerZoom ? this.scale(this.rect[0][0].getAttribute("x")) : 1;
+ this.infoBulle.html(this.parametres.infobulleHtml(node));
+ if (this.infoBulle.classed("selected")) {
+ this.infoBulle.transition()
+ .duration(500)
+ .style("left", node.x + 10 + "px")
+ .style("top", node.y + 10 + "px");
+ }
+ else {
+ this.infoBulle.classed("selected", true)
+ .style("left", node.x +10 + "px")
+ .style("top", node.y +10 + "px")
+ .transition()
+ .duration(300)
+ .style("opacity", 0.5);
+ }
+ },
+
+ //disparition de l'infoBulle
+ blur: function() {
+ this.infoBulle.classed("selected", false)
+ .transition()
+ .duration(400)
+ .style("opacity", 0);
+ this.infoBulle.style("top", this.parametres.height);
+ },
+
+ //zoom sur un point
+ grow: function(node, scale) {
+ if (!this.static) {
+ d3.select(node)
+ .attr("z-index", 1)
+ .transition()
+ .duration(200)
+ .attr("r", this.parametres.nodeSizeInterval[1]*scale);
+ }
+ },
+
+ //dézoom sur un point
+ shrink: function(radius, node) {
+ if (!this.static) {
+ d3.select(node)
+ .transition()
+ .duration(70)
+ .attr("z-index", 0)
+ .attr("r", radius);
+ }
+
+ },
+
+ //réaffichage du fond sur recadrage du navigateur
+ onResize: function(event) {
+ paper.view.draw();
+ d3.select('#' + this.parametres.canvasID)
+ .attr("width", d3.select('#' + this.parametres.selectorID).attr("width"))
+ .attr("height", d3.select('#' + this.parametres.selectorID).attr("height"));
+ },
+
+ dragstart: function(d,i, object) {
+ object.rect.xi = object.scale(d3.event.x);
+ object.static = true;
+ },
+
+ dragmove: function(d, i) {
+ d.x += d3.event.dx;
+ d3.select(this).attr("x", d.x);
+ },
+
+ dragend: function(d, i, object) {
+
+ ratio = object.scale(d3.event.x)/object.rect.xi;
+ object.infoBulle.classed("selected", false)
+ .style("opacity", 0);
+
+ object.zoom(ratio);
+ object.resetCanvas();
+
+ object.zoomTransition(ratio);
+ object.static = false;
+ var timer = new Date().getTime() - object.beginDate.getTime();
+ console.log(timer);
+ },
+
+ resetCanvas: function() {
+ paper.view.remove();
+ ctx = this.canvas.getContext('2d');
+ ctx.fillStyle = 'rgb(0,0,0)';
+ ctx.fillRect(this.canvas.left, this.canvas.top, this.canvas.width, this.canvas.height);
+ paper.setup(this.canvas);
+ paper.view.viewSize = new paper.Size(this.parametres.width, this.parametres.height);
+ },
+
+ scale: function(x) {
+ return (this.parametres.scaleInterval[0] + (this.parametres.scaleInterval[1] - this.parametres.scaleInterval[0])*(x/this.parametres.width));
+ },
+
+ getScale: function(rect) {
+ if (rect == undefined || !this.parametres.activerZoom) {
+ return 1;
+ }
+ else {
+ if (this.parametres.zoomNode) {
+ if (this.parametres.logZoomNode) {
+ return Math.log(1 + this.scale(rect[0][0].getAttribute("x"))*this.parametres.logZoomNodeParameter)/(Math.log(1 + this.parametres.logZoomNodeParameter));
+ }
+ else {
+ return this.scale(rect[0][0].getAttribute("x"));
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+ },
+
+
+zoom: function(ratio) {
+
+ object = this;
+
+ scale = this.getScale(this.rect);
+
+ this.svg.selectAll("circle.node")
+ .each(function(d) {
+ var distx = object.parametres.width/2- d.x;
+ distx *= ratio;
+ d.x = object.parametres.width/2 - distx;
+
+ var disty = object.parametres.height/2 - d.y;
+ disty *= ratio;
+ d.y = object.parametres.height/2 - disty;
+ d.scaledPoids = d.poids*scale;
+
+ });
+ },
+
+ zoomTransition: function() {
+ var object = this;
+ var c = 0;
+ this.svg.selectAll("circle.node")
+ .transition()
+ .duration(Math.max(400*ratio, 400/ratio))
+
+ .attr("cx", function(d) {
+ return d.x;
+ })
+ .attr("cy", function(d) {
+ return d.y;
+ })
+ .attr("r", function(d) { return object.radius(d.scaledPoids);})
+ .each("end", function() {
+ c++;
+ if (c == object.length) {
+ object.static = false;
+ object.createBackground();
+ }
+ });
+ },
+
+ mouseDown: function(e) {
+ this.isDown = true;
+ this.mouse.x = e.x;
+ this.mouse.y = e.y;
+ this.center = {};
+ /*this.center.x = paper.view.center.x;
+ this.center.y = paper.view.center.y;*/
+
+ var object = this;
+ setTimeout(function() {
+ if (object.isDown && !object.drag2) {
+ object.blur();
+ //d3.select(object.canvas).style("visibility", "hidden");
+ object.resetCanvas();
+
+ object.static = true;
+ object.drag2 = true;
+ }
+ }, 300);
+
+ },
+
+ mouseMove: function(e) {
+ if (this.drag2) {
+ diff = {};
+ diff.x = e.x - this.mouse.x;
+ diff.y = e.y - this.mouse.y;
+ /*this.center.x -= diff.x;
+ this.center.y -= diff.y;*/
+ this.svg.selectAll('circle.node')
+ .attr("cx", function(d) {
+ d.x += diff.x;
+ return d.x;
+ })
+ .attr("cy", function(d) {
+ d.y += diff.y;
+ return d.y;
+ });
+ this.mouse.x = e.x; this.mouse.y = e.y;
+ }
+ },
+
+ mouseUp: function(e) {
+ if (this.drag2) {
+ //paper.view.center = new paper.Point(this.center.x, this.center.y);
+ //d3.select(object.canvas).style("visibility", "visible");
+ this.createBackground();
+ this.static = false;
+ this.drag2 = false;
+ }
+ this.isDown = false;
+ this.mouse = {};
+ },
+
+ colorBrighten: function(node) {
+
+ //node.style("opacity", 0.5);
+ node.style("stroke", "#000")
+ .style("stroke-width", 1);
+ },
+
+ colorDarken: function(node) {
+
+ //node.style("opacity", 1);
+ node.style("stroke", "#fff")
+ .style("stroke-width", 0.75);
+ },
+
+ noOcclusions: function(data, node) {
+
+ var allNodes = this.svg.selectAll("circle.node");
+ var x1 = data.x, y1 = data.y, r1 = parseFloat(node.attr("r"));
+// var x1 = parseFloat(node.attr("cx")), y1 = parseFloat(node.attr("cy")), r1 = parseFloat(node.attr("r"));
+
+ allNodes.each(function(d) {
+ var x2 = d.x, y2 = d.y, r2 = parseFloat(d3.select(this).attr("r"));
+ var dist = Math.sqrt(Math.pow((x2 - x1),2) + Math.pow((y2 - y1),2));
+
+ if (dist <= r1 + r2 && dist != 0) {
+ x2 = x2 + (x2-x1)*(r1+r2+1-dist)/dist;
+ y2 = y2 + (y2-y1)*(r1+r2+1-dist)/dist;
+ d3.select(this).transition()
+ .delay(50)
+ .attr("cx", x2)
+ .attr("cy", y2);
+ }
+ });
+
+
+ for (var i = 0; i < allNodes[0].length; i++) {
+
+ otherNode = d3.select(allNodes[0][i]);
+ var x2 = parseFloat(otherNode.attr("cx")), y2 = parseFloat(otherNode.attr("cy")), r2 = parseFloat(otherNode.attr("r"));
+ var dist = Math.sqrt(Math.pow((x2 - x1),2) + Math.pow((y2 - y1),2));
+
+ if (dist <= r1 + r2 && dist != 0) {
+ x2 = x2 + (x2-x1)*(r1+r2+1-dist)/dist;
+ y2 = y2 + (y2-y1)*(r1+r2+1-dist)/dist;
+ otherNode.transition()
+ .delay(50)
+ .attr("cx", x2)
+ .attr("cy", y2);
+ }
+ }
+ },
+
+ replaceAll: function() {
+ this.svg.selectAll("circle.node")
+ .transition()
+ .delay(50)
+ .attr("cx", function(d) {return d.x;})
+ .attr("cy", function(d) {return d.y;});
+ },
+
+ displayInfos: function(node, trueNode) {
+ // Calcul du temps de l'image
+ if (node.type == "cluster") {
+ this.lateral.node = trueNode;
+ this.lateral.cluster = this.clusters[node.group];
+ var clusterInfos = "Ce cluster correspond au thème " + this.lateral.cluster.id + " et contient " + this.lateral.cluster.items.length + " éléments."
+ object = this;
+ this.lateral.select("p.infosCluster").html(clusterInfos);
+ this.lateral.select("span.descriptif").html("Plus d'infos sur un élément-clé du cluster:");
+ var maxWeight = 0, rep = 0;
+ for (i = 0; i < this.lateral.cluster.items.length; i++) {
+ if (this.lateral.cluster.items[i].value > maxWeight) {
+ maxWeight = this.lateral.cluster.items[i].value;
+ rep = i;
+ }
+ }
+ key = this.lateral.cluster.items[rep].key;
+ }
+ else {
+ this.lateral.select("span.descriptif").html("Plus d'infos sur l'élément:");
+ this.lateral.select("p.infosCluster").html("");
+ key = node.key;
+ }
+ var infos = /I_am_a_legend_([0-9]+)\.jpg/.exec(images[key]);
+ var temps = parseInt(infos[1]);
+
+ var heures = parseInt(temps/90000);
+ var temps = temps%90000;
+ var minutes = parseInt(temps/1500);
+ temps = temps%1500;
+ var secondes = parseInt(temps/25);
+ this.lateral.select("span.tempsScene").html(heures + ":" + minutes + ":" + secondes);
+
+ this.lateral.select("img.image").attr("src", '../images/' + images[key]);
+
+ this.lateral.select("span.groupeId").html(node.group);
+
+ // trouver ses potes de groupes
+ var liste = "", first = true, cpt = 0;
+ if (node.group!=carto.clusters.length) {
+ for (var i=0; i<carto.clusters[node.group].items.length; ++i) {
+ if (i==key) {
+ continue;
+ }
+
+ if (first) {
+ first = false;
+ }
+ else {
+ liste+= ", ";
+ }
+
+ liste+= carto.clusters[node.group].items[i].key;
+ ++cpt;
+ }
+ }
+ else {
+ liste = "null (membre des unclustered)";
+ }
+ this.lateral.select("span.autresMembres").html(liste);
+
+ // trouver ses voisins
+ liste = "", first = true, cpt = 0;
+ for (var i=0; cpt<5 && i<links.images[key].v.length; ++i) {
+ if (first) {
+ first = false;
+ }
+ else {
+ liste+= ", ";
+ }
+
+ liste+= links.images[key].v[i].id;
+ ++cpt;
+ }
+ this.lateral.select("span.voisins").html(liste);
+
+ this.displayLateral();
+ },
+
+ displayLateral: function() {
+ this.lateral.transition()
+ .duration(750)
+ .style("width", "400px")
+ .style("opacity", "1");
+ },
+
+ hideLateral: function() {
+ this.lateral.transition()
+ .duration(500)
+ .style("width", "0px")
+ .style("opacity", "0");
+ },
+
+ clusterDatas: function(clusters) {
+ dataset = [];
+ for (var i = 0; i < this.data.nodes.length; i++) {
+ for (var j = 0; j < clusters.length; j++) {
+ if (this.data.nodes[i].group == clusters[j]) {
+ dataset.push(this.data.nodes[i]);
+ }
+ }
+ }
+
+ return dataset;
+
+ },
+
+ displayChoice: function() {
+ this.choice.transition()
+ .duration(500)
+ .style("width", "200px")
+ .style("opacity", "1");
+ },
+
+ fillChoices: function() {
+ for (var i = 0; i < this.clusters.length; i++) {
+ this.choice.select("select")
+ .append("option")
+ .attr("id", this.clusters[i].id)
+ .text(this.clusters[i].id + " (" + this.clusters[i].items.length + ")");
+ }
+ },
+
+ hideChoice: function() {
+ this.choice.transition()
+ .duration(500)
+ .style("width", "0px")
+ .style("opacity", "0");
+ },
+
+ spread: function() {
+ object.blur();
+ if (this.choice.select("select")[0][0].selectedIndex != -1) {
+ this.hideChoice();
+ this.svg.selectAll("circle.node").remove();
+ this.resetCanvas();
+
+ var clusters = [];
+ var selection = this.choice.select("select")[0][0];
+ while (selection.selectedIndex > -1) {
+ var selectedCluster = selection.children[selection.selectedIndex];
+ clusters.push(selectedCluster.id);
+ selectedCluster.selected = false;
+ }
+
+ var dataset = this.clusterDatas(clusters);
+
+ this.showNodes(dataset);
+ this.createBackground();
+
+ object = this;
+ d3.select("h1 button.select").text("Revenir à la vue globale")
+ .on("click", function() {object.globalize();});
+ }
+ },
+
+ globalize: function() {
+ this.svg.selectAll("circle.node").remove();
+ paper.view.remove();
+ this.display(false);
+ d3.select("h1 button.select").text("Faire une selection")
+ .on("click", function() {object.displayChoice();});
+ }
+
+
+};
\ No newline at end of file