乔木.js边缘长度

Arbor.js edges length

本文关键字:边缘 js 乔木      更新时间:2023-09-26

我正在与arbor合作.js建立争议网络。问题是,当我只有几个带有长标签的节点时,画布的边界不受尊重。如何更改边缘的长度?或者我怎样才能让乔木尊重画布的极限?

我的代码 :

<html lang="fr">
    <head>
        <script language="javascript" type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
        <script language="javascript" type="text/javascript" src="path/to/arbor.js" ></script>
        <script language="javascript" type="text/javascript" src="path/to/arbor-tween.js" ></script>
        <script language="javascript" type="text/javascript" src="path/to/graphics.js" ></script>
        <script language="javascript" type="text/javascript" src="renderer.js" ></script>
        <style>
            canvas.linkable{cursor: pointer;}      
        </style>        
    </head>
<body>
    <canvas id="viewport" width="940" height="600"></canvas>
     <script language="javascript" type="text/javascript">
    var colour = {
      orange:"#EEB211",
      darkblue:"#21526a",
      purple:"#941e5e",
      limegreen:"#c1d72e",
      darkgreen:"#619b45",
      lightblue:"#009fc3",
      pink:"#d11b67",    
    }
    var data = {
      nodes:{
        principal:{ 'label':'Fins de la sélection',
                     'color':colour.darkblue, 'alpha': 0, link:'http://controverses.sciencespo-toulouse.fr/angr/' },
        controverse2:{ 'label':'La sélection, symbole du modèle productiviste de l''agriculture ?', 
                     'color':colour.darkblue, 'alpha': 0, link:'http://controverses.sciencespo-toulouse.fr/angr/' },
        controverse3:{ 'label':'Les objectifs de la sélection entrent-ils en conflit avec ceux de la conservation ?', 
                     'color':colour.darkblue, 'alpha': 0, link:'http://controverses.sciencespo-toulouse.fr/angr/' },
       controverse4:{ 'label':'Race pure ou race croisée ?', 
                     'color':colour.darkblue, 'alpha': 0, link:'http://controverses.sciencespo-toulouse.fr/angr/' },      
      },
      edges:{
        principal:{ controverse2:{}, 
              controverse3:{}, 
              controverse4:{} }, 
      }
    }
     // Initialise arbor
    var sys = arbor.ParticleSystem()
    sys.parameters({stiffness:900, repulsion:2000, gravity:false, dt:0.015})
    sys.renderer = Renderer("#viewport");
    sys.graft(data);
    /*
    var nav = Nav("#nav")
    $(sys.renderer).bind('navigate', nav.navigate)
    $(nav).bind('mode', sys.renderer.switchMode)
    nav.init()*/
  </script>
</body>
</html>

我的渲染器.js :

