node graph

by Yoshiharu Kamata

HTML

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<svg width="100%"></svg>

CSS

svg g.node rect {
  fill: lightgray;
  stroke: gray;
}
svg g.node.select rect {
  stroke: red;
  stroke-width: 10px;
}
svg g.node.sonar rect {
  stroke: black;
  fill:   yellow;
}

CoffeeScript

###
Ch
Ps
Ls
Lp
Tn

ch   -   psv
emp  -      psv                        
class Base
  layer: 0  
  childrenIds: null
  parentIds: null
  parents: ->
  children: ->
  siblings:->
  sonar: ->
    @parents()
    @siblings()
    @descendants()
###
class Node extends Backbone.Model
  defaults:
    order: 10000
  initialize: (options)->
    id = _.uniqueId()
    @set 'id', id
    @set 'name', "#{options.type}-#{id}"
    @set 'children', []
    @set 'parents', []
    
  addChild: (child)->
    @get('children').push child.get('id')
    child.get('parents').push @get('id')
      
  children: ->
    result = _(@get('children')).map (id)=>
      @collection.get id
    .sortBy (model)->
      model.get('order')
    .valueOf()
                
  parents: ->
    _.map @get('parents'), (id)=>
      @collection.get id        
    
  siblings: ->
    _(@parents()).reject (parent)->
      parent.get 'isEmpty'
    .invoke("children")
    .flatten()
    .uniq()
    .valueOf()
    
  descendants: ->
    children = @children()
    if _.isEmpty children
      []
    else
      _(children).map (child)->
        child.descendants()
      .flatten()
      .union(children)
      .valueOf()
        
  ancestors: ->
    parents = @parents()
    if _.isEmpty parents
      []
    else
      _(parents).map (parent)->
        parent.ancestors()
      .union(parents)
      .flatten()
      .valueOf()
        
  leafs: (descendants = @descendants() )->
    _.select descendants, (model)->
      _.isEmpty model._children
    
  reflect: (descendants = @descendants())->
    myTypes = _(descendants).map (model)->
      model.get 'type'
    .uniq()
    .valueOf()
    
    reflectParents = _(@leafs descendants).invoke("parents")
    .flatten()
    .compact()
    .reject (parent)->
      _.include myTypes, parent.get('type')
    .valueOf()
    
    _(reflectParents).invoke("ancestors")
    .flatten()
    .concat(reflectParents)
    .valueOf()

  sonar: ->
    descendants = @descendants()
    _.union...