Ejemplo n.º 1
0
function Force(graph) {
  Transform.prototype.init.call(this, graph);

  this._prev = null;
  this._interactive = false;
  this._setup = true;
  this._nodes  = [];
  this._links = [];
  this._layout = d3.layout.force();

  Transform.addParameters(this, {
    size: {type: 'array<value>', default: [500, 500]},
    bound: {type: 'value', default: true},
    links: {type: 'data'},

    // TODO: for now force these to be value params only (pun-intended)
    // Can update to include fields after Parameter refactoring.
    linkStrength: {type: 'value', default: 1},
    linkDistance: {type: 'value', default: 20},
    charge: {type: 'value', default: -30},

    chargeDistance: {type: 'value', default: Infinity},
    friction: {type: 'value', default: 0.9},
    theta: {type: 'value', default: 0.8},
    gravity: {type: 'value', default: 0.1},
    alpha: {type: 'value', default: 0.1},
    iterations: {type: 'value', default: 500},

    interactive: {type: 'value', default: this._interactive},    
    active: {type: 'value', default: this._prev},
    fixed: {type: 'data'}
  });

  this._output = {
    'x': 'layout_x',
    'y': 'layout_y'
  };

  return this.mutates(true);
}
Ejemplo n.º 2
0
  function render(selectedNodeId) {
    var width = window.innerWidth,
      height = window.innerHeight;

    if (force)
      destroy();

    d3.select(window).on('resize', resize);

    force = d3.layout.force()
      .linkDistance(150)
      .charge(-500)
      .size([width, height])
      .on("tick", tick);

    svg = d3.select(container).append("svg")
      .attr("id", "twoDGraphSVG")
      .attr("width", width)
      .attr("height", height);

    link = svg.selectAll(".link");
    node = svg.selectAll(".node");

    var rootInfo = scene.getNodeInfo(selectedNodeId);

    root = {
      name: rootInfo.name,
      id: rootInfo.id
    };

    updateMessage(selectedNodeId);

    // root structure
    expandFromNode(selectedNodeId);

    update();
  }
Ejemplo n.º 3
0
	init: function(){
		var that = this;
		this.nodes = [];
		this.links = [];
		this.colour = d3.scale.ordinal()
  			.range( help.colours );

		this.svg = this.ele.append("svg")
		    .attr("width", this.width + this.margin.left + this.margin.right )
		    .attr("height", this.height + this.margin.top + this.margin.bottom )
		  .append("g")
    	    .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");

    	this.svg.append("rect")
    		.attr("x", 0)
    		.attr("y", 0)
    		.attr("width", this.width + this.margin.left + this.margin.right )
		    .attr("height", this.height + this.margin.top + this.margin.bottom )
		    .attr("fill", "#000000" );

    	this.link = this.svg.selectAll(".link");
		this.node = this.svg.selectAll(".node");

		this.force = d3.layout.force()
		    .size([ this.width, this.height ])
		    .nodes( this.nodes )
    		.links( this.links )
		    .charge(-100)
		    .linkStrength( 0.2 )
		    .linkDistance(function( l, i ){
		    	return ((Math.sin(i) + (Math.random()*0.1)) * 150) + 100;
		    })
		    .on("tick", function(){
		    	that.tick()
		    });

	},
Ejemplo n.º 4
0
export default function createGraph(props) {
  const {
    container,
    nodes,
    onClickNode,
    onClickOutside,
  } = props

  let selected = null

  d3.selection.prototype.dblTap = function(callback) {
    var last = 0
    return this.each(function() {
      d3.select(this).on('touchstart', function(e) {
        if ((d3.event.timeStamp - last) < 500) {
          return callback(e)
        }
        last = d3.event.timeStamp
      })
    })
  }

  const force = d3.layout.force()
    .size([width, height])
    .on('tick', tick)

  const zoom = d3.behavior.zoom()
    .scaleExtent([1, 10])
    .on('zoom', resize)
    .scale(2)
    .translate([ -1 * width / 2, -1 * height / 2 ])

  const svg = d3.select(container).append('svg')
    .attr('id', 'containerSVG')
    .attr('width', width)
    .attr('height', height)
    .style('cursor,', 'move')
    .on('click', clickOutside)
    .call(zoom)

  zoom.event(svg.transition().duration(50))

  const vis = svg.append('g')
    .attr('width', width)
    .attr('height', height)

  let link = vis.selectAll('.link')
  let node = vis.selectAll('.node')

  update()

  function update() {
    const links = d3.layout.tree().links(nodes)

    // Restart the force layout.
    force
      .nodes(nodes)
      .links(links)
      .start()

    // Update the links…
    link = link.data(links, (d) => d.target.id )

    // Exit any old links.
    link.exit().remove()

    // Enter any new links.
    link.enter().insert('line', '.node')
      .attr('class', 'link')
      .attr('x1', (d) => d.source.x)
      .attr('y1', (d) => d.source.y)
      .attr('x2', (d) => d.target.x)
      .attr('y2', (d) => d.target.y)

    // Update the nodes…
    node = node.data(nodes, (d) => d.id ).style('fill', color)

    // Exit any old nodes.
    node.exit().remove()

    const drag = force.drag()
      .on('dragstart', () => d3.event.sourceEvent.stopPropagation())

    // Enter any new nodes.
    node.enter().append('circle')
      .attr('class', 'node')
      .attr('cx', (d) => d.x )
      .attr('cy', (d) => d.y )
      .attr('r', (d) => d.size)
      .style('fill', color)
      .on('click', clickNode)
      .call(drag)

    svg.on('dblclick.zoom', (d) => {
      d3.event.stopPropagation()
      var dcx = (window.innerWidth / 2 - d.x * zoom.scale())
      var dcy = (window.innerHeight / 2 - d.y * zoom.scale())
      zoom.translate([dcx, dcy])
      vis.attr('transform', `translate(${dcx},${dcy})scale(${zoom.scale()})`)
    })
  }

  function tick() {
    link.attr('x1', (d) => d.source.x )
      .attr('y1', (d) => d.source.y )
      .attr('x2', (d) => d.target.x )
      .attr('y2', (d) => d.target.y )

    node.attr('cx', (d) => d.x )
        .attr('cy', (d) => d.y )
  }

  // Color leaf nodes orange, and packages white or blue.
  function color(d) {
    if (d.isOwnUser) {
      return '#FFF'
    }

    if (d._children) {
      return '#3182bd'
    } else {
      return d.children ? '#c6dbef' : '#fd8d3c'
    }
  }

  function clickNode(d) {
    if (selected) {
      selected.attr('class', 'node')
    }
    selected = d3.select(this)
    selected.attr('class', 'node selected')

    if (!d3.event.defaultPrevented) {
      d3.event.stopPropagation()
      d3.event.preventDefault()
      update()
      onClickNode(d.id)
    }
  }

  function clickOutside() {
    if (selected) {
      selected.attr('class', 'node')
    }
    selected = null

    if (!d3.event.defaultPrevented) {
      d3.event.stopPropagation()
      d3.event.preventDefault()
      onClickOutside()
    }
  }

  function resize() {
    const trans = d3.event.translate
    const scale = d3.event.scale

    vis.attr('transform', `translate(${trans}) scale(${scale})`)
  }
}
Ejemplo n.º 5
0
function bubblesVis({data, container, depth=0, gravity=0, width, height, radius=300, maxAmount, fillColor}) {
  let nodesIndex = {};

  let force = d3.layout.force()
    .size([width,height]);

  // let center = {
  //   x: radius,
  //   y: radius,
  // };

  let centerDamper = 0.5, collideDamper = 0;

  let handlers = {
  };


  function update (nodes, center) {
    let income = d => d.income;


    function moveTowardsCenter (alpha) {
      return (d) => {
        let c = center(d);
        d.x = d.x + (c.x - d.x) * (centerDamper) * alpha;
        d.y = d.y + (c.y - d.y) * (centerDamper) * alpha;
      };
    }


    force.nodes(nodes);

    force.gravity(gravity)
      .charge(d => -Math.pow(radiusScale(d.income), 2.0))
      // .charge(d => -radiusScale(d.income) * 15)
      .friction(0.9)

    let s = radius
    let radiusScale = d3.scale.linear().domain([0, maxAmount]).range([s/50, s/3])

    nodes.forEach(node => {
      if (node.x == null || node.y == null) {
        let r = Math.random() * (radius - radiusScale(node.income));
        let a = Math.random() * Math.PI * 2;
        [node.x,node.y] = pol2cart(r, a, radius, radius);
      }
    });

    // data.forEach(d => {
    //   // let bubbleRadius= = (((d.income / avgPowAmount) * radius) /  data.length) * 2e9
    //   let bubbleRadius = radiusScale(income);

    //   //radiusScale(d.income);

    //   if (!(d.id in nodesIndex)) {
    //     let r = Math.random() * (radius - bubbleRadius);
    //     let a = Math.random() * Math.PI * 2;
    //     let [x,y] = pol2cart(r, a, radius, radius);
    //     nodesIndex[d.id] = {id: d.id, x, y};
    //     nodes.push(nodesIndex[d.id]);
    //   }

    //   let node = nodesIndex[d.id];

    //   _.extend(
    //     node,
    //     {
    //       radius: bubbleRadius,
    //       subData: d.subData,
    //       data: d,
    //     });
    // });


    let nodeEls = container.selectAll('.node')
      .data(nodes, d => d.id);


    let enter = nodeEls.enter().append('g')
      .attr('class', 'node')
      // .attr('opacity', 0);

    // nodeEls.exit()
    //   .transition().duration(2000).attr('transform', 'scale(0)').attr('opacity', 0).remove();

    nodeEls.exit().remove();



    enter.append('circle')
      .attr('r', d => radiusScale(d.income))
      .attr('stroke-width', 2)
      .attr('fill', fillColor)
      .attr('aria-label', (d,i) => {
        let inSubSectorView = !!d.strata;
        if (inSubSectorView) {
          return `Sub-sector ${d.subSector} and income band ${d.strata} with total income ${formatMoney(d.income)} and total spending ${formatMoney(d.expend)} (${formatCount(d.count)} organisations)`;
        } else {
          return `Sub-sector ${d.subSector} with total income ${formatMoney(d.income)} and total spending ${formatMoney(d.expend)} (${formatCount(d.count)} organisations)`;
        }
      })
      .on('click', function (d,i) { handlers['click'] && handlers['click'].call(this, d,i) })
      .on('mouseover', function (d,i)  {
        handlers['mouseover'] && handlers['mouseover'].call(this, d,i)
      })
      .on('mousemove', function (d,i)  {
        handlers['mousemove'] && handlers['mousemove'].call(this, d,i)
      })
      .on('mouseout', function (d,i) { handlers['mouseout'] && handlers['mouseout'].call(this, d,i) });
    // .on('click', (d,i) => handlers.select(d.data, i, depth));

    // nodeEls.transition().duration(2000).attr('opacity', 1);

    // Resolves collisions between d and all other circles.
    let padding = 20;
    function collide(alpha) {
      var quadtree = d3.geom.quadtree(nodes);
      return function(d) {
        var radius = radiusScale(d.income);
        var r = radius + padding,
            nx1 = d.x - r,
            nx2 = d.x + r,
            ny1 = d.y - r,
            ny2 = d.y + r;
        quadtree.visit(function(quad, x1, y1, x2, y2) {
          if (quad.point && (quad.point !== d)) {
            var x = d.x - quad.point.x,
                y = d.y - quad.point.y,
                l = Math.sqrt(x * x + y * y),
                r = radius + radiusScale(quad.point.income) + padding;
            if (l < r) {
              l = (l - r) / l * alpha * collideDamper;
              d.x -= x *= l;
              d.y -= y *= l;
              quad.point.x += x;
              quad.point.y += y;
            }
          }
          return x1 > nx2
            || x2 < nx1
            || y1 > ny2
            || y2 < ny1;
        });
      };
    }

    force.on("tick", (e) => {
      nodeEls
        .each(collide(e.alpha))
        .each(moveTowardsCenter(e.alpha))
        .attr('transform', d => {
          return `translate(${d.x}, ${d.y})`
        });
    })

    nodeEls
      .attr('transform', d => {
        return `translate(${d.x}, ${d.y})`
      });

    // // nodeEls
    //   .attr('transform', d => {
    //     let c = center(d);
    //     return `translate(${c.x}, ${c.y})`
    //   });

    force.start();

    return self;
  };

  function on(event, handler) {
    handlers[event] = handler;
    return self;
  }

  let self = {update, on};
  return self;
}
Ejemplo n.º 6
0
var width  = $(window).width(),
    height = $(window).height()

// TODO: Create pagewalker
var repos  = $.ajax({
    url: 'https://api.github.com/users/QuantumPhi/repos?type=all&per_page=100',
    cache: true,
    async: false
})

var color = function(language) {
        if(!language || !colors[language])
            return '#717171'
        return colors[language].color
    },
    force = d3.layout.force()
        .charge(-250)
        .linkDistance(100)
        .size([width, height]),
    svg = d3.select('#content')
        .append('svg')
        .attr('width', width)
        .attr('height', height)

var groups = {}

