Skip to content

Instantly share code, notes, and snippets.

@changtimwu
Last active August 29, 2015 14:07
Show Gist options
  • Save changtimwu/0b8f9d5547ac0a2ccaeb to your computer and use it in GitHub Desktop.
Save changtimwu/0b8f9d5547ac0a2ccaeb to your computer and use it in GitHub Desktop.
net viewer study

base tasks

  • bidirectional port/line
  • load/save map
    • data structure
  • node add/del with reponsive show/hide
  • scale links
  • line animations
    • particle flow
    • line broken
    • link back
    • one way link
  • node animation
    • node down
    • node up
  • edit/monitor mode transition
  • event list
  • time line
    • object change diff
    • playback
  • panel open/close show/hide
    • event list panel
    • node list panel

Integration

  • API verfication
@changtimwu
Copy link
Author

all element creation are concerated in the-graph.js

  TheGraph.factories.createGroup = (options, content) ->
    args = [options]
    args = args.concat(content)  if Array.isArray(content)
    g.apply g, args
  TheGraph.factories.createRect = (options) ->
    rect options
  TheGraph.factories.createText = (options) ->
    gtext options
  TheGraph.factories.createCircle = (options) ->
    circle options
  TheGraph.factories.createPath = (options) ->
    path options
  TheGraph.factories.createCanvas = (options) ->
    canvas options

redefines as creation functions in each element module.

ex. in the-graph-node.js

  TheGraph.factories.node =
    createNodeGroup: TheGraph.factories.createGroup
    createNodeBackgroundRect: TheGraph.factories.createRect
    createNodeBorderRect: TheGraph.factories.createRect
    createNodeInnerRect: TheGraph.factories.createRect
    createNodeIconText: TheGraph.factories.createText
    createNodeInportsGroup: TheGraph.factories.createGroup
    createNodeOutportsGroup: TheGraph.factories.createGroup
    createNodeLabelGroup: TheGraph.factories.createGroup
    createNodeLabelRect: TheGraph.factories.createRect
    createNodeLabelText: TheGraph.factories.createText
    createNodeSublabelGroup: TheGraph.factories.createGroup
    createNodeSublabelRect: TheGraph.factories.createRect
    createNodeSublabelText: TheGraph.factories.createText
    createNodePort: createNodePort

ex. in the-graph-port.js

  TheGraph.factories.port =
    createPortGroup: TheGraph.factories.createGroup
    createPortBackgroundCircle: TheGraph.factories.createCircle
    createPortArc: TheGraph.factories.createPath
    createPortInnerCircle: TheGraph.factories.createCircle
    createPortLabelText: TheGraph.factories.createText

@changtimwu
Copy link
Author

not DI. It's this cascading. TheGraph is the top-level joint global variable which holds all states. You can access it at browser's console.

@changtimwu
Copy link
Author

several react components

the-graph-app.coffee:  TheGraph.App = React.createClass
the-graph-edge.coffee:  TheGraph.Edge = React.createClass
the-graph-graph.coffee:  TheGraph.Graph = React.createClass
the-graph-group.coffee:  TheGraph.Group = React.createClass
the-graph-iip.coffee:  TheGraph.IIP = React.createClass
the-graph-menu.coffee:  TheGraph.Menu = React.createClass
the-graph-menu.coffee:  TheGraph.ModalBG = React.createClass
the-graph-node-menu-port.coffee:  TheGraph.NodeMenuPort = React.createClass
the-graph-node-menu-ports.coffee:  TheGraph.NodeMenuPorts = React.createClass render: ->
the-graph-node-menu.coffee:  TheGraph.NodeMenu = React.createClass
the-graph-node.coffee:  TheGraph.Node = React.createClass
the-graph-port.coffee:  TheGraph.Port = React.createClass
the-graph-tooltip.coffee:  TheGraph.Tooltip = React.createClass
the-graph.coffee:  TheGraph.TextBG = React.createClass render: 

TextBG and NodeMenuPorts define only the render method.

to see how are they cross reference. ex I want to see how edge be used.

> grep 'TG.Edge' *
the-graph-edge.coffee:  TG.Edge = React.createClass
the-graph-graph.coffee:    TG.Edge options
the-graph-graph.coffee:    TG.Edge options

the actual usage in the-graph-graph.coffee

createGraphEdge = (options) ->
  TG.Edge options

TG.Graph = React.createClass
  render: ->
    edgeOptions =
        key: key
        graph: graph
        edge: edge
        app: self.props.app
        sX: source.metadata.x + source.metadata.width
        sY: source.metadata.y + sourcePort.y
        tX: target.metadata.x
        tY: target.metadata.y + targetPort.y
        label: label
        route: route
        onEdgeSelection: self.props.onEdgeSelection
        selected: self.state.selectedEdges.indexOf(edge) isnt -1
        animated: self.state.animatedEdges.indexOf(edge) isnt -1
        showContext: self.props.showContext
    TG.factories.graph.createGraphEdge.call this, edgeOptions