(function(){
  Renderer = function(canvas){
    var canvas = $(canvas).get(0)
    var ctx = canvas.getContext("2d");
    var gfx = arbor.Graphics(canvas)
    var particleSystem = null
    var dom = $(canvas)
    var that = {
      init:function(system){
        particleSystem = system
        particleSystem.screenSize(canvas.width, canvas.height) 
        particleSystem.screenPadding(40)
        that.initMouseHandling()
      },
      redraw:function(){
        if (!particleSystem) return
        gfx.clear() // convenience ƒ: clears the whole canvas rect
        // draw the nodes & save their bounds for edge drawing
        var nodeBoxes = {}
        particleSystem.eachNode(function(node, pt){
          // node: {mass:#, p:{x,y}, name:"", data:{}}
          // pt:   {x:#, y:#}  node position in screen coords
          // determine the box size and round off the coords if we'll be 
          // drawing a text label (awful alignment jitter otherwise...)
          var label = node.data.label||""
          var w = ctx.measureText(""+label).width + 10
          if (!(""+label).match(/^[ 't]*$/)){
            pt.x = Math.floor(pt.x)
            pt.y = Math.floor(pt.y)
          }else{
            label = null
          }
          // draw a rectangle centered at pt
          if (node.data.color) ctx.fillStyle = node.data.color
          else ctx.fillStyle = "rgba(0,0,0,.2)"
          if (node.data.color=='none') ctx.fillStyle = "white"
          if (node.data.shape=='dot'){
            gfx.oval(pt.x-w/2, pt.y-w/2, w,w, {fill:ctx.fillStyle})
            nodeBoxes[node.name] = [pt.x-w/2, pt.y-w/2, w,w]
          }else{
            gfx.rect(pt.x-w/2, pt.y-10, w,20, 4, {fill:ctx.fillStyle})
            nodeBoxes[node.name] = [pt.x-w/2, pt.y-11, w, 22]
          }
          // draw the text
          if (label){
            ctx.font = "12px Helvetica"
            ctx.textAlign = "center"
            ctx.fillStyle = "white"
            if (node.data.color=='none') ctx.fillStyle = '#333333'
            ctx.fillText(label||"", pt.x, pt.y+4)
            ctx.fillText(label||"", pt.x, pt.y+4)
          }
        })              

        // draw the edges
        particleSystem.eachEdge(function(edge, pt1, pt2){
          // edge: {source:Node, target:Node, length:#, data:{}}
          // pt1:  {x:#, y:#}  source position in screen coords
          // pt2:  {x:#, y:#}  target position in screen coords
          var weight = edge.data.weight
          var color = edge.data.color
          if (!color || (""+color).match(/^[ 't]*$/)) color = null
          // find the start point
          var tail = intersect_line_box(pt1, pt2, nodeBoxes[edge.source.name])
          var head = intersect_line_box(tail, pt2, nodeBoxes[edge.target.name])
          ctx.save() 
            ctx.beginPath()
            ctx.lineWidth = (!isNaN(weight)) ? parseFloat(weight) : 1
            ctx.strokeStyle = (color) ? color : "#cccccc"
            ctx.fillStyle = null
            ctx.moveTo(tail.x, tail.y)
            ctx.lineTo(head.x, head.y)
            ctx.stroke()
          ctx.restore()
          // draw an arrowhead if this is a -> style edge
          if (edge.data.directed){
            ctx.save()
              // move to the head position of the edge we just drew
              var wt = !isNaN(weight) ? parseFloat(weight) : 1
              var arrowLength = 6 + wt
              var arrowWidth = 2 + wt
              ctx.fillStyle = (color) ? color : "#cccccc"
              ctx.translate(head.x, head.y);
              ctx.rotate(Math.atan2(head.y - tail.y, head.x - tail.x));
              // delete some of the edge that's already there (so the point isn't hidden)
              ctx.clearRect(-arrowLength/2,-wt/2, arrowLength/2,wt)
              // draw the chevron
              ctx.beginPath();
              ctx.moveTo(-arrowLength, arrowWidth);
              ctx.lineTo(0, 0);
              ctx.lineTo(-arrowLength, -arrowWidth);
              ctx.lineTo(-arrowLength * 0.8, -0);
              ctx.closePath();
              ctx.fill();
            ctx.restore()
          }
        })

      },
      initMouseHandling:function(){
    // no-nonsense drag and drop (thanks springy.js)
    selected = null;
    nearest = null;
    var dragged = null;
    var oldmass = 1
    var mouse_is_down = false;
    var mouse_is_moving = false

    // set up a handler object that will initially listen for mousedowns then
    // for moves and mouseups while dragging
    var handler = {
      mousemove:function(e){
        if(!mouse_is_down){
          var pos = $(canvas).offset();
          _mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
          nearest = particleSystem.nearest(_mouseP);
          if (!nearest.node) return false
          selected = (nearest.distance < 50) ? nearest : null
          if(selected && selected.node.data.link){
            dom.addClass('linkable')
          } else {
            dom.removeClass('linkable')
          }
        }
        return false
      },
      clicked:function(e){
        var pos = $(canvas).offset();
        _mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
        nearest = particleSystem.nearest(_mouseP);
        if (!nearest.node) return false
        selected = (nearest.distance < 50) ? nearest : null
        if (nearest && selected && nearest.node===selected.node){
          var link = selected.node.data.link
          if (link.match(/^#/)){
             $(that).trigger({type:"navigate", path:link.substr(1)})
          }else{
             window.open(link, "frame3")
          }
          return false
        }
      },
      mousedown:function(e){
        var pos = $(canvas).offset();
        _mouseP = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
        selected = nearest = dragged = particleSystem.nearest(_mouseP);
        if (dragged.node !== null) dragged.node.fixed = true
        mouse_is_down = true
        mouse_is_moving = false
        $(canvas).bind('mousemove', handler.dragged)
        $(window).bind('mouseup', handler.dropped)
        return false
      },
      dragged:function(e){
        var old_nearest = nearest && nearest.node._id
        var pos = $(canvas).offset();
        var s = arbor.Point(e.pageX-pos.left, e.pageY-pos.top)
        mouse_is_moving = true
        if (!nearest) return
        if (dragged !== null && dragged.node !== null){
          var p = particleSystem.fromScreen(s)
          dragged.node.p = p
        }
        return false
      },
      dropped:function(e){
        if (dragged===null || dragged.node===undefined) return
        if (dragged.node !== null) dragged.node.fixed = false
        dragged.node.tempMass = 50
        dragged = null
        selected = null
        $(canvas).unbind('mousemove', handler.dragged)
        $(window).unbind('mouseup', handler.dropped)
        _mouseP = null
        if(mouse_is_moving){
          // console.log("was_dragged")
        } else {
          handler.clicked(e)
        }
        mouse_is_down = false
        return false
      }
    }
    $(canvas).mousedown(handler.mousedown);
    $(canvas).mousemove(handler.mousemove);
  }
}
    // helpers for figuring out where to draw arrows (thanks springy.js)
    var intersect_line_line = function(p1, p2, p3, p4)
    {
      var denom = ((p4.y - p3.y)*(p2.x - p1.x) - (p4.x - p3.x)*(p2.y - p1.y));
      if (denom === 0) return false // lines are parallel
      var ua = ((p4.x - p3.x)*(p1.y - p3.y) - (p4.y - p3.y)*(p1.x - p3.x)) / denom;
      var ub = ((p2.x - p1.x)*(p1.y - p3.y) - (p2.y - p1.y)*(p1.x - p3.x)) / denom;
      if (ua < 0 || ua > 1 || ub < 0 || ub > 1)  return false
      return arbor.Point(p1.x + ua * (p2.x - p1.x), p1.y + ua * (p2.y - p1.y));
    }
    var intersect_line_box = function(p1, p2, boxTuple)
    {
      var p3 = {x:boxTuple[0], y:boxTuple[1]},
          w = boxTuple[2],
          h = boxTuple[3]
      var tl = {x: p3.x, y: p3.y};
      var tr = {x: p3.x + w, y: p3.y};
      var bl = {x: p3.x, y: p3.y + h};
      var br = {x: p3.x + w, y: p3.y + h};
      return intersect_line_line(p1, p2, tl, tr) ||
            intersect_line_line(p1, p2, tr, br) ||
            intersect_line_line(p1, p2, br, bl) ||
            intersect_line_line(p1, p2, bl, tl) ||
            false
    }
    return that
  }    
})()

我尝试直接在脚本中修改边缘的长度,例如:

edges:{
        principal:{ controverse2:{length:1}, 
              controverse3:{length:1}, 
              controverse4:{length:1} }, 
      }

它不起作用。

感谢您的帮助!

为粒子系统设置此参数

sys.parameters({ repulsion: 1000, gravity: false, dt: 0.35 })