var nodes = function() {
    var array = [{
        'index': 0,
        'color': '#000',
        'group': -1,
Ejemplo n.º 7
0
    draw: function() {
        this.set_ranges();
        var x_scale = this.scales.x,
            y_scale = this.scales.y,
            color_scale = this.scales.color,
            link_color_scale = this.scales.link_color;

        // clean up the old graph
        this.d3el.selectAll(".node").remove();
        this.d3el.selectAll(".link").remove();

        this.force_layout = d3.layout.force()
            .size([this.parent.width, this.parent.height])
            .linkDistance(this.model.get("link_distance"));

        if (x_scale && y_scale) {
            //set x and y on mark data manually
            this.model.mark_data.forEach(function(d) {
                d.x = x_scale.scale(d.xval) + x_scale.offset;
                d.y = y_scale.scale(d.yval) + y_scale.offset;
            });
        }

        this.force_layout
            .nodes(this.model.mark_data)
            .links(this.model.link_data);

        if (!x_scale && !y_scale) {
            this.force_layout
                .charge(this.model.get("charge"))
                .on("tick", _.bind(this.tick, this))
                .start();
        }

        var directed = this.model.get("directed");

        this.links = this.d3el.selectAll(".link")
            .data(this.force_layout.links())
            .enter().append("path")
            .attr("class", "link")
            .style("stroke", function(d) {
                return link_color_scale ? link_color_scale.scale(d.value) : null;
            })
            .style("stroke-width", function(d) { return d.link_width; })
            .attr("marker-mid", directed ? "url(#arrow)" : null);

        var that = this;
        this.nodes = this.d3el.selectAll(".node")
            .data(this.force_layout.nodes())
            .enter().append("g")
            .attr("class", "node")
            .call(this.force_layout.drag);

        this.nodes
            .append(function(d) {
                return document.createElementNS(d3.ns.prefix.svg, d.shape);
            })
            .attr("class", "element")
            .each(function(d) {
                var node = d3.select(this);
                for(var key in d.shape_attrs) {
                    node.attr(key, d.shape_attrs[key]);
                }
            })
            .style("fill", function(d, i) {
                return that.get_node_color(d, i);
            });

        this.nodes.append("text")
            .attr("class", "label")
            .attr("text-anchor", function(d) {
                return d.label_display === "center" ? "middle": "start";
            })
            .attr("x", function(d) {
                var xloc = 0;
                if (d.label_display === "outside") {
                    switch (d.shape) {
                        case "rect":
                            xloc = d.shape_attrs.width / 2 + 5;
                            break;
                        case "circle":
                            xloc = d.shape_attrs.r + 5;
                            break;
                        case "ellipse":
                            xloc = d.shape_attrs.rx + 5;
                            break;
                        default:
                            xloc = 0;
                    }
                }
                return xloc;
            })
            .attr("y", ".31em")
            .text(function(d) { return d.label; })
            .style("display", function(d) {
                return d.label_display === "none" ? "none" : "inline";
            });

        this.nodes.on("click", _.bind(function(d, i) {
            this.event_dispatcher("element_clicked",
                  {"data": d, "index": i});
        }, this));
        this.nodes.on("mouseover", _.bind(function(d, i) {
            this.hover_handler({"data": d, "index": i});
        }, this));
        this.nodes.on("mouseout", _.bind(function() {
            this.reset_hover();
        }, this));
    },
Ejemplo n.º 8
0
var allCountries = function (container_selector, service) {

    var model = this;
    model.service = service;

    var data = model.service.getActiveDataset("cityPmData");
    var xVar = "pm2.5Mean";
    data = data.filter(function (d) {
        return !(isNaN(d[xVar]) || isNaN(d[xVar]));
    });

    model.iconTip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function (d) {
            return d.city + ", " + d.country + "<br>PM2.5: " + d[xVar];
        });

    model.legendtip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function () {
            return "Click to pin";
        });


    var margin = {top: 20, right: 60, bottom: 100, left: 5};
    var width = 1100 - margin.left - margin.right,
        height = 700 - margin.top - margin.bottom;
    var radius = 3;
    var padding = 7;
    var radius2 = 9;
    // init svg
    model.svgPad = d3.select(container_selector).append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom);

    model.svg = model.svgPad.append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    model.svg.call(model.iconTip);
    model.svg.call(model.legendtip);

    var x = d3.scale.linear()
        .range([0, width]);

    var y = d3.scale.linear()
        .range([height, 0]);

    var color = d3.scale.category10();

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("top");


    var svg = model.svg;

    var who = svg.append("g");
    svg = svg.append("g");


    var force = d3.layout.force()
        .nodes(data)
        .size([width, height])
        .on("tick", tick)
        .charge(-0.001)
        .gravity(0)
        .chargeDistance(30);

    x.domain(d3.extent(data, function (d) {
        return d[xVar];
    })).nice();
    y.domain([0, height]).nice();

    // set colors
    color("African Region");
    color("Region of the Americas");
    color("Eastern Mediterranean Region");
    color("European Region");
    color("South-East Asian Region");
    color("Western Pacific Region");

    // Set initial positions
    data.forEach(function (d) {
        d.x = d.px;
        d.y = d.py;
        d.color = color(d.region);
        d.radius = radius;
    });

    service.regionScale = color;


    svg.append("g")
        .attr("class", "x-axis")
        .attr("transform", "translate(0," + 0 + ")")
        .call(xAxis)
        .append("text")
        .attr("class", "label")
        .attr("x", width)
        .attr("y", 12)
        .style("text-anchor", "end")
        .text("Annual PM 2.5 (μg/m3)");

    // Interaction icon
    model.hand = model.svg.append("svg:image")
        .attr("x", width)
        .attr("y", 50)
        .attr("width", 30)
        .attr("height", 30)
        .attr("xlink:href", "img/hand.png");


    var node = svg.selectAll(".dot")
        .data(data)
        .enter().append("circle")
        .attr("class", "dot")
        .attr("r", radius)
        .attr("cx", function (d) {
            return d.x;
        })
        .attr("cy", function (d) {
            return d.y;
        })
        .style("fill", function (d) {
            return d.color;
        })
        .style("opacity", 0.3)
        .attr("stroke", "gray")
        .attr("stroke-width", 1)
        .on('mouseover', model.iconTip.show)
        .on('mouseout', model.iconTip.hide);

    var legend = svg.selectAll(".legend")
        .data(color.domain())
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function (d, i) {
            return "translate(0," + ((i * 20) + 50) + ")";
        });

    legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", "transparent")
        .style('cursor', 'pointer')
        .style("stroke-width", 3)
        .style("stroke", color)
        .on("mouseover", function (d) {
            model.legendtip.show(d);
            model.show(d);
            model.removeCountryLegend();
        })
        .on("mouseout", function (d) {
            model.legendtip.hide(d);
            model.update();
        })
        .on("click", function (d) {

            model.removeInteractivityIcon();

            var index = model.pinned.indexOf(d);

            if (index > -1) {
                model.pinned.splice(index, 1);
                d3.select(this).style("fill", "transparent");
            }
            else {
                model.pinned.push(d);
                d3.select(this).style("fill", color);
            }
        });

    model.pinned = [];
    legend.append("text")
        .attr("x", width - 24)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "end")
        .text(function (d) {
            return d;
        });


    svg.append("line")
        .attr("x1", width - 150)
        .attr("y1", 175)
        .attr("x2", width)
        .attr("y2", 175)
        .style("stroke", "gray")
        .style("stroke-width", 1);

    // Selected city legend
    model.legend_city_text = svg.append("text")
        .attr("x", width - 24)
        .attr("y", 190)
        .attr("dy", ".35em")
        .style("text-anchor", "end")
        .text("Selected City");

    model.legend_city_circle = svg.append("circle")
        .attr("r", radius)
        .attr("cx", width - 8)
        .attr("cy", 190)
        .style("fill", 'yellow')
        .attr("stroke", "gray")
        .attr("stroke-width", 1);


    force.start();

    model.stop = null;

    function tick(e) {

        //if (model.stop !== null) {
        //    force.stop();
        //}
        //
        //
        //node.each(moveTowardDataPosition(e.alpha));
        //
        //node.each(collide(e.alpha));
        //
        //node.attr("cx", function (d) {
        //        return d.x;
        //    })
        //    .attr("cy", function (d) {
        //        if (model.city && model.city.city === d.city && model.city.country === d.country) {
        //            var x = d.x;
        //            var y = d.y;
        //            model.citydot.attr("cx", x).attr("cy", y);
        //
        //        }
        //        return d.y;
        //    });


    }


    function moveTowardDataPosition(alpha) {
        return function (d) {
            d.y += ( y(height / 2) - d.y) * 0.1 * alpha;
        };
    }

    // Resolve collisions between nodes.
    function collide(alpha) {
        var quadtree = d3.geom.quadtree(data);
        return function (d) {
            var r = d.radius + radius + padding,
                nx1 = d.x - r,
                nx2 = d.x + r,
                ny1 = d.y - r,
                ny2 = d.y + r;
            quadtree.visit(function (quad, x1, y1, x2, y2) {
                if (quad.point && (quad.point !== d)) {
                    var x = d.x - quad.point.x,
                        y = d.y - quad.point.y,
                        l = Math.sqrt(x * x + y * y),
                        r = d.radius + quad.point.radius + radius2 + (d.color !== quad.point.color) * padding;
                    if (l < r) {
                        l = (l - r) / l * alpha;
                        d.y -= y *= l;
                        quad.point.y += y;
                    }
                }
                return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
            });
        };
    }


    who.append("line")
        .attr("x1", x(10))
        .attr("y1", 0)
        .attr("x2", x(10))
        .attr("y2", height)
        .style("stroke", "black")
        .style("stroke-width", 2);

    who.append("text")
        .attr("class", "label")
        .attr("x", x(10))
        .attr("y", -10)
        .style("text-anchor", "middle")
        .text("WHO SAFE VALUE");


    // Function to remove the interactivity icon later
    model.removeInteractivityIcon = function () {
        model.hand.remove();
        return true;
    };

    model.legend_country_text = null;

    // Function to remove the country legend text for later
    model.removeCountryLegend = function () {
        model.legend_country_text.remove();
        model.legend_country_text = null;
        model.legend_country_circle.remove();
        return true;
    };

    model.show = function (group) {
        node.data(data)
            .each(function (d) {

                d3.select(this).style("opacity", 0.1)
                    .style("fill", function () {
                        return 'gray';
                    });

                if (d.region === group) {

                    d3.select(this).style("opacity", 0.7)
                        .style("fill", function (d) {
                            return d.color;
                        });


                }
            });
    };

    model.update = function () {


        // Selected country legend
        if (model.legend_country_text === null && model.pinned.indexOf(service.getSelectedCityData().region) <= -1) {
            model.legend_country_text = svg.append("text")
                .attr("x", width - 24)
                .attr("y", 210)
                .attr("dy", ".35em")
                .style("text-anchor", "end")
                .text("Selected Country");

            model.legend_country_circle = svg.append("circle")
                .attr("r", radius)
                .attr("cx", width - 8)
                .attr("cy", 210)
                .style("fill", function () {
                    var colorVal = color(service.getSelectedCityData().region);
                    //console.log(service.getSelectedCityData());
                    return colorVal;
                })
                .attr("stroke", "grey")
                .attr("stroke-width", 1);
        }

        model.legend_country_circle
            .style("fill", function () {
                var colorVal = color(service.getSelectedCityData().region);
                //console.log(service.getSelectedCityData());
                return colorVal;
            });

        if (model.cityline) {
            model.cityline.remove();
            model.others.remove();

            if (model.citydot) {
                model.citydot.remove();
            }
        }
        model.others = svg.append("g");
        model.cityline = svg.append("g");

        model.city = model.service.getSelectedCityData();


        //var y = 0;
        var values = [];

        var total = 0;
        var better = 0;

        node.data(data)
            .each(function (d) {

                    //console.log(d);
                    d3.select(this).style("opacity", 0.3)
                        .style("fill", function (d) {

                            if (model.pinned.indexOf(d.region) > -1) {
                                d3.select(this).style("opacity", 0.7);
                                return d.color;
                            }
                            return 'gray';
                        });

                    if (d[xVar] > model.city[xVar]) {

                        better++;
                    }
                    total++;
                    if (d.country === model.city.country) {

                        d.lineY = d3.select(this).attr("cy");
                        d.lineX = d3.select(this).attr("cx");
                        if (d.lineY > 0) {
                            values.push(d);
                        }

                        d3.select(this).style("opacity", 0.7)
                            .style("fill", d.color);

                        if (d.city === model.city.city) {
                            d3.select(this).style("opacity", 0.3)
                                .style("fill", 'gray');

                            model.citydot = svg.append("circle")
                                .attr("r", radius)
                                .attr("cx", d.lineX)
                                .attr("cy", d.lineY)
                                .style("fill", 'yellow')
                                .attr("stroke", "gray")
                                .attr("stroke-width", 1)
                                .on('mouseover', function () {
                                    model.iconTip.show(d);
                                })
                                .on('mouseout', function () {
                                    model.iconTip.hide(d);
                                });

                        }
                    }
                }
            );

        // set cities in country lines
        var lowest = 9001;
        var highest = 0;
        var highest_val, lowest_val;

        values.forEach(function (d) {

            if (x(d[xVar]) > highest) {
                highest = x(d[xVar]);
                highest_val = d[xVar];
            }
            if (x(d[xVar]) < lowest) {
                lowest = x(d[xVar]);
                lowest_val = d[xVar];
            }

        });

        model.others.append("line")
            .attr("x1", lowest)
            .attr("y1", height + 55)
            .attr("x2", highest)
            .attr("y2", height + 55)
            .style("stroke", "black")
            .style("stroke-width", 1);

        model.cityline.append("text")
            .attr("class", "label")
            .attr("x", (highest + lowest) / 2)
            .attr("y", height + 70)
            .style("text-anchor", "middle")
            .style("fill", "black")
            .text(model.city.country);

        // Lowest
        model.cityline.append("text")
            .attr("class", "label")
            .attr("x", lowest - 10)
            .attr("y", height + 60)
            .style("text-anchor", "middle")
            .style("fill", "black")
            .text(lowest_val);

        // Highest
        model.cityline.append("text")
            .attr("class", "label")
            .attr("x", highest + 10)
            .attr("y", height + 60)
            .style("text-anchor", "middle")
            .style("fill", "black")
            .text(highest_val);

        var c = model.city.city + ", " + model.city.country;
        var perc = (better / total * 100);

        model.textLine = "";
        if (perc >= 50) {
            model.textLine = "The air in " + c + " is better than the air in " + perc.toFixed(0) + "% of all other recorded cities.";

        }
        else {
            model.textLine = "The air in " + c + " is worse than the air in " + (100 - perc).toFixed(0) + "% of all other recorded cities.";
        }
        $("#percentCompared").text(model.textLine);


        model.setSocial();


        window.history.pushState('string', 'The Air we Breathe', 'http://www.theairwebreathe.org/index.html?city=' + model.city.city + '&country=' + model.city.country);
    };


    model.setSocial = function () {

        $('meta[property="og:title"]').remove();
        $('head').append('<meta property="og:title" content="' + model.text + '">');

        var simpleLink = 'http://www.theairwebreathe.org';
        var Linkedinlink = simpleLink + '/index.html?city=' + model.city.city + '%26country=' + model.city.country;
        var link = simpleLink + '/index.html?city=' + encodeURIComponent(model.city.city) + '&country=' + encodeURIComponent(model.city.country);
        $("#fb_share").unbind();
        $("#fb_share").click(function () {
            FB.ui({
                method: 'feed',
                link: link,
                caption: 'The Air We Breathe - Free Radicals',
                name: model.textLine,
            }, function (response) {
            });

        });

        $("#linkedInShare").unbind()
        $("#linkedInShare").click(function () {
            var llink = 'https://www.linkedin.com/shareArticle?url=' + Linkedinlink + '&title="' + encodeURIComponent(model.textLine) + '"&summary=Air%20pollution%20is%20now%20the%20single%20biggest%20environmental%20health%20risk%20to%20humans.%20Outdoor%20air%20pollution%20in%20both%20cities%20and%20rural%20areas%20was%20estimated%20to%20cause%203.7%20million%20premature%20deaths%20worldwide%20in%202012.&source=LinkedIn';
            window.open(llink, "popupWindow", "width=600, height=400, scrollbars=yes");
        });


        $("#twitterShare").unbind()
        $("#twitterShare").click(function () {
            var tlink = 'https://twitter.com/intent/tweet?hashtags=air%2Cpollution&original_referer=' + simpleLink + '&ref_src=twsrc%5Etfw&text=' + encodeURIComponent('"' + model.textLine + '" - ') + '&tw_p=tweetbutton&url=' + simpleLink;
            window.open(tlink, "popupWindow", "width=600, height=400, scrollbars=yes");
        });
    };

    model.updateExternal = function () {
        model.update();

    }

    //setTimeout(function () {
    //    console.log(JSON.stringify(data));
    //}, 5 * 60000);


};
Ejemplo n.º 9
0
    Template.logincounts.rendered = function () {
        container=document.getElementById('logins-wrapper')
        container.style.cursor='wait'
        var margin = {top: 0, right: 0, bottom: 0, left: 0},
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom,
            minRadius=3,
            maxRadius=40,
            clipPadding=4;

        var fill = d3.scale.category10();

        var nodes = [],
            links = [],
            foci = [{x: 50, y: 50}, {x: 350, y: 250}];

        var svg = d3.select(".logins-wrapper").append("svg")
            .attr("width", width)
            .attr("height", height)
           .append("g")
            .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        var force = d3.layout.force()
            .nodes(nodes)
            .links([])
            .gravity(.1)
            .charge(-300)
            .size([width, height])
            .on("tick", tick);

        var node = svg.selectAll(".node"),
            link = svg.selectAll(".link");

        var r = d3.scale.sqrt()
            .range([0, maxRadius]);

        Meteor.apply('logincounts',
            [],
            onResultReceived = function(err,result){
                //debugLog(err,result);
                if (typeof err == 'undefined') {
                    logincountsResult.status='completed';
                    logincountsResult.result = result;
                    logincountsResult.content=result.content;
                    logincountsResult.data=result.data;
                    jsondata=result.data;
                    container.style.cursor='auto';
                    r.domain([0, d3.max(jsondata, function(d) { return d.success+ d.failures; })])
                    jsondata.forEach(function(d){
                        d.id=d.username;
                        d.count=(d.success +d.failures)
                        d.k = fraction(d.success, d.failures);
                        d.r = r(d.count);
                        d.cr = Math.max(minRadius, d.r);
                        nodes.push(d)
                        });
                    start();
               } else {
                    //debugLog(err,result);
                    logincountsResult.status='error';
                    logincountsResult.error=err;
                    container.style.cursor='auto';
               }
           });

        function start() {
            container.style.cursor='auto'
            node = node.data(force.nodes(), function(d) { return d.id;});
            //console.log(node)
            //make a node for each entry
            node.enter()
                .append("a")
                .attr("class", function(d) { return "node " + d.id; })
                .attr("class", "node")
                .call(force.drag);

            // delineate between success/failures:
            var successEnter = node.append("g")
                .attr("class", "g-success");

            successEnter.append("clipPath")
                .attr("id", function(d) { return "g-clip-success-" + d.username; })
                .append("rect");

            successEnter.append("circle")
                .attr("r", function(d) {return d.cr;})
                .attr("class","successcircle");

            var failureEnter = node.append("g")
                .attr("class", "g-failures");

            failureEnter.append("clipPath")
                .attr("id", function(d) { return "g-clip-failure-" + d.username; })
                .append("rect");

            failureEnter.append("circle")
                .attr("r", function(d) {return d.cr;})
                .attr("class","failurecircle");

            node.append("line")
                .attr("class", "g-split")
                .attr("x1", function(d) { return -d.cr + 2 * d.r * d.k; })
                .attr("y1", function(d) {
                    return -Math.sqrt(d.cr * d.cr - Math.pow(-d.cr + 2 * d.cr * d.k, 2));
                    })
                .attr("x2", function(d) { return -d.cr + 2 * d.cr * d.k; })
                .attr("y2", function(d) { return Math.sqrt(d.cr * d.cr - Math.pow(-d.cr + 2 * d.cr * d.k, 2)); })
                .attr("stroke","white")
                .attr("stroke-width",1);

            node.append("svg:text")
                .attr("x", 1)
                .attr("y", ".3em")
                .attr("class","textlabel")
                .text(function(d) { return d.username; });

            // make a mouse over for the success/failure counts
            node.append("title")
              .text(function(d) { return d.username + ": " + d.success + " / " + d.failures });

            // size circle clips
            node.selectAll("rect")
              .attr("y", function(d) { return -d.r - clipPadding; })
              .attr("height", function(d) { return 2 * d.r + 2 * clipPadding; });

            node.select(".g-success rect")
              .style("display", function(d) { return d.k > 0 ? null : "none" })
              .attr("x", function(d) { return -d.r - clipPadding; })
              .attr("width", function(d) { return 2 * d.r * d.k + clipPadding; });

              node.select(".g-success circle")
                .attr("clip-path", function(d) { return d.k < 1 ? "url(#g-clip-success-" + d.username + ")" : null; });

              node.select(".g-failures rect")
                .style("display", function(d) { return d.k < 1 ? null : "none" })
                .attr("x", function(d) { return -d.cr + 2 * d.cr * d.k; })
                .attr("width", function(d) { return 2 * d.cr; });

              node.select(".g-failures circle")
                .attr("clip-path", function(d) { return d.k > 0 ? "url(#g-clip-failure-" + d.username + ")" : null; });

            node.exit().remove();
            force.start();
        }

        function tick(e) {
            var k = .1 * e.alpha;

            // Push nodes toward their designated focus
            // based on ratio of success to failure
            nodes.forEach(function(o, i) {
              if (o.success > o.failures ){
                  o.y += (foci[0].y - o.y) * k;
                  o.x += (foci[0].x - o.x) * k;
              }else{
                  o.y += (foci[1].y - o.y) * k;
                  o.x += (foci[1].x - o.x) * k;
              }

            });

            svg.selectAll(".node")
                .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
        }

      // Given two quantities a and b, returns the fraction to split the circle a + b.
        function fraction(a, b) {
            var k = a / (a + b);
            if (k > 0 && k < 1) {
              var t0, t1 = Math.pow(12 * k * Math.PI, 1 / 3);
              for (var i = 0; i < 10; ++i) { // Solve for theta numerically.
                t0 = t1;
                t1 = (Math.sin(t0) - t0 * Math.cos(t0) + 2 * k * Math.PI) / (1 - Math.cos(t0));
              }
              k = (1 - Math.cos(t1 / 2)) / 2;
            }
            return k;
      }

    } //end Template rendered
