block by 1wheel 408f41a4e4c721c5e1fb

cord-links

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">

<style>
rect{
  fill-opacity: 1;
  stroke: black;
  fill: lightgrey;
  cursor: pointer;
}
text{
  pointer-events: none;
}

svg{
  overflow: visible;
  background: black;
}

body{
  margin: 0px;
}

html{
  width: 960px;
  height: 500px;
}



.place rect{
  fill: white;
}

.people text{
  font-size: 10px;
}

.places text{
  font-size: 10px;
}

.connection{
  fill: pink;
  stroke: black;
}

</style>

<body></body>

<script src="/1wheel/raw/67b47524ed8ed829d021/d3-3.5.5.js"></script>
<script src="/1wheel/raw/67b47524ed8ed829d021/lodash-3.8.0.js"></script>
<script src='/1wheel/raw/1b6758978dc2d52d3a37/d3-jetpack.js'></script>
<script src='/1wheel/raw/1b6758978dc2d52d3a37/d3-starterkit.js'></script>
<script src='/1wheel/raw/5d32ecb8a54b42f53646/geometry.js'></script>

<script src='chord-links.js'></script>

chord-links.js

var width = 960,
    height = 500,
    angle = d3.scale.linear()


var events = d3.range(10).map(function(d, i){
  return {
    i: i,
    name: randString(Math.floor(Math.random()*10) + 10),
    people: [],
    places: []
  }
})
angle.domain([0, events.length - 1]).range([-12, 12])
events.forEach(function(d, i){
  d.θ = angle(d.i)
  d.rotateCenter = P(width/2 + 700, height/2)
  d.rectWidth = 220
  d.rectHeight = 30
  d.translate = P(width/2 - 220 - 100, height/2)
})


var people = d3.range(15).map(function(d, i){
  var rv = {
    i: i,
    name: randString(Math.floor(Math.random()*5) + 5)
  }
  rv.events = events.filter(function(){ return Math.random() < .3 })
  rv.events.forEach(function(e){ e.people.push(rv) })
  return rv
})
angle.domain([0, people.length - 1]).range([-60, -3])
people.forEach(function(d, i){
  d.θ = angle(d.i)
  d.rotateCenter = P(width/2, height/2)
  d.rectWidth = 100
  d.rectHeight = 12
  d.translate = P(width/2 + 180, height/2)
})


var places = d3.range(15).map(function(d, i){
  var rv = {
    i: i,
    name: randString(Math.floor(Math.random()*5) + 5)
  }
  rv.events = events.filter(function(){ return Math.random() < .3 })
  rv.events.forEach(function(e){ e.places.push(rv) })
  return rv
})
angle.domain([0, places.length - 1]).range([3, 60])
places.forEach(function(d, i){
  d.θ = angle(d.i)
  d.rotateCenter = P(width/2, height/2)
  d.rectWidth = 100
  d.rectHeight = 12
  d.translate = P(width/2 + 180, height/2)
})


events.concat(people).concat(places).forEach(function(d){
  d.corners = d3.range(4).map(function(i){
    var x = d.translate.x + (i == 0 || i == 3 ? 0 : d.rectWidth)
    var y = d.translate.y + (i < 2            ? 0 : d.rectHeight)
    return rotatePoint({x: x, y: y}, d.rotateCenter, d.θ)
  })
})


var svg = d3.select('body')
  .append('svg')
    .attr({width: width, height: height})


var eventGs = svg.dataAppend(events, 'g.place').call(rotateTransform)

eventGs.append('rect')
    .attr({width: 220, height: 30})
    .on('mouseover', makeLeftConnections)

eventGs.append('text')
    .text(ƒ('name'))
    .attr({dy: '1.33em', dx: '.33em'})


var peopleG = svg.dataAppend(people, 'g.people').call(rotateTransform)

peopleG.append('rect')
    .attr({width: 100, height: 12})
    .on('mouseover', makeRightConnections)

peopleG.append('text')
    .text(ƒ('name'))
    .attr({dy: '1em', dx: '.33em'})


var placesG = svg.dataAppend(places, 'g.places').call(rotateTransform)

placesG.append('rect')
    .attr({width: 100, height: 12})
    .on('mouseover', makeRightConnections)