The class hierarchy is

  • App
    • Graph
    • Tooltip
  • Graph
    • IIP
      • TextBG
    • Node
      • NodeMenuPorts
        • NodeMenuPort
      • NodeMenu
        • NodeMenuPorts
        • Menu
      • Menu
    • Edge
      • Menu
    • Group
    • Menu

@changtimwu
Copy link
Author

TheGraph.merge is used everywhere.

  # The `merge` function provides simple property merging.
  TheGraph.merge = (src, dest, overwrite=false) ->
    # Do nothing if neither are true objects.
    return dest  if Array.isArray(src) or Array.isArray(dest) or typeof src isnt "object" or typeof 
dest isnt "object"
    for key of src
      # Only copy properties, not functions.
      dest[key] = src[key] if typeof src[key] isnt "function" and (not dest[key] or overwrite)
    dest

@changtimwu
Copy link
Author

@props and @state are from reactjs.

@changtimwu
Copy link
Author

member list of TG.Config

  • app
  • edge
  • graph
  • group
  • iip
  • menu
  • modalBG
  • nodeMenuPort
  • nodeMenuPorts
  • node
  • port
  • tooltip

@changtimwu
Copy link
Author

getContext is what to do at right clicking. It's usually menu.

@changtimwu
Copy link
Author

noflo is in the packages.json of the-graph .

  "dependencies": {
    "noflo": "^0.5.9"
  },

Noflo is written in CoffeeScript.
the-graph can run without it but....

  • the grunt task build index.js into build/noflo.js
 grunt browserify:libs
  • the whole content of index.js is
// Build required libs
noflo = require('noflo');

Wow, build/noflo.js actually includes the whole noflo.

  • take a look of browserify:libs
  browserify: {
        libs: {
          files: {
            'build/noflo.js': ['index.js'],
          },
          options: {
            transform: ['coffeeify']
          },
          browserifyOptions: {
            require: 'noflo'
          }
        }
      },

@changtimwu
Copy link
Author

  • How does main page make use the the-graph module?
  • the-graph assigned itself top object into context.TheGraph then main page can reference it by accessing window.TheGraph like the following. See it? TheGraph is as an React component.
  @appView = React.renderComponent window.TheGraph.App(
          graph: @graph
          width: @width
          height: @height
          library: @library
          menus: @menus
          editable: @editable
          onEdgeSelection: @onEdgeSelection.bind this
          onNodeSelection: @onNodeSelection.bind this
          onPanScale: @onPanScale.bind this
          getMenuDef: @getMenuDef
          displaySelectionGroup: @displaySelectionGroup
          forceSelection: @forceSelection
        ), @$.svgcontainer

@changtimwu
Copy link
Author

Good! I have finished the browserifying

it uses lots of

<link rel="import" href="../the-graph/the-graph.html" >

http://www.html5rocks.com/en/tutorials/webcomponents/imports/

@changtimwu
Copy link
Author

