block by denisemauldin c2f7b2af3f90d17a9f83ac76596f25a2

Org Bubbles

Full Screen

Built with blockbuilder.org

forked from SpaceActuary‘s block: Group Clustering

forked from SpaceActuary‘s block: Org Bubbles

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body { 
      margin:0;
      position:fixed;
      top:0;
      right:0;
      bottom:0;
      left:0;
    	font-family: sans-serif;
    }
    .selected {
      fill: none;
    }
    
    .links line {
      stroke: #000;
      stroke-width: 3px;
    }
    
    .button {
      min-width: 130px;
      padding: 4px 5px;
      cursor: pointer;
      text-align: center;
      font-size: 13px;
      border: 1px solid #e0e0e0;
      text-decoration: none;
    }

    .button.active {
      background: #000;
      color: #fff;
    }
  </style>
</head>

<body>
  <div id="toolbar">
      <button id="all" class="button">All</button>
      <button id="Location" class="button">By Location</button>
      <button id="Org" class="button active">By Org</button>
      <button id="Type" class="button">By Type</button>
    </div>
  <script>
    console.clear()
    var w = 960, h = 500;
    
    var radius = 25;
    var color = d3.scaleOrdinal(d3.schemeCategory20);
    var centerScale = d3.scalePoint().padding(1).range([0, w]);
    var xScale = d3.scaleLinear().range([w * .2, w * .8]);
    var yScale = d3.scaleLinear().range([h * .2, h * .8]);
    var forceStrength = 0.05;
    
    var svg = d3.select("body").append("svg")
      .attr("width", w)
      .attr("height", h)

    var simulation = d3.forceSimulation()
            .force("link", d3.forceLink().id(function(d) { return d.ID; })
    																		 .strength(0))
    				.force("collide",d3.forceCollide( function(d){
              	return d.r + 8 }).iterations(16) 
            )
            .force("charge", d3.forceManyBody())
            .force("y", d3.forceY().y(h / 2))
            .force("x", d3.forceX().x(w / 2))
    
    d3.csv("data.csv", function(data){
      
      graph = {
        "nodes": data,
        "links": data.map(function(d){
                   return {source: d.ID, target: d.PID};
                 })
      };
      
      data.forEach(function(d){
        d.r = radius;
        d.x = w / 2;
        d.y = h / 2;
      })
      
      console.table(data); 
           
      var link = svg.append("g")
          .attr("class", "links")
        .selectAll("line")
        .data(graph.links)
        .enter().append("line")
          .attr("stroke-width", function(d) { return 3; });
      
      var node = svg.append("g")
          .attr("class", "nodes")
        .selectAll("circle")
        .data(graph.nodes)
        .enter().append("circle")
          .attr("r", radius)
          .style("fill", function(d, i){ return color(d.ID); })
          .style("stroke", function(d, i){ return color(d.ID); })
          .style("stroke-width", 5)
          .style("pointer-events", "all")
          .call(d3.drag()
              .on("start", dragstarted)
              .on("drag", dragged)
              .on("end", dragended));
      
      function ticked() {
        //console.log("tick")
        //console.log(data.map(function(d){ return d.x; }));
        
        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; });
        
        node
            .attr("cx", function(d){ return d.x; })
            .attr("cy", function(d){ return d.y; });
      }   

      simulation
          .nodes(graph.nodes)
          .on("tick", ticked);
      
      simulation.force("link")
      		.links(graph.links);
      
      function dragstarted(d,i) {
        //console.log("dragstarted " + i)
        if (!d3.event.active) simulation.alpha(1).restart();
        d.fx = d.x;
        d.fy = d.y;
      }

      function dragged(d,i) {
        //console.log("dragged " + i)
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      }

      function dragended(d,i) {
        //console.log("dragended " + i)
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
        var me = d3.select(this)
        console.log(me.classed("selected"))
        me.classed("selected", !me.classed("selected"))
        
        d3.selectAll("circle")
          .style("fill", function(d, i){ return color(d.ID); })
      	
        d3.selectAll("circle.selected")
          .style("fill", "none")
      	
      } 
      
      function groupBubbles() {
        hideTitles();

        link.transition().duration(500)
        	.style("stroke-opacity", 0)
        
        // @v4 Reset the 'x' force to draw the bubbles to the center.
        simulation.force('x', d3.forceX().strength(forceStrength).x(w / 2));

        // @v4 We can reset the alpha value and restart the simulation
        simulation.alpha(1).restart();
      }
      
      function splitBubbles(byVar) {
        
        centerScale.domain(data.map(function(d){ return d[byVar]; }));
        
        if(byVar == "all"){
          hideTitles()
        } else {
	        showTitles(byVar, centerScale);
        }
        
        link.transition().duration(500)
        	.style("stroke-opacity", 0)
        
        // @v4 Reset the 'x' force to draw the bubbles to their year centers
        simulation
          .force('x', d3.forceX().strength(forceStrength).x(function(d){ 
        		return centerScale(d[byVar]);
        	})).
        	force('y', d3.forceY().strength(forceStrength).y(h / 2));

        // @v4 We can reset the alpha value and restart the simulation
        simulation.alpha(2).restart();
      }
      
      function orgBubbles() {
        console.log("orgBubbles")
        
        xScale.domain(d3.extent(graph.nodes, function(d){ return +d.Position; }));
        yScale.domain(d3.extent(graph.nodes, function(d){ return +d.Level; }));
        
        link.transition().duration(2000)
        	.style("stroke-opacity", 1)
        
        // @v4 Reset the 'x' force to draw the bubbles to their year centers
        simulation
          .force('x', d3.forceX().strength(forceStrength).x(function(d){ 
        		return xScale(d.Position);
        	}))
          .force('y', d3.forceY().strength(forceStrength).y(function(d){ 
        		return yScale(d.Level);
        	}));

        // @v4 We can reset the alpha value and restart the simulation
        simulation.alpha(2).restart();
      }
      
      function hideTitles() {
        svg.selectAll('.title').remove();
      }

      function showTitles(byVar, scale) {
        // Another way to do this would be to create
        // the year texts once and then just hide them.
       	var titles = svg.selectAll('.title')
          .data(scale.domain());
        
        titles.enter().append('text')
          	.attr('class', 'title')
        	.merge(titles)
            .attr('x', function (d) { return scale(d); })
            .attr('y', 40)
            .attr('text-anchor', 'middle')
            .text(function (d) { return byVar + ' ' + d; });
        
        titles.exit().remove() 
      }
      
      function setupButtons() {
        d3.selectAll('.button')
          .on('click', function () {
          	
            // Remove active class from all buttons
            d3.selectAll('.button').classed('active', false);
            // Find the button just clicked
            var button = d3.select(this);

            // Set it as the active button
            button.classed('active', true);

            // Get the id of the button
            var buttonId = button.attr('id');

	          console.log(buttonId)
            // Toggle the bubble chart based on
            // the currently clicked button.
            if(buttonId == "Org"){
              orgBubbles()
            } else {
            	splitBubbles(buttonId);
            }
          
          });
      }
      
      setupButtons()
      orgBubbles()
      
    })
    
  </script>
</body>

data.csv

ID,PID,Level,Position,Location,Type
0,0,1,5.5,2,M
1,0,2,5.5,1,M
2,1,3,3,1,M
3,1,3,9,1,N
4,1,3,7,1,N
5,1,3,5.5,1,M
6,5,4,3,1,N
7,5,4,8,2,N
8,6,5,1,3,M
9,6,5,3,1,M
10,6,5,5,1,N
11,7,5,7,1,N
12,7,5,9,2,M