Ejemplo n.º 10
0
function visualizeTypeSolver(typeSolver, types) {
  // Taken from d3 example of force-directed graphs
  var nodes = getNodes(typeSolver.constraints);
  var links = getLinks(typeSolver.constraints);

  var width = window.innerWidth - 400;
  var height = window.innerHeight;

  var color = d3.scale.category20();

  var colorTypes = [];
  for (var i = 0; i < nodes.length; i++) {
    colorTypes.push(nodes[i].type);
  }
  for (var i = 0; i < links.length; i++) {
    colorTypes.push(links[i].type);
  }
  colorTypes = Utils.set(colorTypes);

  function color(type) {
    colorTypes.push(type);
    return actualColor(type);
  }

  var force = d3.layout.force()
    .charge(-300)
    .linkDistance(100)
    .size([width / 2, height / 2]);

  var prevSvg = document.getElementById('d3-container');
  if (prevSvg) {
    prevSvg.parentNode.removeChild(prevSvg);
  }

  var svg = d3.select('body').append('svg')
      .attr('width', width)
      .attr('height', height)
      .attr('id', 'd3-container');

  force.nodes(nodes)
       .links(links)
       .start();

  var link = svg.selectAll('.link')
      .data(links)
    .enter().append('line')
      .attr('class', 'link')
      .style('stroke-width', '5px')
      .style('stroke', function(d) {
        return color(d.type);
      });

  var node = svg.selectAll('.node')
      .data(nodes)
    .enter().append('g')
      .attr('class', 'node');

  node.append('circle')
      .attr('r', function(d) {
        return 10 + (getNodeText(d) + ': ' + getNodeTypeText(d)).length * 3.5;
      })
      .style('fill', function(d) { return color(d.type); })
      .call(force.drag);

  function getNodeTypeText(node) {
    var finalTypes = types.find(function(candidateType) {
      return node === candidateType.node;
    });
    if (!finalTypes) {
      return '??';
    }
    return getTypesText(finalTypes.types);
  }

  function getTypesText(types) {
    if (types.length === 0) {
      return 'UNSAT';
    }
    var text = '';
    for (var i = 0; i < types.length; i++) {
      text += types[i].name;
      if (i < types.length - 1) {
        text += '|';
      }
    }
    return text;
  }

  node.append('text')
    .attr('dy', '.31em')
    .attr('text-anchor', 'middle')
    .text(function(d) {
      return getNodeText(d) + ': ' + getNodeTypeText(d);
    });

  node.append('title')
    .text(function(d) {
      return getNodeText(d) + ': ' + getNodeTypeText(d);
    });

  force.on('tick', function() {
    link.attr('x1', function(d) { return d.source.x * 2; })
        .attr('y1', function(d) { return d.source.y * 2; })
        .attr('x2', function(d) { return d.target.x * 2; })
        .attr('y2', function(d) { return d.target.y * 2; });

    node.attr('transform', function(d) {
      return 'translate(' + (d.x * 2) + ',' + (d.y * 2) + ')';
    });
  });

  makeLegend(colorTypes, color);
}
Ejemplo n.º 11
0
    initialize: function(options) {

      var self = this;

      self.width = options.width;
      self.height = options.height;

      self.base.classed('sillyforce', true);

      self.bases = {
        nodes: self.base.append('g')
          .classed('nodes', true),
        links: self.base.append('g')
          .classed('links', true)
      };

      function onEnd() {
        if (self.running) {
          generateLinks();
          self.draw();
          self.start();
        }
      }

      function tick() {
        self.base.selectAll('.node').attr("cx", function(d) { return d.x; })
            .attr("cy", function(d) { return d.y; });
      }

      self.force = d3.layout.force()
        .charge(-400)
        .linkDistance(320)
        .size([self.width, self.height])
        .on("tick", tick)
        .on("end", onEnd);

      self.layer('nodes', self.bases.nodes, {
        dataBind: function(data) {
          return this.selectAll(".node")
            .data(self.force.nodes(), function(d) {
              return d.id;
            });
        },
        insert: function() {
          return this.append("circle");
        },
        events: {
          enter: function() {
            this.attr("class", function(d) {
              return "node " + d.id;
            })
            .attr("r", 8)
            .attr("fill", colors.regular);
          },
          "merge:transition": function() {
            this.attr("opacity", function(d) {
              return Math.random();
            });
          },
          exit: function() {
            this.remove();
          }
        }
      });


    },
