在Famo.us的表面之间绘制很多线条?

时间:2014-07-17 13:44:47

标签: canvas svg famo.us

我的目标是能够以一种看起来非常好的方式呈现图形数据库(通过线连接的节点),并在添加新节点时平滑动画。我一直在关注SVG,Canvas和现在的Famo.us。

Famo.us似乎对此有好处,因为我可以使用Famo.us Surfaces渲染每个节点,包括HTML格式的文本和控件。问题是绘制线来连接节点。 Famo.us没有像线条这样的原语。它确实有画布表面,但这似乎不是正确的方法。

我猜测我必须为每条线做一些非常尴尬的事情,比如创建一个高而薄的表面并计算一个可以使它连接在两个表面之间的变换。

3 个答案:

答案 0 :(得分:3)

以下是2个可拖动曲面的工作示例,它们之间有一条线。该线条是用另一个表面创建的。

运行演示http://gazibit.com/widget/31

var Engine = famous.core.Engine;
var Surface = famous.core.Surface;
var Modifier = famous.core.Modifier;
var Transform = famous.core.Transform;
var Draggable = famous.modifiers.Draggable;
var StateModifier = famous.modifiers.StateModifier;

var mainContext = Engine.createContext();


var lineOptions = {thickness:2,
                 lineColor:'#FA5C4F'};

//line surface
var ls = new Surface({
    origin:[0,.5],
    properties:{
      backgroundColor:lineOptions.lineColor
    }
});
initLine();
//Add the 2 blocks that will be joined by the line
ls.s1 = createBlock("s1",[100,100]);
ls.s2 = createBlock("s2",[300,100]);


//----------------------
//  HELPER FUNCTIONS
//----------------------
function initLine(){
var canvasModifier = new Modifier({
    size:function(){
      var len = _getLineLength()+5;
      return [len,lineOptions.thickness];
    },
    transform: function() {
        var p = _getPosition();
        return Transform.translate(p[0], p[1], 0);
    }
  });

var rotateModifier = new Modifier({
  transform: function (){
    var _s = _getRect();
    var angle  = Math.atan2(_s[1],_s[0]);
    return Transform.rotateZ(angle);
  } 
});

mainContext.add(canvasModifier).add(rotateModifier).add(ls);  
}

function createBlock(cnt,initialPosition){
var s = new Surface(
{ size:[100,100],
  content:cnt,
  properties:{
    color: 'white',
    textAlign: 'center',
    backgroundColor: '#FA5C4F'
  }
});
//Save the current position of the new surface
s.currentPosition = initialPosition;
var draggable = new Draggable();
draggable.obj = s;
s.pipe(draggable);
mainContext.add(draggable).add(s);
draggable.setPosition(initialPosition);
draggable.on('update',function(e){
  this.obj.currentPosition = e.position;   
});
return s;
}

//gets the position of where the line should start
function _getPosition(){
var dta = _getObjects();
var pnts = _getEndPoints(dta);
return pnts[0];
}

//Gets the Dx and Dy of line to calculate hypotenous
function _getRect(){
var res = [0,0];
var dta = _getObjects();
var pnts = _getEndPoints(dta);
var p1 = pnts[0];
var p2 = pnts[1];
res[0] = p2[0]-p1[0];
res[1] = p2[1]-p1[1];
return res;
}
function _getLineLength(){
var res = _getRect();
return Math.sqrt( ((res[0] * res[0]) + (res[1] * res[1])) );
}


function _getEndPoints(dta){
var dx = dta.rm.currentPosition[0]-dta.lmredge;
var dy = dta.bm.currentPosition[1]-dta.tmbedge;
if ( (dx <= 0) && (dy <= 0) ) {
  //objects are overlapping. Draw no line
  return [[0,0],[0,0]];
}
else if (dx > dy){
  //draw line from R and L edges
  var lmYMidPoint = dta.lm.currentPosition[1]+(dta.lm.size[1]/2);
  var rmYMidPoint = dta.rm.currentPosition[1]+(dta.rm.size[1]/2);
  var p1 = [dta.lmredge,lmYMidPoint];
  var p2 = [dta.rm.currentPosition[0],rmYMidPoint];
  return [p1,p2];
}
else {
  //draw line from B and Top edges
  var tmXMidPoint = dta.tm.currentPosition[0]+(dta.tm.size[0]/2);
  var bmXMidPoint = dta.bm.currentPosition[0]+(dta.bm.size[0]/2);
  var p1 = [tmXMidPoint,dta.tmbedge];
  var p2 = [bmXMidPoint,dta.bm.currentPosition[1]];
  return [p1,p2];
}
}

//Mark the objects as 
//top most, left most, bottom most, right most
function _getObjects(){
var lm = _getLeftMost(ls);
var rm = ls.s1;
if (lm == rm){
  rm = ls.s2;
}
var tm = _getTopMost(ls);
var bm = ls.s1;
if (tm == bm){
  bm = ls.s2;
}

var lm_redge = (lm.currentPosition[0]+lm.size[0]);
var lm_bedge = (lm.currentPosition[1]+lm.size[1]);
var rm_redge = (rm.currentPosition[0]+rm.size[0]);
var rm_bedge = (rm.currentPosition[1]+rm.size[1]);

var tm_redge = (tm.currentPosition[0]+tm.size[0]);
var tm_bedge = (tm.currentPosition[1]+tm.size[1]);
var bm_redge = (bm.currentPosition[0]+bm.size[0]);
var bm_bedge = (bm.currentPosition[1]+bm.size[1]);


return {lm:lm,rm:rm,tm:tm,bm:bm,
        lmredge:lm_redge,
        lmbedge:lm_bedge,
        rmredge:rm_redge,
        rmbedge:rm_bedge,
        tmredge:tm_redge,
        tmbedge:tm_bedge,
        bmredge:bm_redge,
        bmbedge:bm_bedge};
}

function _getLeftMost(obj){
if (obj.s1.currentPosition[0] <= obj.s2.currentPosition[0]){
  return obj.s1;
} else {
  return obj.s2;
}
}

function _getTopMost(obj){
if (obj.s1.currentPosition[1] <= obj.s2.currentPosition[1]){
  return obj.s1;
} else {
  return obj.s2;
}
}

答案 1 :(得分:0)

虽然我自己没有尝试过这样的事情。我看过一些涉及famo.us检查员的开发中的东西。这基本上是一个chrome扩展,它绘制了一个famo.us场景的层次结构。

如果您可能分析代码并自行安装扩展程序以查看它的实际效果,您可能会找到实现您正在寻找的结果的途径。如果我记得,层次结构被绘制为族树样式图,它允许动态添加和删除由流体线连接的节点。

当然,它正在开发中,可能是一个摇摇欲坠的原型,所以不要指望任何支持或反馈。

https://github.com/FamousInternal/famous-inspector

答案 2 :(得分:0)

为什么不使用具有一个窄尺寸和旋转变换的曲面?

var lineSurface = new Surface({
  size: [150,1],
  properties: {
    backgroundColor: 'white'
  }
});

var rotateModifier = new StateModifier({
  transform: Transform.rotateZ(Math.PI/4)
});

mainContext.add(rotateModifier1).add(lineSurface);