UNPKG

cloudvisio

Version:

Visual Representation of cloud data

182 lines (148 loc) 3.84 kB
// dependencies var d3 = require('d3'); // force chart var force = function( self ) { this.self = self; // setup options self.set( this.defaults ); // set axis self._axisSchema( this.schema ); }; force.prototype = { layout: "force", schema: { label: "string", group: "number", radius: "number" }, defaults: { charge: -20, distance: 30, ir : 0, radius: 5 }, constructor: force, render: function( append ){ var self = this.self; var that = this; var svg = d3.select( self.el + " "+ self.options.container); var width = 4000, height = 3000; var data = this.nodes = this.data(); var force = d3.layout.force() .charge( self.options.charge ) .linkDistance( self.options.distance ) .size([width, height]) .nodes( data ) .links([]) .start(); /* var groups = d3.nest().key(function(d) { return d.group & 3; }).entries( nodes ); var groupPath = function(d) { return "M" + d3.geom.hull(d.values.map(function(i) { return [i.x, i.y]; })).join("L") + "Z"; }; var groupFill = function(d, i) { return self.color(i & 3); }; */ this.node = svg.selectAll(".node") .data( data ).enter() .append("circle") .attr("class", "node") .attr("r", function(d) { return d.radius; }) .style("fill", function(d) { return self.color( d.group ); }) .call(force.drag); this.node.append("title") .text(function(d) { return d.name; }); force.on("tick", function(e){ that.update(e); }); }, // local data: function(){ var self = this.self, d = self.models; // get keys //var keys = self.keys( d ); // required data: // - name (string) var name = self._axis.label, group = self._axis.group, radius = self._axis.radius; // old code: // - group (integer) /* if( keys.indexOf("id") > -1 ) name = "id"; if( keys.indexOf("title") > -1 ) name = "title"; if( keys.indexOf("label") > -1 ) name = "label"; if( keys.indexOf("name") > -1 ) name = "name"; for( var i in keys ){ if( keys[i].search(/group_/gi) === 0 ) group = keys[i]; } */ // var result = []; for( var j in d ){ result.push({ name : d[j][name], group : d[j][group], // if radius is a number, use it as a static value radius: ( isNaN(radius) )? d[j][radius] : radius }); } // return result; }, update: function(e) { // Push different nodes in different directions for clustering. var k = 6 * e.alpha; this.nodes.forEach(function(o, i) { //o.x += i & 2 ? k : -k; //o.y += i & 1 ? k : -k; o.x += (o.group + 2) & 2 ? k : -k; o.y += (o.group + 2) & 1 ? k : -k; }); var q = d3.geom.quadtree( this.nodes ), i = 0, n = this.nodes.length; while (++i < n) { q.visit( this.collide( this.nodes[i] )); } this.node.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); /* svg.selectAll("path") .data(groups) .attr("d", groupPath) .enter().insert("path", "circle") .style("fill", groupFill) .style("stroke", groupFill) .style("stroke-width", 40) .style("stroke-linejoin", "round") .style("opacity", .2) .attr("d", groupPath); */ }, // Collision detection // Source: https://gist.github.com/GerHobbelt/3116713 collide: function(node) { var r = node.radius + 16, nx1 = node.x - r, nx2 = node.x + r, ny1 = node.y - r, ny2 = node.y + r; return function(quad, x1, y1, x2, y2) { if (quad.point && (quad.point !== node)) { var x = node.x - quad.point.x, y = node.y - quad.point.y, l = Math.sqrt(x * x + y * y), r = node.radius + quad.point.radius; if (l < r) { l = (l - r) / l * 0.5; node.x -= x *= l; node.y -= y *= l; quad.point.x += x; quad.point.y += y; } } return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; }; } }; module.exports = force;