Ejemplo n.º 12
0
RDFSChema.visualize = function(data){
	var nodes = data.nodes;
	var links = data.links;
	var width = window.innerWidth;
	var height = window.innerHeight;
	var edges = [];
	
  links.forEach(function(e) { 
    var sourceNode = nodes.filter(function(n) { return n.id === e.source; })[0],
    targetNode = nodes.filter(function(n) { return n.id === e.target; })[0];
    	
    edges.push({source: sourceNode, target: targetNode, label:e.label, uri: e.uri});
    });

	// set up data
	var graph = {};
	graph.nodes = nodes;
	graph.links = edges;

	//Set up the colour scale
	var color = d3.scale.category20();

	//Set up the force layout
	var force = d3.layout.force()
	    .charge(-500)
		.theta(0.1)
	    .gravity(0.7)
	    .linkDistance(200)
	    .size([width, height]);

	//Append a SVG to the body of the html page. Assign this SVG as an object to svg
	var svg = d3.select("body").append("svg")
	    .attr("width", width)
	    .attr("height", height)
	    .attr('viewBox','0 0 '+Math.min(width,height)+' '+Math.min(width,height))



	//Creates the graph data structure out of the json data
	force.nodes(graph.nodes)
	    .links(graph.links)
	    .start();


	//Create all the line svgs but without locations yet
	var edges = svg.selectAll("line")
	    .data(graph.links)
	    .enter()
		.append("line")
	    .attr('id', function(d, i){return 'edge' + i;})
	    .style("marker-end",  "url(#arrowhead)") //Added 
	    .style('stroke-width', function(d){
	    	return d.count;
	    })
	    .style("pointer-events", "none");
	

	//Set up tooltip
	var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-10, 0])
  .html(function(d) {

    return "<strong>Uri:</strong> <span style='color:red'>" + d.uri + "</span>";
  })

  svg.call(tip);
	   

	//Do the same with the circles for the nodes - no 
	var node = svg.selectAll(".rect")
	    .data(graph.nodes)
	    .enter().append("g")
	    .attr("class", "node")
	    .call(force.drag)
	    .on('click', tip.show)
      	.on('mouseout', function() {
      d3.select(".d3-tip")
      .transition()
        .delay(100)
        .duration(1000)
        .style("opacity",0)
        .style('pointer-events', 'none')
      })


	node.append('rect')
	.attr('height', font + rect_padding)
	.attr('width', function(d){
		if(d.label){
			return (d.label.length/2 * font) + 'px'; 
		}else{
			return font + 'px';
		}
	})
	.style('stroke-width', 1)
	.style('stroke', 'black')
    .style("fill", function (d) {
    	if(d.label){
    		return 'green';
    	}else{
    		return 'red';
    	}
	});
	


	node.append("text")
	//.attr('text-anchor', 'middle')
	.text(function(d){
		//console.log(d)
		return d.label;
	})
	.style('font-size',font + 'px')
	.style('color', 'black')
	.attr("dy", font + 'px');





	var edgepaths = svg.selectAll(".edgepath")
		.data(graph.links)
		.enter()
		.append('path')
		.attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
			'class':'edgepath',
			'fill-opacity':1,
			'stroke-opacity':1,
			'fill':'blue',
			'stroke':'red',
			'id':function(d,i) {return 'edgepath'+i}})
		.style("pointer-events", "none");

	var edgelabels = svg.selectAll(".edgelabel")
		.data(graph.links)
		.enter()
		.append('text')
		.style("pointer-events", "none")
		.attr({'class':'edgelabel',
			'id':function(d,i){return 'edgelabel'+i},
			'dx':80,
			'dy':0,
			'font-size':10,
			'fill':'#aaa'});

	edgelabels.append('textPath')
		.attr('xlink:href',function(d,i) {return '#edgepath'+i})
		.style("pointer-events", "none")
		.text(function(d,i){
			return d.label
		});


	svg.append('defs').append('marker')
		.attr({'id':'arrowhead',
			'viewBox':'-0 -5 10 10',
			'refX':25,
			'refY':0,
			//'markerUnits':'strokeWidth',
			'orient':'auto',
			'markerWidth':10,
			'markerHeight':10,
			'xoverflow':'visible'})
		.append('svg:path')
		.attr('d', 'M 0,-5 L 10 ,0 L 0,5')
		.attr('fill', '#ccc')
		.attr('stroke','#ccc');
/*
	//fisheye
	var fisheye = FE.fisheye.circular()
      .radius(120);
	svg.on("mousemove", function() {
      force.stop();
      fisheye.focus(d3.mouse(this));
      d3.selectAll("rect").each(function(d) { d.fisheye = fisheye(d); })
          .attr("x", function(d) { return d.fisheye.x; })
          .attr("y", function(d) { return d.fisheye.y; })
      edges.attr("x1", function(d) { return d.source.fisheye.x; })
          .attr("y1", function(d) { return d.source.fisheye.y; })
          .attr("x2", function(d) { return d.target.fisheye.x; })
          .attr("y2", function(d) { return d.target.fisheye.y; });
    });
*/

	//Now we are giving the SVGs co-ordinates - the force layout is generating the co-ordinates which this code is using to update the attributes of the SVG elements
	force.on("tick", function () {
	    edges.attr("x1", function (d) {
	        return d.source.x;
	    })
	        .attr("y1", function (d) {
	        return d.source.y;
	    })
	        .attr("x2", function (d) {
	        return d.target.x;
	    })
	        .attr("y2", function (d) {
	        return d.target.y;
	    });

	    d3.selectAll("rect").attr("x", function (d) {
	        return d.x;
	    })
	        .attr("y", function (d) {
	        return d.y;
	    });
	    d3.selectAll("text").attr("x", function (d) {
	        return d.x;
	    })
	        .attr("y", function (d) {
	        return d.y;
	    });

		edgepaths.attr('d', function(d){
			var path='M'+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;
			return path;
		});

		edgelabels.attr('transform',function(d,i){
			if (d.target.x<d.source.x){
				var bbox = this.getBBox();
				var rx = bbox.x+bbox.width/2;
				var ry = bbox.y+bbox.height/2;
				return 'rotate(180 '+rx+' '+ry+')';
			}
			else {
				return 'rotate(0)';
			}
		});
	    
	    node.each(collide(1)); //Added
	});

	// collision detection
	var padding = 1, // separation between circles
	    radius=8;
	function collide(alpha) {
	  var quadtree = d3.geom.quadtree(graph.nodes);
	  return function(d) {
	    var rb = 2*radius + padding,
	        nx1 = d.x - rb,
	        nx2 = d.x + rb,
	        ny1 = d.y - rb,
	        ny2 = d.y + rb;
	    quadtree.visit(function(quad, x1, y1, x2, y2) {
	      if (quad.point && (quad.point !== d)) {
	        var x = d.x - quad.point.x,
	            y = d.y - quad.point.y,
	            l = Math.sqrt(x * x + y * y);
	          if (l < rb) {
	          l = (l - rb) / l * alpha;
	          d.x -= x *= l;
	          d.y -= y *= l;
	          quad.point.x += x;
	          quad.point.y += y;
	        }
	      }
	      return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
	    });
	  };
}
	//Arrows
	svg.append("defs").selectAll("marker")
	    .data(["suit", "licensing", "resolved"])
	  .enter().append("marker")
	    .attr("id", function(d) { return d; })
	    .attr("viewBox", "0 -5 10 10")
	    .attr("refX", 25)
	    .attr("refY", 0)
	    .attr("markerWidth", 6)
	    .attr("markerHeight", 6)
	    .attr("orient", "auto")
	  .append("path")
	    .attr("d", "M0,-5L10,0L0,5 L10,0 L0, -5")
	    .style("stroke", "#4679BD")
	    .style("opacity", "0.6");
	

	//Toggle stores whether the highlighting is on
	var toggle = 0;
	//Create an array logging what is connected to what
	var linkedByIndex = {};
	for (var i = 0; i < graph.nodes.length; i++) {
	    linkedByIndex[i + "," + i] = 1;
	};




	/*// search
	var optArray = [];
	for (var i = 0; i < graph.nodes.length - 1; i++) {
	    optArray.push(graph.nodes[i].label);
	}
	optArray = optArray.sort();
	$(function () {
	    $("#search").autocomplete({
	        source: optArray
	    });
	});
	function searchNode() {
	    //find the node
	    var selectedVal = document.getElementById('search').value;
	    var node = svg.selectAll(".node");
	    if (selectedVal == "none") {
	        node.style("stroke", "white").style("stroke-width", "1");
	    } else {
	        var selected = node.filter(function (d, i) {
	            return d.label != selectedVal;
	        });
	        selected.style("opacity", "0");
	        var link = svg.selectAll(".link")
	        link.style("opacity", "0");
	        d3.selectAll(".node, .link").transition()
	            .duration(5000)
	            .style("opacity", 1);
	    }
	}*/
}
var createVisualization = function(containerElement, data){



	// set up SVG for D3
var width  = 495,
    height = 495,
    colors = d3.scale.category10();

var svg = d3.select(containerElement)
  .append('svg')
  .attr('oncontextmenu', 'return false;')
  .attr('width', width)
  .attr('height', height);

// set up initial nodes and links
//  - nodes are known by 'id', not by index in array.
//  - reflexive edges are indicated on the node (as a bold black circle).
//  - links are always source < target; edge directions are set by 'left' and 'right'.
var nodes = [
    {id: 0, reflexive: false},
    {id: 1, reflexive: true },
    {id: 2, reflexive: false}
  ],
  lastNodeId = 2,
  links = [
    {source: nodes[0], target: nodes[1], left: true, right: true },
    {source: nodes[1], target: nodes[2], left: true, right: true }
  ];

// init D3 force layout
var force = d3.layout.force()
    .nodes(nodes)
    .links(links)
    .size([width, height])
    .linkDistance(150)
    .charge(-500)
    .on('tick', tick)

// define arrow markers for graph links
svg.append('svg:defs').append('svg:marker')
    .attr('id', 'end-arrow')
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 6)
    .attr('markerWidth', 3)
    .attr('markerHeight', 3)
    .attr('orient', 'auto')
  .append('svg:path')
    .attr('d', 'M0,-5L10,0L0,5')
    .attr('fill', '#000');

svg.append('svg:defs').append('svg:marker')
    .attr('id', 'start-arrow')
    .attr('viewBox', '0 -5 10 10')
    .attr('refX', 4)
    .attr('markerWidth', 3)
    .attr('markerHeight', 3)
    .attr('orient', 'auto')
  .append('svg:path')
    .attr('d', 'M10,-5L0,0L10,5')
    .attr('fill', '#000');

// line displayed when dragging new nodes
var drag_line = svg.append('svg:path')
  .attr('class', 'link dragline hidden')
  .attr('d', 'M0,0L0,0');

// handles to link and node element groups
var path = svg.append('svg:g').selectAll('path'),
    circle = svg.append('svg:g').selectAll('g');

// mouse event vars
var selected_node = null,
    selected_link = null,
    mousedown_link = null,
    mousedown_node = null,
    mouseup_node = null;

function resetMouseVars() {
  mousedown_node = null;
  mouseup_node = null;
  mousedown_link = null;
}

// update force layout (called automatically each iteration)
function tick() {
  // draw directed edges with proper padding from node centers
  path.attr('d', function(d) {
    var deltaX = d.target.x - d.source.x,
        deltaY = d.target.y - d.source.y,
        dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY),
        normX = deltaX / dist,
        normY = deltaY / dist,
        sourcePadding = d.left ? 17 : 12,
        targetPadding = d.right ? 17 : 12,
        sourceX = d.source.x + (sourcePadding * normX),
        sourceY = d.source.y + (sourcePadding * normY),
        targetX = d.target.x - (targetPadding * normX),
        targetY = d.target.y - (targetPadding * normY);
    return 'M' + sourceX + ',' + sourceY + 'L' + targetX + ',' + targetY;
  });

  circle.attr('transform', function(d) {
    return 'translate(' + d.x + ',' + d.y + ')';
  });
}