import tree of the-graph-editor

  • index.html imports
    • the-graph-editor.html imports
      • ../the-graph/the-graph.html
    • ../the-graph-nav/the-graph-nav.html
    • ../build/noflo.js this is a browserifed version of noflo
  • index.html expects window.TheGraph.FONT_AWESOME exists. This is a bad design since FONT_AWESOME is provided through the-graph-editor.html including../the-graph/the-graph.html`
  • noflo is a also global variable. You can access it in console.

@changtimwu
Copy link
Author

the-graph is packed as a web component. What does its interface?

  • How to feed nodes/link into it?
  • How to feed events into ?
  • data layer?

@changtimwu
Copy link
Author

@changtimwu
Copy link
Author

data structure

  • a group ( access through .groups). changeFilter is the group label
{ 
  name: 'changefilter',
    nodes: 
     [ 'dom/GetElement_e16dy',
       'dom/GetElement_85so0',
       'interaction/ListenMouse_bil4d',
       'interaction/ListenMouse_aii7r' ],
 metadata: { description: '', color: 5 } 
}
  • a process ( access through .process). clickPrev is the process label.
{
  'interaction/ListenMouse_aii7r': { 
      component: 'interaction/ListenMouse',
      metadata:   { x: 720, y: 288, label: 'clickPrev' } 
  },
}
  • a connection
{ 
  src: { process: 'dom/GetElement_85so0', port: 'element' },
  tgt: { process: 'interaction/ListenMouse_aii7r', port: 'element' },
  metadata: { route: '10' } 
}

{ 
  src: { process: 'interaction/ListenMouse_aii7r', port: 'click' },
  tgt: { process: 'routers/KickRouter_bzaiw', port: 'prev' },
  metadata: { route: '9' }
}

Obviously, component of a process defines its type and its ports.

@changtimwu
Copy link
Author

Too bad! there is no ports define component. A port not connected is defined as single end connection like the following.

{ 
  data: 0.01,
  tgt: { process: 'seriously/TVGlitch_e1qre', port: 'verticalsync' } 
}

Component is actually defined in noflo. Take the simple noflo component Output as an example.
http://noflojs.org/component/noflo-core-Output/

  • It defines

@changtimwu
Copy link
Author

the-graph-editor/index.html

  • photo_booth.json.js 內一開始就call loadGraph, index.html 裡面有定義好 window.loadGraph
  • 可以 var editor=document.getElementById('editor') . editor 看出下列 api
  editor.graph;   // 完整 graph 資料
  editor.getComponent('core/Split'); // -- 取得某種component 
  editor.triggerAutolayout();
  theme = (theme==="dark" ? "light" : "dark");
  editor.theme = theme;
  editor.toJSON();  // get json
  • 共有下列 simulates
    • library update -- timeout 1000
    • node icon updates -- interval 1000
    • un/triggering wire animations -- interval 2014
    • un/triggering errors -- interval 3551

@changtimwu
Copy link
Author

'#editor' 的 tag 是<the-graph-editor >, <the-graph-editor > 是用 polymer 訂出來的, 主要實作在 the-graph-editor.html內, its properties & methods are all defined through the Polymer statement

 Polymer('the-graph-editor', {

});
  • properties
      graph: null,
      grid: 72,
      snap: 36,
     width: 800,
      height: 600,
      scale: 1,
      plugins: {},
      nofloGraph: null,
      menus: null,
      autolayout: false,
      theme: "dark",
      selectedNodes: [],
      copyNodes: [],
      errorNodes: {},
      selectedEdges: [],
      animatedEdges: [],
      displaySelectionGroup: true,
      forceSelection: false,
  • created: function()
  • ready: function () {}
  • attached: function ()
  • detached: function ()
  • addPlugin: function (name, plugin)
  • addMenu: function (type, options)
  • addMenuCallback: function (type, callback)
  • addMenuAction: function (type, direction, options)
  • getMenuDef function (options)
  • widthChanged
  • heightChanged
  • graphChanged
  • buildInitialLibrary
  • registerComponent: function (definition, generated)
  • updateIcon: function (nodeId, icon)
  • rerender
  • triggerAutolayout: function () EG
  • triggerFit: function ()
  • animateEdge: function (edge)
  • unanimateEdge: function (edge)
  • addErrorNode: function (id)
  • removeErrorNode: function (id)
  • clearErrorNodes: function () E
  • updateErrorNodes: function () E
  • focusNode: function (node) E
  • getComponent: function (name) EG
  • getLibrary: function () E
  • toJSON: function () EG

@changtimwu
Copy link
Author

index.html

  • 內有三大部分 editor, navigator, control buttons, 前兩者都是 polymer
<the-graph-editor id="editor" 
      width="800" height="600" 
      grid="72" 
      snap="36" 
      theme="dark">
    </the-graph-editor>
    <the-graph-nav id="nav" width="216" height="162"></the-graph-nav>
    <div id="testing">
      <button id="autolayout">autolayout</button>
      <button id="theme">theme</button>
      <button id="focus">focus</button>
    </div>
  • 透過 jsonp load到的資料 會在 index.html 內的 window.loadGraph 直接塞到 editor.graph
  • 但 editor 變數其實是來自底下這行, 而DOM上的 #editor 是個 polymer tag, 所以等於是把 map資料傳給了 the-graph-editor了.
var editor = document.getElementById('editor');

the-graph-editor.html

  • <the-graph-editor > 內又使用了 the-graph, 而 <the-graph> 也是用 polymer 訂出來的, 主要實作在 the-graph.html
  • 其 member function graphChanged: (oldGraph, newGraph), 使用了 React.renderComponent 來 render TheGraph.App
  • <the-graph-editor>this.graph 經過 noflo.graph.loadJSON 轉換, 放入 this.nofloGraph, 然後再傳給 <the-graph>裏的 this.graph
  • 所以想知道 吃什麼格式, 得知道noflo做了什麼事.
  • polymer 裏類似這樣的 code, this.$.graph.updateIcon, 就是select child tag graph -> <the-graph id="graph" >
  • 所以 this.$.graph & this.graph 是不一樣的, 前者也是一個polymer 元件, 可以call這個元件所有method, this.graph 是純資料.

@changtimwu
Copy link
Author

come up with some screenshots. make a component

  • has 8 ports
  • in/out interleave
  • show port labels as number

is outports are at right side and inport are always at left side?

@changtimwu
Copy link
Author

line is rendered at edge.coffee

Graph = React.createClass
  renderEdges: ->
    graph = @state.graph
    for edge in graph.edges
      source = graph.getNode edge.from.node
      target = graph.getNode edge.to.node

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment