canvas - 在 Famo.us 的表面之间画很多线?

标签 canvas svg famo.us

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

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

我猜我必须为每条线做一些相当尴尬的事情,比如创建一个又高又薄的表面并计算一个变换,使其在两个表面之间连接。

最佳答案

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

运行演示 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;
}
}

关于canvas - 在 Famo.us 的表面之间画很多线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24805335/

相关文章:

android - 单独的圆角(不是所有角)

java - 合并两个图像总是顶部和底部。但我想在 android 中并排

javascript - 这个 "if statement"不应该导致反弹吗?

svg - 如何将文本转换为轮廓 svg 图像?

javascript - 使用 JavaScript 的 HTML 前端 SVG 导出下载

javascript - 有关 famo.us 中的 View 的问题

javascript - Chart.js 微软边缘显示问题

javascript - contextMenu的GoJS makeSvg

javascript - Famo.us 球拖放,释放时设置速度

meteor - 需要帮助请 : Meteor and Famous integration and creation of forms