placesG.append('text')
    .text(ƒ('name'))
    .attr({dy: '1em', dx: '.33em'})



function drawConnections(connections){
  var color = randColor()

  svg.append('g').dataAppend(connections, 'path.connection')
      .style('fill', color)
      .attr('d', function(d){

        return [
        'M',  d.from.top, 
        'C',  [d.from.top.x, d.from.top.y],
              [d.from.top.x, d.from.top.y], 
              d.from.top,
        'L', d.from.bot, 
        'C',  [d.from.bot.x, d.from.bot.y],
              [d.from.bot.x, d.from.bot.y], 
              d.from.bot,
        ].join(' ')
      })
    .transition().duration(1000)
      .attr('d', function(d){
        var fSin = Math.sin(Math.PI/2 + Math.PI/180*d.from.θ)
        var fCos = Math.cos(Math.PI/2 + Math.PI/180*d.from.θ)
        var tSin = Math.sin(Math.PI/2 + Math.PI/180*d.to.θ)
        var tCos = Math.cos(Math.PI/2 + Math.PI/180*d.to.θ)

        return [
        'M',  d.to.top, 
        'C',  [d.to.top.x - tSin*100, d.to.top.y - tCos*100],
              [d.from.top.x - fSin*100, d.from.top.y - fCos*100], 
              d.from.top,
        'L', d.from.bot, 
        'C',  [d.from.bot.x - fSin*100, d.from.bot.y - fCos*100],
              [d.to.bot.x - tSin*100, d.to.bot.y - tCos*100], 
              d.to.bot,
        ].join(' ')
      })
      .each('end', function(d){
        if (!d.exiting) return d.drawing = false

        d3.select(this).transition().duration(1000)
            .call(exitConnection)
      })
}

function makeRightConnections(datum){
  exitConnections()

  var connections = datum.events.map(function(d){
    return {  from: 
              { top: datum.corners[0], 
                bot: datum.corners[3],
                θ:   -datum.θ},
              to: 
              { top: d.corners[1], 
                bot: d.corners[2],
                θ:   -d.θ + 180},
              drawing:  true,
              exiting:  false
      }
  })

  drawConnections(connections)
}

function makeLeftConnections(datum){
  exitConnections()

  var connections = datum.people.concat(datum.places).map(function(d){
    return {  from: 
              { top: datum.corners[1], 
                bot: datum.corners[2],
                θ:   -datum.θ + 180},
              to: 
              { top: d.corners[0], 
                bot: d.corners[3],
                θ:   -d.θ},
              drawing:  true,
              exiting:  false
      }
  })

  drawConnections(connections)
}




function rotateTransform(sel){
  sel.attr('transform', function(d, i){
      return 'rotate(' + d.θ + ' ' + d.rotateCenter +') ' +
             'translate(' + d.translate + ')' 
  })
}


function exitConnections(){
  svg.selectAll('.connection')
      .each(function(d){ d.exiting = true })
      .style('opacity', .7)
      .filter(function(d){ return !d.drawing })
      .each(function(d){ d.drawing = true })
    .transition().duration(1000)
      .call(exitConnection)
}

function exitConnection(sel){
  sel.attr('d', function(d){
    return [
    'M',  d.to.top, 
    'C',  [d.to.top.x, d.to.top.y],
          [d.to.top.x, d.to.top.y], 
          d.to.top,
    'L', d.to.bot, 
    'C',  [d.to.bot.x, d.to.bot.y],
          [d.to.bot.x, d.to.bot.y], 
          d.to.bot,
    ].join(' ')
  })
  .remove() 
}


function rotatePoint(p, c, θ){
  var sin = Math.sin(θ*Math.PI/180)
  var cos = Math.cos(θ*Math.PI/180)

  var x0 = p.x - c.x
  var y0 = p.y - c.y

  var x1 = x0*cos - y0*sin
  var y1 = x0*sin + y0*cos

  return P(x1 + c.x, y1 + c.y)
}


function randString(len){
  var alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ     '
  return d3.range(len).map(function(){
    return alpha[Math.floor(Math.random()*alpha.length)]
  }).join('')
}

function randColor(){
  return 'rgb(' + [Math.random()*255, Math.random()*255, Math.random()*255].map(Math.round) + ')'
}

events.csv

people.csv

places.csv