// update graph (called when needed)
function restart() {
  // path (link) group
  path = path.data(links);

  // update existing links
  path.classed('selected', function(d) { return d === selected_link; })
    .style('marker-start', function(d) { return d.left ? 'url(#start-arrow)' : ''; })
    .style('marker-end', function(d) { return d.right ? 'url(#end-arrow)' : ''; });


  // add new links
  path.enter().append('svg:path')
    .attr('class', 'link')
    .classed('selected', function(d) { return d === selected_link; })
    .style('marker-start', function(d) { return d.left ? 'url(#start-arrow)' : ''; })
    .style('marker-end', function(d) { return d.right ? 'url(#end-arrow)' : ''; })
    .on('mousedown', function(d) {
      if(d3.event.ctrlKey) return;

      // select link
      mousedown_link = d;
      if(mousedown_link === selected_link) selected_link = null;
      else selected_link = mousedown_link;
      selected_node = null;
      restart();
    });

  // remove old links
  path.exit().remove();


  // circle (node) group
  // NB: the function arg is crucial here! nodes are known by id, not by index!
  circle = circle.data(nodes, function(d) { return d.id; });

  // update existing nodes (reflexive & selected visual states)
  circle.selectAll('circle')
    .style('fill', function(d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
    .classed('reflexive', function(d) { return d.reflexive; });

  // add new nodes
  var g = circle.enter().append('svg:g');

  g.append('svg:circle')
    .attr('class', 'node')
    .attr('r', 12)
    .style('fill', function(d) { return (d === selected_node) ? d3.rgb(colors(d.id)).brighter().toString() : colors(d.id); })
    .style('stroke', function(d) { return d3.rgb(colors(d.id)).darker().toString(); })
    .classed('reflexive', function(d) { return d.reflexive; })
    .on('mouseover', function(d) {
      if(!mousedown_node || d === mousedown_node) return;
      // enlarge target node
      d3.select(this).attr('transform', 'scale(1.1)');
    })
    .on('mouseout', function(d) {
      if(!mousedown_node || d === mousedown_node) return;
      // unenlarge target node
      d3.select(this).attr('transform', '');
    })
    .on('mousedown', function(d) {
      if(d3.event.ctrlKey) return;

      // select node
      mousedown_node = d;
      if(mousedown_node === selected_node) selected_node = null;
      else selected_node = mousedown_node;
      selected_link = null;

      // reposition drag line
      drag_line
        .style('marker-end', 'url(#end-arrow)')
        .classed('hidden', false)
        .attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + mousedown_node.x + ',' + mousedown_node.y);

      restart();
    })
    .on('mouseup', function(d) {
      if(!mousedown_node) return;

      // needed by FF
      drag_line
        .classed('hidden', true)
        .style('marker-end', '');

      // check for drag-to-self
      mouseup_node = d;
      if(mouseup_node === mousedown_node) { resetMouseVars(); return; }

      // unenlarge target node
      d3.select(this).attr('transform', '');

      // add link to graph (update if exists)
      // NB: links are strictly source < target; arrows separately specified by booleans
      var source, target, direction;
      if(mousedown_node.id < mouseup_node.id) {
        source = mousedown_node;
        target = mouseup_node;
        direction = 'right';
      } else {
        source = mouseup_node;
        target = mousedown_node;
        direction = 'left';
      }

      var link;
      link = links.filter(function(l) {
        return (l.source === source && l.target === target);
      })[0];

      if(link) {
        link[direction] = true;
      } else {
        link = {source: source, target: target, left: false, right: false};
        link[direction] = true;
        links.push(link);
      }

      // select new link
      selected_link = link;
      selected_node = null;
      restart();
    });

  // show node IDs
  g.append('svg:text')
      .attr('x', 0)
      .attr('y', 4)
      .attr('class', 'id')
      .text(function(d) { return d.id; });

  // remove old nodes
  circle.exit().remove();

  // set the graph in motion
  force.start();
}

function mousedown() {
  // prevent I-bar on drag
  //d3.event.preventDefault();

  // because :active only works in WebKit?
  svg.classed('active', true);

  if(d3.event.ctrlKey || mousedown_node || mousedown_link) return;

  // insert new node at point
  var point = d3.mouse(this),
      node = {id: ++lastNodeId, reflexive: false};
  node.x = point[0];
  node.y = point[1];
  nodes.push(node);

  restart();
}

function mousemove() {
  if(!mousedown_node) return;

  // update drag line
  drag_line.attr('d', 'M' + mousedown_node.x + ',' + mousedown_node.y + 'L' + d3.mouse(this)[0] + ',' + d3.mouse(this)[1]);

  restart();
}

function mouseup() {
  if(mousedown_node) {
    // hide drag line
    drag_line
      .classed('hidden', true)
      .style('marker-end', '');
  }

  // because :active only works in WebKit?
  svg.classed('active', false);

  // clear mouse event vars
  resetMouseVars();
}

function spliceLinksForNode(node) {
  var toSplice = links.filter(function(l) {
    return (l.source === node || l.target === node);
  });
  toSplice.map(function(l) {
    links.splice(links.indexOf(l), 1);
  });
}

// only respond once per keydown
var lastKeyDown = -1;

function keydown() {
  d3.event.preventDefault();

  if(lastKeyDown !== -1) return;
  lastKeyDown = d3.event.keyCode;

  // ctrl
  if(d3.event.keyCode === 17) {
    circle.call(force.drag);
    svg.classed('ctrl', true);
  }

  if(!selected_node && !selected_link) return;
  switch(d3.event.keyCode) {
    case 8: // backspace
    case 46: // delete
      if(selected_node) {
        nodes.splice(nodes.indexOf(selected_node), 1);
        spliceLinksForNode(selected_node);
      } else if(selected_link) {
        links.splice(links.indexOf(selected_link), 1);
      }
      selected_link = null;
      selected_node = null;
      restart();
      break;
    case 66: // B
      if(selected_link) {
        // set link direction to both left and right
        selected_link.left = true;
        selected_link.right = true;
      }
      restart();
      break;
    case 76: // L
      if(selected_link) {
        // set link direction to left only
        selected_link.left = true;
        selected_link.right = false;
      }
      restart();
      break;
    case 82: // R
      if(selected_node) {
        // toggle node reflexivity
        selected_node.reflexive = !selected_node.reflexive;
      } else if(selected_link) {
        // set link direction to right only
        selected_link.left = false;
        selected_link.right = true;
      }
      restart();
      break;
  }
}

function keyup() {
  lastKeyDown = -1;

  // ctrl
  if(d3.event.keyCode === 17) {
    circle
      .on('mousedown.drag', null)
      .on('touchstart.drag', null);
    svg.classed('ctrl', false);
  }
}

// app starts here
svg.on('mousedown', mousedown)
  .on('mousemove', mousemove)
  .on('mouseup', mouseup);
d3.select(window)
  .on('keydown', keydown)
  .on('keyup', keyup);
restart();


	return containerElement;
}
Ejemplo n.º 14
0
        componentDidMount: function() {            
            var width = window.innerWidth,
            height = window.innerHeight;
            
            var foci = [];
            for (var i = 0; i <= 10; i++) {
                foci[i] = {
                    x: (i+1) * width / 13 + width / 26,
                    y: height / 2
                };
            }
            
            var svg = d3.select('#main-svg')
                .attr('xmlns', 'http://www.w3.org/2000/svg')
                .attr('width', width)
                .attr('height', height);

            var force = d3.layout.force()
                .gravity(0.1)
                .charge(-300)
                .chargeDistance(Infinity)
                .friction(0.9)
                .linkDistance(2)
                .linkStrength(function(d) { return d.weight / 5; })
                .size([width, height]);

            var component = this;
            var nodes = Array.from(this.props.animes.animeIds).map(function(id) {
                return {
                    name: component.props.animes.animeTitles[id],
                    url: component.props.animes.animeUrls[id],
                    myScore: component.props.animes.animePersonalScores[id],
                    group: 1
                };
            });

            var links = this.props.edges;

            force.nodes(nodes)
                .links(links)
                .start();

            var link = svg.selectAll('.link')
                .data(links)
                .enter().append('svg:line')
                .attr('class', 'link');

            var node = svg.selectAll('.node')
                .data(nodes)
                .enter().append('g')
                .attr('class', 'node')
                .attr('x', function(d) { return d.myScore; })
                .attr('y', 0)
                .attr('px', function(d) { return d.myScore; })
                .attr('py', 0)
                .on('mouseover', mouseover)
                .on('mouseout', mouseout)
                .call(force.drag);
                
            node.append('circle')
                .attr('r', 30.1)
                .attr('cx', 0)
                .attr('cy', 0)
                .attr('stroke', 'black')
                .attr('stroke-width', 1);

            node.append('svg:image')
                .attr('xlink:href', function(d) { return d.url; })
                .attr('x', -35)
                .attr('y', -35)
                .attr('width', 70)
                .attr('height', 70)
                .attr('preserveAspectRatio', 'xMidYMid slice')
                .attr('clip-path', 'url(#clipCircle)');

            /*node.append('text')
                .attr('dx', 12)
                .attr('dy', '.35em')
                .text(function(d) { return d.myScore; });*/
                
            function mouseover() {
                d3.select(this).selectAll('image,circle').transition()
                    .duration(400)
                    .attr('transform', 'scale(3, 3)');
            };
                
            function mouseout() {
                d3.select(this).selectAll('image,circle').transition()
                    .duration(400)
                    .attr('transform', 'scale(1, 1)');
            };

            force.on('tick', function(e) {
                link.attr('x1', function(d) { return d.source.x; })
                    .attr('y1', function(d) { return d.source.y; })
                    .attr('x2', function(d) { return d.target.x; })
                    .attr('y2', function(d) { return d.target.y; });
                    
                var k = .1 * e.alpha;
                nodes.forEach(function(o) {
                    o.y += (foci[o.myScore].y - o.y) * k;
                    o.x += (foci[o.myScore].x - o.x) * k;
                });

                node.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; });
            });
        },
Ejemplo n.º 15
0
	buildForceLayout: function() {
		let width = 800;
		let height = 800;
		let color = d3.scale.category20();

		this.refs.forceLayout.innerHTML = '';

		this.zoom = d3.behavior.zoom()
		.scaleExtent([-10, 10])
		.on('zoom', this.zoomed);

		this.force = d3.layout.force()
		.size([width, height])
		.nodes(this.props.nodes)
		.charge(function(d){
			let charge = -4000;
			if (d.index === 0) charge = 10 * charge;
			return charge;
		})
		.links(this.props.links)
		.linkDistance(15);

		this.svg = d3.select(this.refs.forceLayout).append('svg')
		.attr('width', '100%')
		.attr('height', height)
		.append('g');

		let rect = this.svg.append('rect')
		.attr('width', width)
		.attr('height', height)
		.style('fill', 'none')
		.style('pointer-events', 'all');

		this.container = this.svg.append('g');

		let link = this.container.append('g')
		.attr('class', 'links')
		.selectAll('.link')
		.data(this.props.links)
		.enter()
		.append('line')
		.attr('class', 'link');

		let node = this.container.append('g')
		.attr('class', 'nodes')
		.selectAll('.node')
		.data(this.props.nodes)
		.enter();

		let circles = node.append('circle')
		.style('fill', function(node) { return color(node.type); })
		.attr('class', 'node');

		this.force.on('end', () => {
			this.setState({ loading: false });
			let minWeight = this.props.nodes.reduce((prev, current) => {
				return Math.min(prev, current.weight);
			}, 100);
			let maxWeight = this.props.nodes.reduce((prev, current) => {
				return Math.max(prev, current.weight);
			}, 0);

			this.svg.call(this.zoom);

			circles.attr('r', function(d) { return Math.max(5, (d.weight-minWeight+1)/(maxWeight+1)*15); })
				.attr('cx', function(d) { return d.x; })
				.attr('cy', function(d) { return d.y; });

			node.append('text')
				.attr('x', function(d) { return d.x; })
				.attr('y', function(d) { return d.y; })
				.attr('text-anchor', 'middle')
				.attr('dy', '1.25em')
				.text(function(d) { return d.name; })
				.style('fill', '#555').style('font-family', 'Arial').style('font-size', 12);

			link.attr('x1', function(d) { return d.source.x; })
				.attr('y1', function(d) { return d.source.y; })
				.attr('x2', function(d) { return d.target.x; })
				.attr('y2', function(d) { return d.target.y; });

			this.zoomFit();

		});

		this.setState({ loading: true });
		this.force.start();
	},
