escher.js
/**
 * Listen for rotation, and rotate selected nodes.
 */
Listen for rotation, and rotate selected nodes.
Listen for rotation and rotate selected nodes .
function toggle_rotation_mode (on_off) {
  if (on_off === undefined) {
    this.rotation_mode_enabled = !this.rotation_mode_enabled
  } else {
    this.rotation_mode_enabled = on_off
  }
  var selection_node = this.map.sel.selectAll('.node-circle')
  var selection_background = this.map.sel.selectAll('#canvas')
  if (this.rotation_mode_enabled) {
    this.map.callback_manager.run('start_rotation')
    var selected_nodes = this.map.get_selected_nodes()
    if (Object.keys(selected_nodes).length === 0) {
      console.warn('No selected nodes')
      return
    }
    this.center = average_location(selected_nodes)
    show_center.call(this)
    var map = this.map
    var selected_node_ids = Object.keys(selected_nodes)
    var reactions = this.map.reactions
    var nodes = this.map.nodes
    var beziers = this.map.beziers
    var start_fn = function (d) {
      d3_selection.event.sourceEvent.stopPropagation()
    }
    var drag_fn = function (d, angle, total_angle, center) {
      var updated = build.rotate_nodes(selected_nodes, reactions,
                                       beziers, angle, center)
      map.draw_these_nodes(updated.node_ids)
      map.draw_these_reactions(updated.reaction_ids)
    }
    var end_fn = function (d) {}
    var undo_fn = function (d, total_angle, center) {
      var these_nodes = {}
      selected_node_ids.forEach(function (id) {
        these_nodes[id] = nodes[id]
      })
      var updated = build.rotate_nodes(these_nodes, reactions,
                                       beziers, -total_angle,
                                       center)
      map.draw_these_nodes(updated.node_ids)
      map.draw_these_reactions(updated.reaction_ids)
    }
    var redo_fn = function (d, total_angle, center) {
      var these_nodes = {}
      selected_node_ids.forEach(function (id) {
        these_nodes[id] = nodes[id]
      })
      var updated = build.rotate_nodes(these_nodes, reactions,
                                       beziers, total_angle,
                                       center)
      map.draw_these_nodes(updated.node_ids)
      map.draw_these_reactions(updated.reaction_ids) }
    var center_fn = function () {
      return this.center
    }.bind(this)
    this.rotation_drag = this._get_generic_angular_drag(start_fn, drag_fn,
                                                        end_fn, undo_fn,
                                                        redo_fn, center_fn,
                                                        this.map.sel)
    selection_background.call(this.rotation_drag)
    this.selectable_drag = this.rotation_drag
  } else {
    hide_center.call(this)
    selection_node.on('mousedown.center', null)
    selection_background.on('mousedown.center', null)
    selection_background.on('mousedown.drag', null)
    selection_background.on('touchstart.drag', null)
    this.rotation_drag = null
    this.selectable_drag = null
  }
  function show_center () {
    var sel = this.map.sel.selectAll('#rotation-center').data([ 0 ])
    var enter_sel = sel.enter().append('g').attr('id', 'rotation-center')
    enter_sel.append('path').attr('d', 'M-32 0 L32 0')
      .attr('class', 'rotation-center-line')
    enter_sel.append('path').attr('d', 'M0 -32 L0 32')
      .attr('class', 'rotation-center-line')
    var update_sel = enter_sel.merge(sel)
    update_sel.attr('transform',
                    'translate(' + this.center.x + ',' + this.center.y + ')')
      .attr('visibility', 'visible')
      .on('mouseover', function () {
        var current = parseFloat(update_sel.selectAll('path').style('stroke-width'))
        update_sel.selectAll('path').style('stroke-width', current * 2 + 'px')
      })
      .on('mouseout', function () {
        update_sel.selectAll('path').style('stroke-width', null)
      })
      .call(d3_drag().on('drag', function () {
        var cur = utils.d3_transform_catch(update_sel.attr('transform'))
        var new_loc = [
          d3_selection.event.dx + cur.translate[0],
          d3_selection.event.dy + cur.translate[1]
        ]
        update_sel.attr('transform', 'translate(' + new_loc + ')')
        this.center = { x: new_loc[0], y: new_loc[1] }
      }.bind(this)))
  }
  function hide_center(sel) {
    this.map.sel.select('#rotation-center')
      .attr('visibility', 'hidden')
  }
  function average_location(nodes) {
    var xs = []
    var ys = []
    for (var node_id in nodes) {
      var node = nodes[node_id]
      if (node.x !== undefined)
        xs.push(node.x)
      if (node.y !== undefined)
        ys.push(node.y)
    }
    return { x: utils.mean(xs),
             y: utils.mean(ys) }
  }
}
function toggle_rotation_mode ( on_off ) { if ( on_off === undefined ) { this . rotation_mode_enabled = ! this . rotation_mode_enabled } else { this . rotation_mode_enabled = on_off } var selection_node = this . map . sel . selectAll ( '.node-circle' ) var selection_background = this . map . sel . selectAll ( '#canvas' ) if ( this . rotation_mode_enabled ) { this . map . callback_manager . run ( 'start_rotation' ) var selected_nodes = this . map . get_selected_nodes ( ) if ( Object . keys ( selected_nodes ) . length === 0 ) { console . warn ( 'No selected nodes' ) return } this . center = average_location ( selected_nodes ) show_center . call ( this ) var map = this . map var selected_node_ids = Object . keys ( selected_nodes ) var reactions = this . map . reactions var nodes = this . map . nodes var beziers = this . map . beziers var start_fn = function ( d ) { d3_selection . event . sourceEvent . stopPropagation ( ) } var drag_fn = function ( d , angle , total_angle , center ) { var updated = build . rotate_nodes ( selected_nodes , reactions , beziers , angle , center ) map . draw_these_nodes ( updated . node_ids ) map . draw_these_reactions ( updated . reaction_ids ) } var end_fn = function ( d ) { } var undo_fn = function ( d , total_angle , center ) { var these_nodes = { } selected_node_ids . forEach ( function ( id ) { these_nodes [ id ] = nodes [ id ] } ) var updated = build . rotate_nodes ( these_nodes , reactions , beziers , - total_angle , center ) map . draw_these_nodes ( updated . node_ids ) map . draw_these_reactions ( updated . reaction_ids ) } var redo_fn = function ( d , total_angle , center ) { var these_nodes = { } selected_node_ids . forEach ( function ( id ) { these_nodes [ id ] = nodes [ id ] } ) var updated = build . rotate_nodes ( these_nodes , reactions , beziers , total_angle , center ) map . draw_these_nodes ( updated . node_ids ) map . draw_these_reactions ( updated . reaction_ids ) } var center_fn = function ( ) { return this . center } . bind ( this ) this . rotation_drag = this . _get_generic_angular_drag ( start_fn , drag_fn , end_fn , undo_fn , redo_fn , center_fn , this . map . sel ) selection_background . call ( this . rotation_drag ) this . selectable_drag = this . rotation_drag } else { hide_center . call ( this ) selection_node . on ( 'mousedown.center' , null ) selection_background . on ( 'mousedown.center' , null ) selection_background . on ( 'mousedown.drag' , null ) selection_background . on ( 'touchstart.drag' , null ) this . rotation_drag = null this . selectable_drag = null } function show_center ( ) { var sel = this . map . sel . selectAll ( '#rotation-center' ) . data ( [ 0 ] ) var enter_sel = sel . enter ( ) . append ( 'g' ) . attr ( 'id' , 'rotation-center' ) enter_sel . append ( 'path' ) . attr ( 'd' , 'M-32 0 L32 0' ) . attr ( 'class' , 'rotation-center-line' ) enter_sel . append ( 'path' ) . attr ( 'd' , 'M0 -32 L0 32' ) . attr ( 'class' , 'rotation-center-line' ) var update_sel = enter_sel . merge ( sel ) update_sel . attr ( 'transform' , 'translate(' + this . center . x + ',' + this . center . y + ')' ) . attr ( 'visibility' , 'visible' ) . on ( 'mouseover' , function ( ) { var current = parseFloat ( update_sel . selectAll ( 'path' ) . style ( 'stroke-width' ) ) update_sel . selectAll ( 'path' ) . style ( 'stroke-width' , current * 2 + 'px' ) } ) . on ( 'mouseout' , function ( ) { update_sel . selectAll ( 'path' ) . style ( 'stroke-width' , null ) } ) . call ( d3_drag ( ) . on ( 'drag' , function ( ) { var cur = utils . d3_transform_catch ( update_sel . attr ( 'transform' ) ) var new_loc = [ d3_selection . event . dx + cur . translate [ 0 ] , d3_selection . event . dy + cur . translate [ 1 ] ] update_sel . attr ( 'transform' , 'translate(' + new_loc + ')' ) this . center = { x : new_loc [ 0 ] , y : new_loc [ 1 ] } } . bind ( this ) ) ) } function hide_center ( sel ) { this . map . sel . select ( '#rotation-center' ) . attr ( 'visibility' , 'hidden' ) } function average_location ( nodes ) { var xs = [ ] var ys = [ ] for ( var node_id in nodes ) { var node = nodes [ node_id ] if ( node . x !== undefined ) xs . push ( node . x ) if ( node . y !== undefined ) ys . push ( node . y ) } return { x : utils . mean ( xs ) , y : utils . mean ( ys ) } } }
Listen for rotation, and rotate selected nodes.
Listen for rotation and rotate selected nodes .
// show center // this.set_status('Drag to rotate.') // silence other listeners // undo // redo // turn off all listeners // definitions