Force.prototype._init = function() {

    var opts = this.opts
    var height = this.height
    var width = this.width
    var selector = this.selector
    var links = this.data.links
    var nodes = this.data.nodes
    var self = this

    this.$el = $(selector).first();

    // if points are colored use gray, otherwise use our default
    var linkStrokeColor = nodes[0].c ? '#999' : '#A38EF3';

    // set opacity inversely proportional to number of links
    var linkStrokeOpacity = Math.max(1 - 0.0005 * links.length, 0.5)

    // set circle stroke thickness based on number of nodes
    var strokeWidth = nodes.length > 500 ? 1 : 1.1

    function nearestPoint(points, target, xscale, yscale) {
        // find point in points nearest to target
        // using scales x and y
        // point must have attrs x, y, and s
        var i = 0, count = 0;
        var found, dist, n, p;
        while (count == 0 & i < points.length) {
            p = points[i]
            dist = Math.sqrt(Math.pow(xscale(p.x) - target[0], 2) + Math.pow(yscale(p.y) - target[1], 2))
            if (dist <= p.s) {
                found = p
                count = 1
            }
            i++;
        }
        return found
    }

    this.x = d3.scale.linear()
        .domain([0, width + margin.left + margin.right])
        .range([0, width + margin.left + margin.right]);

    this.y = d3.scale.linear()
        .domain([height + margin.top + margin.bottom, 0])
        .range([height + margin.top + margin.bottom, 0]);

    var zoom = d3.behavior.zoom()
        .x(self.x)
        .y(self.y)
        .scaleExtent([0.2, 7])
        .on('zoom', zoomed)

    var container = d3.select(selector)
        .append('div')
        .style('width', width + margin.left + margin.right + "px")
        .style('height', height + margin.top + margin.bottom + "px")

    var canvas = container
        .append('canvas')
        .attr('class', 'force-plot canvas')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .call(zoom)
        .on("click", mouseHandler)
        .on("dblclick.zoom", null)
        .node().getContext("2d")

    var loading = container
        .append('svg:svg')
        .attr('class', 'force-plot svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append("text")
        .attr("x", width / 2)
        .attr("y", height / 2)
        .attr("dy", ".35em")
        .style("text-anchor", "middle")
        .text("loading...");

    function mouseHandler() {
        if (d3.event.defaultPrevented) return;
        var pos = d3.mouse(this)
        var found = nearestPoint(nodes, pos, self.x, self.y)
        if (found) {
            highlighted = []
            highlighted.push(found.i)
            self.emit('hover', found);
        } else {
            highlighted = []
            selected = []
        };
        redraw();
    }

    var selected = [];
    var highlighted = [];
    var shiftKey;

    var brush = d3.svg.brush()
        .x(self.x)
        .y(self.y)
        .on("brushstart", function() {
            // remove any highlighting
            highlighted = []
            // select a point if we click without extent
            var pos = d3.mouse(this)
            var found = nearestPoint(nodes, pos, self.x, self.y)
            if (found) {
                if (_.indexOf(selected, found.i) == -1) {
                    selected.push(found.i)
                } else {
                    _.remove(selected, function(d) {return d == found.i})
                }
                redraw();
            }
        })
        .on("brush", function() {
            var extent = d3.event.target.extent();
            if (Math.abs(extent[0][0] - extent[1][0]) > 0 & Math.abs(extent[0][1] - extent[1][1]) > 0) {
                selected = []
                var x = self.x
                var y = self.y
                _.forEach(nodes, function(n) {
                    var cond1 = (x(n.x) > x(extent[0][0]) & x(n.x) < x(extent[1][0]))
                    var cond2 = (y(n.y) > y(extent[0][1]) & y(n.y) < y(extent[1][1]))
                    if (cond1 & cond2) {
                        selected.push(n.i)
                    }
                })
                redraw();
            }
        })
        .on("brushend", function() {
            getUserData()
            d3.event.target.clear();
            d3.select(this).call(d3.event.target);
        })

    function zoomed() {
        redraw();
    }

    _.map(nodes, function(d) {
        d.s = d.s ? d.s : self.defaultSize
        d.cfill = d.c ? d.c : self.defaultFill
        d.cstroke = d.c ? d.c.darker(0.75) : self.defaultStroke
        return d
    })

    // array indicating links
    var linkedByIndex = {};
    var i
    for (i = 0; i < nodes.length; i++) {
        linkedByIndex[i + ',' + i] = 1;
    };
    links.forEach(function (d) {
        linkedByIndex[d.source + ',' + d.target] = 1;
    });

    // look up neighbor pairs
    function neighboring(a, b) {
        return linkedByIndex[a.index + ',' + b.index];
    }

    var force = d3.layout.force()
        .size([width, height])
        .charge(-120)
        .linkDistance(30)    
        .nodes(nodes)
        .links(links)

    var brushrect = container
        .append('svg:svg')
        .attr('class', 'force-plot brush-container')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
    .append("g")
        .attr('class', 'brush')
        .call(brush)

    d3.selectAll('.brush .background')
        .style('cursor', 'default')
    d3.selectAll('.brush')
        .style('pointer-events', 'none')

    d3.select(selector).attr("tabindex", -1)

    d3.select(selector).on("keydown", function() {
        shiftKey = d3.event.shiftKey;
        if (shiftKey) {
            d3.selectAll('.brush').style('pointer-events', 'all')
            d3.selectAll('.brush .background').style('cursor', 'crosshair')
        }
    });

    d3.select(selector).on("keyup", function() {
        if (shiftKey) {
            d3.selectAll('.brush').style('pointer-events', 'none')
            d3.selectAll('.brush .background').style('cursor', 'default')
        }
        shiftKey = false
    });

    function getUserData() {

        utils.sendCommMessage(self, 'selection', selected);
        utils.updateSettings(self, {
            selected: selected
        }, function(err) {
            if(err) {
                console.log('err saving user data');
            }
        });
    }

    function redraw() {
        canvas.clearRect(0, 0, width + margin.left + margin.right, height + margin.top + margin.bottom);
        draw()
    }

    function draw() {

        _.forEach(links, function(l) {
            var alpha
            if (selected.length > 0) {
                if (_.indexOf(selected, l.source.index) > -1 & _.indexOf(selected, l.target.index) > -1) {
                    alpha = 0.9
                } else {
                    alpha = 0.05
                }
            } 
            if (highlighted.length > 0) {
                if (_.indexOf(highlighted, l.source.index) > -1 | _.indexOf(highlighted, l.target.index) > -1) {
                    alpha = 0.9
                } else {
                    alpha = 0.05
                }
            } 
            if (selected.length == 0 & highlighted.length == 0) {
                alpha = linkStrokeOpacity
            }
            canvas.strokeStyle = utils.buildRGBA(linkStrokeColor, alpha);
            canvas.lineWidth = 1 * Math.sqrt(l.value);
            canvas.lineJoin = 'round';
            canvas.beginPath();
            canvas.moveTo(self.x(l.source.x), self.y(l.source.y))
            canvas.lineTo(self.x(l.target.x), self.y(l.target.y));
            canvas.stroke()

        })

        _.forEach(nodes, function(n) {
            var alpha, stroke;
            if (selected.length > 0) {
                if (_.indexOf(selected, n.i) >= 0) {
                    alpha = 0.9
                } else {
                    alpha = 0.1
                }
            } else {
                alpha = 0.9
            }
            if (highlighted.length > 0) {
                if (neighboring(nodes[highlighted[0]], n) | neighboring(n, nodes[highlighted[0]])) {
                    alpha = 0.9
                } else {
                    alpha = 0.1
                }
            }
            if (_.indexOf(highlighted, n.i) >= 0) {
                stroke = "black"
            } else {
                stroke = n.cstroke
            }
            canvas.beginPath();
            canvas.arc(self.x(n.x), self.y(n.y), n.s, 0, 2 * Math.PI, false);
            canvas.fillStyle = utils.buildRGBA(n.cfill, alpha)
            canvas.lineWidth = strokeWidth
            canvas.strokeStyle = utils.buildRGBA(stroke, alpha)
            canvas.fill()
            canvas.stroke()
        })

    }

    setTimeout(function() {

        force.start();
        for (var i = nodes.length * nodes.length; i > 0; --i) force.tick();
        force.stop();

        draw();

        loading.style('fill', 'white');

    }, 10);

};
Ejemplo n.º 17
0
const render = (json) => {
  var width = 960,
    height = 600;

  d3.select("#host").selectAll("*").remove();

  var fill = d3.scale.category10();

  var nodes = json.map(function (d, i) {
    var status;
    if (d.OfferStatus) {
      status = d.OfferStatus.SystemName
    } else {
      status = d.RoleStatus.SystemName;
    }
    return {
      index: i,
      status: status,
      prop: d
    };
  });

  var force = d3.layout.force()
    .nodes(nodes)
    .size([width, height])
    .on("tick", tick)
    .start();

  var svg = d3.select("#host").append("svg")
    .attr("width", width)
    .attr("height", height);

  var node = svg.selectAll(".node")
    .data(nodes)
    .enter().append("circle")
    .attr("class", "node")
    .attr("cx", function (d) { return d.x; })
    .attr("cy", function (d) { return d.y; })
    .attr("r", function (d, i) {
      return d.prop.AskingPrice.PriceValue / 100000 + 6;
    })
    .style("fill", function (d, i) {
      switch (d.status) {
        case "Valued":
          return "#f2bd72";
        case "InstructionToSell":
          return "#33cc99"
        case "OfferAccepted":
          return "#da2c01"
        default:
          return "#385595";
      }
    })
    .style("stroke", function (d, i) { return d3.rgb(fill(i & 3)).darker(2); })
    .call(force.drag)
    .on("mousedown", function () { d3.event.stopPropagation(); });

  svg.style("opacity", 1e-6)
    .transition()
    .duration(1000)
    .style("opacity", 1);

  function tick(e) {


    if (grouped) {
      var k = 6 * e.alpha;
      nodes.forEach(function (o, i) {
        o.y += o.status === "Valued" ? k : -k;
        o.x += o.status === "InstructionToSell" ? k : -k;
        o.x += o.status === "OfferAccepted" ? k : -k;
      });
    }

    node.attr("cx", function (d) { return d.x; })
      .attr("cy", function (d) { return d.y; });
  }

}
Ejemplo n.º 18
0
var d3 = require('d3');
var width = window.innerWidth,
    height = window.innerHeight,
    c = {y:height/2, x: width/2};

var rootEl, svg, node, nodes, inited;

var nodesOut = [];

var force = d3.layout.force()
    // .nodes(nodes)
    .links([])
    .charge(-0.5)
    .gravity(0)
    .theta(0.99)
    .size([width, height])
    .on("tick", tick);

var forceOut = d3.layout.force()
    .nodes(nodesOut)
    .links([])
    .charge(-1)
    .gravity(-0.1)
    .size([width,height])
    .on('tick', tickOut);

function visualisation(el, maxValue) {
    rootEl = el;
    init(maxValue); // ?
    return update;
  render(users) {
    const width = 1000;
    const height = 700;
    const radius = 15;

    const vis = d3
      .select(this.containerElement)
      .append('svg')
      .attr('width', width)
      .attr('height', height);

    const links = [];

    users.forEach((user, userIndex) => {
      if (user.manager) {
        const manager = users.find(x => x.id === user.manager.id);

        if (manager) {
          const managerIndex = users.findIndex(x => x.id === manager.id);

          links.push({
            source: userIndex,
            target: managerIndex
          });
        } else {
          // eslint-disable-next-line no-console
          console.log(`Missing manager for ${user.displayName} (${user.id}) in data.`);
        }
      }
    });

    const link = vis.selectAll('line')
      .data(links)
      .enter().append('line');

    const node = vis.selectAll('.node')
      .data(users)
      .enter().append('g')
      .attr('class', 'node')
      .on('mouseover', d => this.onNodeMouseOver(d));

    node.append('circle')
      .attr('r', d => {
        d.radiusMultiplier = 1;

        if (!d.manager) {
          d.radiusMultiplier = 1.6;
        } else {
          const atLeastOneDirectReport = users.some(x => x.manager && x.manager.id === d.id);

          const manager = users.find(x => x.id === d.manager.id);

          if (!manager.manager && atLeastOneDirectReport) {
            d.radiusMultiplier = 1.5;
          } else if (atLeastOneDirectReport) {
            d.radiusMultiplier = 1.2;
          }
        }

        return radius * d.radiusMultiplier;
      });

    this.updateGrouping();
    Array.from(document.querySelectorAll('#js-group-by-container input'))
      .forEach(x => (x.onclick = () => this.updateGrouping()));

    node.append('text')
      .attr('text-anchor', 'middle')
      .attr('class', 'circle-text')
      .text(x => this.getNameAbbreviation(x.displayName));

    const circleImageStrokeBorderPx = 4;

    node.append('image')
      .attr('class', 'circle-image')
      .attr('xlink:href', d => this.imageRetriever.getImageUrl(d.email))
      .attr('x', d => radius * d.radiusMultiplier / 2 + circleImageStrokeBorderPx)
      .attr('y', d => radius * d.radiusMultiplier / 2 + circleImageStrokeBorderPx)
      .attr('width', d => radius * 2 * d.radiusMultiplier - circleImageStrokeBorderPx * 2)
      .attr('height', d => radius * 2 * d.radiusMultiplier - circleImageStrokeBorderPx * 2);

    const force = d3.layout.force()
      .nodes(users)
      .links(links)
      .size([width, height])
      .linkDistance(30)
      .charge(-400)
      .gravity(0.3)
      .start();

    node.call(force.drag);

    force.on('tick', () => {
      link.attr('x1', d => d.source.x)
          .attr('y1', d => d.source.y)
          .attr('x2', d => d.target.x)
          .attr('y2', d => d.target.y);

      d3.selectAll('circle')
          .attr('cx', d => Math.max(radius, Math.min(width - radius, d.x)))
          .attr('cy', d => Math.max(radius, Math.min(height - radius, d.y)));

      d3.selectAll('.circle-text')
        .attr('x', d => Math.max(radius, Math.min(width - radius, d.x)))
        .attr('y', d => Math.max(radius, Math.min(height - radius, d.y)) + 5);

      d3.selectAll('.circle-image')
        .attr('x', d => Math.max(radius, Math.min(width - radius, d.x))
          - radius * d.radiusMultiplier
          + circleImageStrokeBorderPx)
        .attr('y', d => Math.max(radius, Math.min(height - radius, d.y))
          - radius * d.radiusMultiplier
          + circleImageStrokeBorderPx);
    });
  }
Ejemplo n.º 20
0
    d3.json(slice.jsonEndpoint(), function (error, json) {
      const linkLength = json.form_data.link_length || 200;
      const charge = json.form_data.charge || -500;

      if (error !== null) {
        slice.error(error.responseText, error);
        return;
      }
      const links = json.data;
      const nodes = {};
      // Compute the distinct nodes from the links.
      links.forEach(function (link) {
        link.source = nodes[link.source] || (nodes[link.source] = {
          name: link.source,
        });
        link.target = nodes[link.target] || (nodes[link.target] = {
          name: link.target,
        });
        link.value = Number(link.value);

        const targetName = link.target.name;
        const sourceName = link.source.name;

        if (nodes[targetName].total === undefined) {
          nodes[targetName].total = link.value;
        }
        if (nodes[sourceName].total === undefined) {
          nodes[sourceName].total = 0;
        }
        if (nodes[targetName].max === undefined) {
          nodes[targetName].max = 0;
        }
        if (link.value > nodes[targetName].max) {
          nodes[targetName].max = link.value;
        }
        if (nodes[targetName].min === undefined) {
          nodes[targetName].min = 0;
        }
        if (link.value > nodes[targetName].min) {
          nodes[targetName].min = link.value;
        }

        nodes[targetName].total += link.value;
      });

      /* eslint-disable no-use-before-define */
      // add the curvy lines
      function tick() {
        path.attr('d', function (d) {
          const dx = d.target.x - d.source.x;
          const dy = d.target.y - d.source.y;
          const dr = Math.sqrt(dx * dx + dy * dy);
          return (
            'M' +
            d.source.x + ',' +
            d.source.y + 'A' +
            dr + ',' + dr + ' 0 0,1 ' +
            d.target.x + ',' +
            d.target.y
          );
        });

        node.attr('transform', function (d) {
          return 'translate(' + d.x + ',' + d.y + ')';
        });
      }
      /* eslint-enable no-use-before-define */

      const force = d3.layout.force()
      .nodes(d3.values(nodes))
      .links(links)
      .size([width, height])
      .linkDistance(linkLength)
      .charge(charge)
      .on('tick', tick)
      .start();

      const svg = div.append('svg')
      .attr('width', width)
      .attr('height', height);

      // build the arrow.
      svg.append('svg:defs').selectAll('marker')
      .data(['end']) // Different link/path types can be defined here
      .enter()
      .append('svg:marker') // This section adds in the arrows
      .attr('id', String)
      .attr('viewBox', '0 -5 10 10')
      .attr('refX', 15)
      .attr('refY', -1.5)
      .attr('markerWidth', 6)
      .attr('markerHeight', 6)
      .attr('orient', 'auto')
      .append('svg:path')
      .attr('d', 'M0,-5L10,0L0,5');

      const edgeScale = d3.scale.linear()
      .range([0.1, 0.5]);
      // add the links and the arrows
      const path = svg.append('svg:g').selectAll('path')
      .data(force.links())
      .enter()
      .append('svg:path')
      .attr('class', 'link')
      .style('opacity', function (d) {
        return edgeScale(d.value / d.target.max);
      })
      .attr('marker-end', 'url(#end)');

      // define the nodes
      const node = svg.selectAll('.node')
      .data(force.nodes())
      .enter()
      .append('g')
      .attr('class', 'node')
      .on('mouseenter', function () {
        d3.select(this)
        .select('circle')
        .transition()
        .style('stroke-width', 5);

        d3.select(this)
        .select('text')
        .transition()
        .style('font-size', 25);
      })
      .on('mouseleave', function () {
        d3.select(this)
        .select('circle')
        .transition()
        .style('stroke-width', 1.5);
        d3.select(this)
        .select('text')
        .transition()
        .style('font-size', 12);
      })
      .call(force.drag);

      // add the nodes
      const ext = d3.extent(d3.values(nodes), function (d) {
        return Math.sqrt(d.total);
      });
      const circleScale = d3.scale.linear()
      .domain(ext)
      .range([3, 30]);

      node.append('circle')
      .attr('r', function (d) {
        return circleScale(Math.sqrt(d.total));
      });

      // add the text
      node.append('text')
      .attr('x', 6)
      .attr('dy', '.35em')
      .text(function (d) {
        return d.name;
      });


      slice.done(json);
    });
Ejemplo n.º 21
0
function collision(){
  var width = 960,
      height = 500;

  var nodes = d3.range(200).map(function() { return {radius: Math.random() * 12 + 4}; }),
      root = nodes[0],
      color = d3.scale.category10();

  root.radius = 0;
  root.fixed = true;

  var force = d3.layout.force()
      .gravity(0.05)
      .charge(function(d, i) { return i ? 0 : -2000; })
      .nodes(nodes)
      .size([width, height]);

  force.start();

  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);

  svg.selectAll("circle")
      .data(nodes.slice(1))
    .enter().append("circle")
      .attr("r", function(d) { return d.radius; })
      .style("fill", function(d, i) { return color(i % 3); });

  force.on("tick", function(e) {
    var q = d3.geom.quadtree(nodes),
        i = 0,
        n = nodes.length;

    while (++i < n) q.visit(collide(nodes[i]));

    svg.selectAll("circle")
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  });

  svg.on("mousemove", function() {
    var p1 = d3.mouse(this);
    root.px = p1[0];
    root.py = p1[1];
    force.resume();
  });

  function collide(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 * .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;
    };
  }
}
Ejemplo n.º 22
0
module.exports = () => {
  const svg = d3.select('#d3container').append('svg')
    .attr('width', width)
    .attr('height', height);

  let chartData = {
    nodes: [{
      name: 'bot',
      r: 5,
      color: '#999',
      alpha: 1,
    }],
    links: [],
  };

  let force = d3.layout.force()
      .charge(-250)
      .linkDistance(40)
      .nodes(chartData.nodes)
      .links(chartData.links)
      .size([width, height])
      .start();

  const update = () => {
    const nodes = svg.selectAll('.bubble')
        .data(chartData.nodes);

    const links = svg.selectAll('.link')
        .data(chartData.links);

    const text = svg.selectAll('.label')
        .data(chartData.nodes);

    links.enter().append('line')
        .attr('class', 'link')
        .style('stroke-width', '10');

    nodes.enter().append('circle')
        .attr('class', 'bubble')
        .style('position', 'absolute')
        .attr('r', d => Math.sqrt(d.r * 100))
        .style('fill', d => {
          if (d.color) {
            return d.color;
          } else {
            return 'red';
          } })
        .style('fill-opacity', d => d.alpha)
        .call(force.drag);

    text.enter().append('text')
        .attr('class', 'label')
        .attr('x', d => d.x)
        .attr('y', d => d.y)
        .text(d => d.name)
        .call(force.drag);

    links.exit().remove();
    nodes.exit().remove();
    text.exit().remove();

    links.attr('x1', d => d.source.x)
        .attr('y1', d => d.source.y)
        .attr('x2', d => d.target.x)
        .attr('y2', d => d.target.y)
        .style('stroke-width', '5')
        .style('stroke', '#999')
        .style('stroke-opacity', '.6');

    nodes.attr('cx', d => d.x)
        .attr('cy', d => d.y)
        .attr('r', d => Math.sqrt(d.r * 100));

    text.attr('x', d => d.x)
        .attr('y', d => d.y);
  };

  d3.timer(update);

  return tax => {
    force.stop();
    chartData = taxUpdate(tax, chartData);
    force.start();
  };
};
Ejemplo n.º 23
0
ns.update = function (el, state, props, dispatcher) {
  if (_.isEmpty(state.reactions)) {
    return
  }

  // TODO 2nd update (componentDidUpdate) don't work
  var nodes = getReactionsWithRatio(state.reactions)

  var node = d3.select(el).select('svg').selectAll('.node')
    .data(nodes)
    .enter().append('g')
    .attr('class', 'node')

  var sizeByCount = (d) => (
    Math.sqrt(Math.max(d.ratio / d.ratio_total, 0.05)) * 150
  )

  function tick (e) {
    // Push different nodes in different directions for clustering.

    images.attr('x', function (d) { return d.x })
      .attr('y', function (d) { return d.y })

    labels.attr('x', function (d) { return d.x })
      .attr('y', function (d) { return d.y })
  }

  // TODO tune the charge
  // http://stackoverflow.com/questions/9901565/charge-based-on-size-d3-force-layout
  let k = this.k(nodes.length, props.width, props.height)
  var force = d3.layout.force()
    .nodes(nodes)
    .gravity(0.4)
    .charge(-1700)
    .size([props.width, props.height])
    .on('tick', tick)
    .start()

  // labels before images for svg z-index
  let labels = node
    .append('text')
    .attr('dx', 1)
    .attr('dy', 1)
    .text(function (d) { return (d.ratio * 100).toFixed(0) + '%' })

  var images = node.append('image')
    .attr('xlink:href', (d) => getReactionImageUrl(d.type))
    .attr('x', function (d) { return d.x })
    .attr('y', function (d) { return d.y })
    .attr('width', sizeByCount)
    .attr('height', sizeByCount)

    // .style("fill", function(d, i) { return fill(i & 3); })
    // .style("stroke", function(d, i) { return d3.rgb(fill(i & 3)).darker(2); })
    .call(force.drag)
    .on('mousedown', function () { d3.event.stopPropagation() })

  var like = d3.select(el).select('svg')
    .append('image')
    .attr('xlink:href', (d) => getReactionImageUrl('LIKE'))
    .attr('x', 360)
    .attr('y', 370)
    .attr('width', 30)
    .attr('height', 30)
    .call(force.drag)
    .on('mousedown', function () { d3.event.stopPropagation() })

  var likeRatio = (state.reactions['LIKE'] / _.sum(_.values(state.reactions)) * 100).toFixed(0)
  d3.select(el).select('svg')
    .append('text')
    .attr('x', 400)
    .attr('y', 390)
    .text(likeRatio + '%')
    // state.reactions['LIKE'] + ' - ' +

  // namespace otherwise as will replace as the only listener
  // http://stackoverflow.com/questions/14749182/how-to-register-multiple-external-listeners-to-the-same-selection-in-d3
  if (!isMobile()) {
    d3.select(window).on('resize.' + props.id, ns._resize.bind(null, el, nodes, props, force))
  }

  d3.select(el)
    .on('mousedown', this._mousedown(nodes, force))
// var scales = this._scales(el, state.domain)
// var prevScales = this._scales(el, state.prevDomain)
// this._drawPoints(el, scales, state.data, prevScales, dispatcher)
// this._drawTooltips(el, scales, state.tooltips, prevScales)
}
Ejemplo n.º 24
0
        var SvgGraph = function (nodes, links, container) {

            /**
             * The external api (hoisted)
             * 
             * @type {Object}
             */
            var _this = null;

            /**
             * The svg container
             * 
             * @type {[Element]}
             */
            container = 
                d3.select(container)
                    .append("svg:svg")
                    .attr({ "width": "100%", "height": "100%" });

            /**
             * The svg group ( zoomable capable )
             * 
             * @type {[Element]}
             */
            var svg = container
                .append("svg:g")
                .attr({ "width": "100%", "height": "100%" });

            // disable doube click zoom
            svg.on("dblclick.zoom", null);

            /**
             * The viwport
             * 
             * @type {Viewport}
             */
            var viewport = Viewport(container);

            /**
             * Currently dragging over
             * 
             */
            var draggingOverTimeout = null,
                draggingOver        = null;


            /**
             * The D3 layout
             * 
             * @type {D3.Layout}
             */
            var layout = 
                d3.layout.force()
                    .size([500, 500])
                    .nodes(nodes)
                    .links(links)
                    .linkDistance(50);
            

            /**
             * The node/link elements
             * 
             */
            var node = svg.selectAll(".node"),
                link = svg.selectAll(".link"),
                text = svg.selectAll(".text");


            /**
             * Updates the rendered node/links elements
             * 
             */
            var render = function(){

                link = link.data(links, function(d) { return d.source.id + "-" + d.target.id; });
                link.enter()
                    .insert("line", ".node")
                    .attr("class", "link")
                    .attr("x1", function(d) { return d.source.x; })
                    .attr("y1", function(d) { return d.source.y; })
                    .attr("x2", function(d) { return d.target.x; })
                    .attr("y2", function(d) { return d.target.y; })
                    .attr("data-from", function(d) { return d.source.id; })
                    .attr("data-to", function(d) { return d.target.id; });

                /// remove not existing items
                link.exit().remove();

                node = node.data(nodes, function(d) { return d.id;});
                node.enter()
                    .append("circle")
                    .attr("class", function(d) { return "node " + d.id; })
                    .attr("r", 20)
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; })
                    
                    // click event
                    .on("click", function (d) {

                        d3.event.preventDefault();
                        d3.event.stopPropagation();
                        
                        _this.emitEvent("selected", [this, d]);

                    })

                    // hover events
                    .on("mouseover", function(d){
                        
                        /// manage the current dragging item
                        /* jshint -W041 */
                        if(draggingOverTimeout != null) clearTimeout(draggingOverTimeout);
                        draggingOver = d;

                        _this.emitEvent("mouseover", [this, d]);

                    })
                    .on("mouseout", function (d) {
                        
                        // reset the debounced timeout to set dragging over to null
                        draggingOverTimeout = setTimeout(function(){ 
                            draggingOver = null; 
                        }, 300);

                        _this.emitEvent("mouseout", [this, d]);

                    });

                /// remove not existing nodes
                node.exit().remove();

                text = text.data(nodes, function(d) { return d.id;});
                text.enter()
                    .append("text")
                    .attr("class", "text")
                    .attr("x", function(d) { return d.x; })
                    .attr("y", function(d) { return d.y; })
                    .attr("text-anchor", "left");

                text.exit().remove();


                // execute animation to re-position elements
                layout.start();
                layout.tick();
                layout.stop();
                
            };


            /**
             * On simulation tick update the nodes positions
             * 
             */
            layout.on("tick", function(e) {
                
                link
                    .transition()
                    .duration(50)
                    .ease(d3.ease("linear"))
                    .attr("x1", function(d) { return d.source.x; })
                    .attr("y1", function(d) { return d.source.y; })
                    .attr("x2", function(d) { return d.target.x; })
                    .attr("y2", function(d) { return d.target.y; });

                /// Update the 
                node
                    .transition()
                    .duration(50)
                    .ease(d3.ease("linear"))
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; })
                    .attr("class", function(d) { 
                        return $(this).attr("class") + " " + d.class; 
                    });

                text
                    .transition()
                    .duration(50)
                    .ease(d3.ease("linear"))
                    .attr("x", function(d) { 
                        var x = d.x - 40;
                        if(!d.children.length){
                            x = d.x + 35;
                        } 
                        return x; 
                    })
                    .attr("y", function(d) { 
                        var y = d.y - 35;
                        if(!d.children.length){
                            y = d.y + 5;
                        } 
                        return y; 
                    })
                    .text(function(d){ return d.text || ""; });
                   
            });

            
            /**
             * External API
             * 
             * @type {Object}
             * 
             */
            _this = {
                
                /**
                 * Renders the graph
                 * 
                 * @type {Function}
                 */
                render: render,

                /**
                 * Dragging over
                 * 
                 * @type {Object}
                 * 
                 */
                draggingOver: function(){
                    return draggingOver;
                },

                /**
                 * Reset
                 * 
                 * @return {[type]} [description]
                 */
                reset: function(){

                    /*link.remove();
                    node.remove();
                    text.remove();*/

                    _.remove(nodes);
                    _.remove(links);

                }

            };

            // initialize this instance as an EventEmitter
            OOP.super(_this, EventEmitter);
            OOP.inherit(_this, EventEmitter.prototype);

            // extend from behaviour
            _.assign(_this, viewport);

            return _this;

        };
Ejemplo n.º 25
0
    {
      url: require("data/NetworkGraph/nodes_company.csv"),
      rowParser: ({ id, name, logo, logoAspectRatio, relations }) =>
        ({ id, name, logo, logoAspectRatio: +logoAspectRatio, relations: +relations, type: "company" })
    }
  ],
  links: [
    {
      url: require("data/NetworkGraph/links_person_company.csv"),
      rowParser: ({ person, company, title, type }) =>
        ({ source: person, target: company, title, type })
    }
  ]
};

const force = d3.layout.force();
const rawData = { nodes: [], links: [] };

function createPromise(src) {
  if (typeof src.nodes === "undefined" || !Array.isArray(src.nodes) ||
      typeof src.links === "undefined" || !Array.isArray(src.links)) {
    throw new TypeError("loadCSV() called with wrong argument type");
  }
  const nodeRequests = src.nodes.map(obj =>
    new Promise((resolve, reject) => {
      d3.csv(obj.url).row(obj.rowParser).get((error, rows) => {
        if (error) reject(error); else resolve({ type: "node", data: rows });
      });
    }));
  const linkRequests = src.links.map(obj =>
    new Promise((resolve, reject) => {
Ejemplo n.º 26
0
  setupD3(function(d3, parent) {
    var svg = d3.select(parent).append("svg:svg"),
        width = 1200,
        height = 800;

    var force = d3.layout.force()
      .charge(-40)
      .linkDistance(20)
      .gravity(0.3)
      .size([width/2, height/2]); // just to be sure it fits

    svg.attr("width", width)
       .attr("height", height);

    var nodes = [],
        links = [],
        nodes_set = {},
        nodes_idx = {};

    // deduplicate nodes
    _.each(data, function(movies, user) {
      nodes_set[user] = -1;
      _.each(movies, function(movie) { nodes_set[movie] = -1; });
    });

    _.each(nodes_set, function(_, id) {
      var l = nodes.push({
        id: id,
        name: id,
        is_movie: id[0] == "m",
      });

      // store the index
      nodes_set[id] = l-1;
    });

    _.each(data, function(movies, user) {
      _.each(movies, function(movie) {
        var idx1 = nodes_set[user],
            idx2 = nodes_set[movie];

        links.push({source: idx1, target: idx2, weight: 1});
      });
    });

    force.nodes(nodes)
         .links(links);

    force.start()

    var maxTicks = 600;
    for (var i=0; i<maxTicks; i++) {
      // console.log("tick", i, "out of", maxTicks);
      force.tick();
    }

    force.stop()

    /*
    svg.selectAll(".link")
      .data(links)
      .enter().append("line")
        .attr("class", "link")
        .style("stroke", "#AAA")
        .attr("x1", function(d) { return d.source.x; })
        .attr("y1", function(d) { return d.source.y; })
        .attr("x2", function(d) { return d.target.x; })
        .attr("y2", function(d) { return d.target.y; });
    // */

    svg.selectAll(".node")
      .data(nodes)
      .enter().append("circle")
        .attr("class", "node")
        .attr("r", function(d) { return d.is_movie ? 3 : 3 })
        .style("fill", function(d) {
          return d.is_movie ? "blue" : "green"; // experimental
        })
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });

    res.writeHead(200, {"Content-Type": "image/svg+xml"});
    res.end(parent.innerHTML);
  });
Ejemplo n.º 27
0
  render: function() {
    var self = this;

    this.init();
    
    function circleRadius(d) { return self.radiusScale(self.getSize(d) || 1); }

    var force = this.force = d3.layout.force()
      .nodes(this.nodes)
      .links(this.links)
      .size([this.opts.width, this.opts.height])
      .linkDistance(defaults.linkDistance)
      .charge(defaults.graphCharge)
      .gravity(defaults.gravity)
      .on("tick", tick)
      .start();

    this.d3Path = this.parent.append("svg:g").selectAll("path")
      .data(force.links())
      .enter().append("svg:path")
      .attr("stroke", bind(this, this.pathStroke))
      .attr("stroke-width", PATH_STROKE_WIDTH)
      .attr("fill", "none");
    
    var node = this.d3Nodes = this.parent.selectAll(".node")
      .data(force.nodes())
      .enter().append("g")
      .attr("class", "node")
      .on("mouseover", bind(this, this.onMouseOver))
      .on("mouseout", bind(this, this.onMouseOut))
      .on("click", bind(this, this.onCircleClick));

    this.d3Circles = node.append("circle")
      .style("fill", bind(this, this.getClusterColor))
      .attr("r", circleRadius)

    this.d3TitleNodes = node.append("text")
      .attr("text-anchor", "middle")
      .attr("dy", ".35em")
      .style("display", "none")
      .text(function(d) { return self.getText(d); });

    function tick(e) {
      //var progress = Math.round((1 - (e.alpha * 10 - 0.1)) * 100);

      if (force.alpha() < defaults.forceAlphaLimit) {
        self.handleCollisions();
        
        // to prevent the chart from moving after
        force.stop();

        self.updateNodesPosition();
        self.updateLinksPosition();

        // center the graph
        self._center();

        // showing canvas after finished rendering
        self.show();

        self.refreshZoom();
        self.emit("rendered");
      }
    }
    
    if (this.hasUnappliedFilters() || this.hasUnappliedFocus()) { 
      this.update();
    }

    return this;
  },
/**
 *  Draw network view
 **/
function draw(selectedEdgeId, sourceIpNodeId, targetIpNodeId, data) {
  //Get the nodes from the data
  var data = this.state.data;

  var nodes = data.map(function (d) {
    return { ip: d.srcIP, isInternal: +d.srcIpInternal };
  })

  var nodes_2 = data.map(function (d) {
    return { ip: d.dstIP, isInternal: +d.destIpInternal };
  });

  nodes = getUniqueNodes(nodes.concat(nodes_2));

  // Get the edges from the data
  var edges = data.map(function (d) {
    var fSrc = -1, fDst = -1, i, n;

    // Find indexes for srcIP and dstIP in nodes array
    for (i=0, n=nodes.length ; i<n ; i++)
    {
      // Is this srcIP?
      if (nodes[i].ip == d.srcIP) fSrc = i;
      // Is this dstIP?
      if (nodes[i].ip == d.dstIP) fDst = i;

      // Stop looking as soon as we find both indexes
      if (fSrc>=0 && fDst>=0) break;
    }

    return {
      source: fSrc,
      target: fDst,
      weight: -Math.log(d.lda_score),
      id: "k" + d.srcIP.replace(/\./g, "_") + "-" + d.dstIP.replace(/\./g, "_")
    };
  });

  // Update the degree in the edges if the edge is a suspect
  edges.forEach(function (d) {
    nodes[d.source].degree = nodes[d.source].degree + 1 || 1;
    nodes[d.target].degree = nodes[d.target].degree + 1 || 1;
  });

  // define an opacity function
  var opacity = d3.scale.threshold()
                                    .domain([13])
                                    .range([0.1, 1]);

  // Color for edges
  var color = d3.scale.linear()
                                .domain([16, 13, 12, 2])
                                .range([d3.hsl(214, 0.04, 0.34), d3.hsl(216, 0.02, 0.59), d3.hsl(216, 0.69, 0.84), d3.hsl(201, 0.1, 0.72)])
                                .interpolate(d3Interpolate.interpolateCubehelix);

  // Graph dimensions
  var w = $(this.getDOMNode()).width(),
      h = $(this.getDOMNode()).height(),
      r = Math.round(w * 0.005), // 0.005 magic number for nodes styling purposes when expanding graph, radious is 0.5% of the #grap div
      rightMargin = w - r,
      bottomMargin = h - r,
      size = [w, h];

  //Main SVG container
  d3.select(this.getDOMNode()).select('svg').remove();

  var svg = d3.select(this.getDOMNode())
                .append('svg')
                    .attr('width', w)
                    .attr('height', h)
                .append('g');

  // Graph force
  var force = d3.layout.force()
                .linkDistance(70)
                .charge(-120)
                .chargeDistance(-Math.round(h * 0.55)) // 0.55 is a magic number for graph styling purposes charge is 55% of the grap height
                .size(size)
                .nodes(nodes)
                .links(edges);

  // Group and append the edges to the main SVG
  svg.append('g')
       .selectAll('.edge')
       .data(edges)
       .enter()
            .append('line')
            .classed('edge', true)
            .attr("id", function (d) { return d.id; })
            .style('stroke', function (d) { return color(d.weight); })
            .style('stroke-opacity', function (d) { return opacity(d.weight); });

  var edge = svg.selectAll('.edge');

  // Tooltip generator
  var tooltip = d3.select(this.getDOMNode())
                    .append("div")
                    .classed('node-label', true);

  // GROUP and append the nodes to the main SVG

  var node = svg.append('g')
                 .selectAll('.node')
                 .data(nodes.filter(function (d) { return d.degree > 0; }))
                 .data(nodes)
                 .enter()
                   .append('path')
                   .classed('node', true)
                   .attr("id", function (d) { return "n" + d.ip.replace(/\./g, "_"); })
                   .attr("d", d3.svg.symbol()
                        .size(function (d) { return (d.degree + r) * 20; })
                        .type(function (d) {
                            if (d.isInternal == 1)
                                return "diamond";
                            else
                                return "circle";
                        }))
                   .attr('fill', function (d) {
                       if (d.isInternal == 1)
                           return "#0071C5";
                       else
                           return "#fdb813";
                   })
                   .call(force.drag)
                   .on('mouseover', function (d) {
                       tooltip.html(d.ip + '<br/> <small class="text-muted">Right click to apply IP filter</small>')
                             .style('visibility', 'visible');
                   })
                   .on('mousemove', function (d) {
                      tooltip.style('top', d3.event.layerY + 'px');

                      if ((w*.5) > d3.event.layerX)
                      {
                        // Show tooltip to the right
                        tooltip.style('left', (d3.event.layerX + 20) + 'px');
                      }
                      else
                      {
                        // Show tooltip to the left
                        tooltip.style('left', (d3.event.layerX - 200) + 'px');
                      }
                   })
                   .on("click", nodeClick)
                   .on("contextmenu", nodeContextualClick)
                   .on('mouseout', function () { tooltip.style('visibility', 'hidden'); });

  // set the tick event listener for the force
  force.on('tick', function () {
    edge.attr("x1", function (d) { return d.source.x; })
            .attr("y1", function (d) { return d.source.y; })
            .attr("x2", function (d) { return d.target.x; })
            .attr("y2", function (d) { return d.target.y; });

    node.attr('transform', function (d) {
            d.x = Math.max(r, Math.min(rightMargin, d.x));
            d.y = Math.max(r, Math.min(bottomMargin, d.y));
            return 'translate(' + d.x + ',' + d.y + ')';
    });
  });

  force.start();

  // if the function params are not null then that means we have a selected edge and nodes and we need to add the blink animation to them
  if (this.state.selectedEdgeId && this.state.selectedSrcNodeId && this.state.selectedDstNodeId) {
    var selectedEdge = d3.select("#" + this.state.selectedEdgeId)
               .style("stroke", "#FDB813")
               .style("stroke-opacity", "1")
               .classed("blink_me", true)
               .classed("active", true);
    var parent = $("#" + selectedEdge.attr("id")).parent()

    selectedEdge.remove();

    parent.append(selectedEdge[0]);

    d3.select("#" + this.state.selectedSrcNodeId)
        .classed("blink_me", true);

    d3.select("#" + this.state.selectedDstNodeId)
          .classed("blink_me", true);
  }
}
Ejemplo n.º 29
0
module.exports = () => {
  let width = window.innerWidth;
  const height = window.innerHeight - 100;

  const svg = d3.select('#d3container').append('svg')
    .attr('width', width)
    .attr('height', height);

  let chartData = [];

  let force = d3.layout.force()
      .gravity(0.1)
      .distance(100)
      .charge(-150)
      .nodes(chartData)
      .size([width * 0.8, height * 0.8]);

  function collide(node) {
    var r = node.r + 8,
    nx1 = (node.x + node.r) - r,
    nx2 = (node.x + node.r) + r,
    ny1 = (node.y + node.r) - r,
    ny2 = (node.y + node.r) + r;
    return function(quad, x1, y1, x2, y2) {
      if (quad.point && (quad.point !== node)) {
        var x = (node.x + node.r) - (quad.point.x + quad.point.r),
        y = (node.y + node.r) - (quad.point.y + quad.point.r),
        l = Math.sqrt(x * x + y * y),
        r = node.r + quad.point.r;
        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;
    };
  }

  force.start();

  const update = () => {
    const q = d3.geom.quadtree(chartData);
    let i = 0;
    const n = chartData.length;

    while (++i < n) {
      q.visit(collide(chartData[i]));
    }

    const charts = svg.selectAll('.bubble')
        .data(chartData)
        .call(force.drag);

    const text = svg.selectAll('.label')
        .data(chartData);

    charts.transition().duration(30)
        .attr('x', d => d.x)
        .attr('y', d => d.y);

    charts.enter().append('image')
        .attr('class', 'bubble')
        .style('position', 'absolute')
        .attr('x', d => d.x)
        .attr('y', d => d.y)
        .attr('width', d => d.r * 2)
        .attr('height', d => d.r * 2)
        .attr('xlink:href', '../assets/bubble.png');

    text.enter().append('text')
        .attr('class', 'label')
        .attr('x', d => d.x + d.r)
        .attr('y', d => d.y + d.r)
        .style('font-family', 'Arial')
        .style('text-anchor', 'middle')
        .style('fill', 'white')
        .style('font-weight', 'bold')
        .style('fill-opacity', 1)
        .style('stroke', '#000000')
        .style('stroke-width', '1px')
        .style('stroke-linecap', 'butt')
        .style('stroke-linejoin', 'miter')
        .style('stroke-opacity', 1)
        .text(d => d.text)
        .call(force.drag);

    charts.exit().remove();
    text.exit().remove();

    text.attr('x', d => d.x + d.r)
        .attr('y', d => d.y + d.r);
  };

  d3.timer(update);

  return {
    update: (keywords) => {
      force.stop();
      for (let i in keywords) {
        let found = false;
        for (let n in chartData) {
          if (keywords[i].keyword_text === chartData[n].text) {
            chartData[n].val = keywords[i]['SUM(relevance)'];
            chartData[n].r = Math.ceil(Math.sqrt(keywords[i]['SUM(relevance)'] * 1000));
            found = true;
            break;
          }
        }
        if (!found) {
          const newVal = {
            text: keywords[i].keyword_text,
            val: keywords[i]['SUM(relevance)'],
            x: Math.ceil(Math.random() * width),
            y: Math.ceil(Math.random() * height),
            r: Math.ceil(Math.sqrt(keywords[i]['SUM(relevance)'] * 1000)),
          };
          chartData.push(newVal);
        }
      }
      force.start();
    },
    resize: () => {
      force.stop();
      width = window.innerWidth;
      force.size([width * 0.8, height * 0.8]).start();
    },
  };
};
Ejemplo n.º 30
0
	componentDidMount(){

		const container = ReactDOM.findDOMNode(this);
		const canvas = container.querySelector('.filter-viz__canvas');
		const svg = d3.select(canvas);
		const width = window.innerWidth / 2;
		const height = window.innerHeight;

		this.radius = d3.scale.linear().domain([1,10]).range([30, 80]);
		this.radius2 = d3.scale.sqrt().domain([5,15]).range([40, 80]);
		this.flexScale = d3.scale.linear().domain([1,10]).range([0, window.innerHeight])
		this.personScale = d3.scale.linear().domain([5,15]).range([50, window.innerHeight])
		this.mode = 'none';

		//prepare data
		this.nodes = data.map((row) => {
			row.radius = this.radius(row.size);
			row.x = 0;
			row.y = 0;
			return row;
		});

		this.data = [ ...this.nodes ];

		//add mouse
		this.mouse = {
			name: 'mouse',
			radius: 10
		};
		this.data.push(this.mouse);

		this.force = d3.layout.force()
			.nodes(this.data)
			// .links(this.links)
			// .friction(0.9)
			.size([width, height])
			.on('tick', this.tick.bind(this))
			.start();

		this.circles = svg.selectAll('circle')
			.data(this.nodes)
			.enter()
			.append('circle')
			.attr('r', function(d){ return d.radius; })
			.style('fill', function(d){ return '#fff'; })
			.call(this.force.drag)
			// .on('mouseover', main.tooltip)
			// .on('mouseout', main.hideTooltip);
			.on('click', (d) => {
				this.props.history.push('/' + d.slug);
				this.force.resume();
			})

		this.texts = svg.selectAll('text')
			.data(this.nodes)
			.enter()
			.append('text')
			.text((d) => { return d.name });

		window.addEventListener('mousemove', (evt) => {
			this.mouse.x = evt.clientX;
			this.mouse.y = evt.clientY;
			// this.force.alpha(0.1);
		});

		window.addEventListener('resize', (evt) => {
			this.force.size([window.innerWidth/2, window.innerHeight]).resume();
		});

		window.__force = this.force;

	}