`
chaoran
  • 浏览: 24389 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

使用excanvas.js实现拓扑功能

阅读更多



     最近看了一下excanvas.js,感觉是个好东西。

    一直想用js实现拓扑功能,正好试一下。我用的是最新版的excanvas.js,还使用到了jquery和jquery ui的最新版。

    效果图如下

 

 

 

    四个节点都可以用鼠标拖拽,之间的连接线会跟着重画。

    js代码如下

$.jvChart = $.jvChart || {};
$.extend($.jvChart,{
 createElement : function(tag, attribs, styles, parent, nopad) {
  var el = document.createElement(tag);
  if (attribs) $(el).attr(attribs);
  if (nopad) $(el).css({padding: 0, border: 'none', margin: 0});
  if (styles) $(el).css(styles);
  if (parent) parent.appendChild(el); 
  return el;
 },
 drawEllipse : function(paper, x, y, rx, ry, color, width, fill, shadow, image){
    var ctx = paper.ctx;
    ctx.beginPath(); 
    var div = document.createElement("<div id='" + paper.getId() + "' style='position:absolute; cursor:move; left:" + x + "; top:" + y +
     "; width:" + rx + "; height:" + ry + "; '></div>");
    $(paper.canvas).append(div);
    ctx.element_ = div;
    $(div).draggable({
     stop : function(event, ui){
      $.jvChart.reDrawConnections(paper);
     }
    });
    x = y = 0;
         var hB = (rx / 2) * .5522848,
             vB = (ry / 2) * .5522848,
             eX = x + rx,           
             eY = y + ry,           
             mX = x + rx / 2,           
             mY = y + ry / 2;   
               
         ctx.moveTo(x, mY);       
         ctx.bezierCurveTo(x, mY - vB, mX - hB, y, mX, y);       
         ctx.bezierCurveTo(mX + hB, y, eX, mY - vB, eX, mY);       
         ctx.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY);       
         ctx.bezierCurveTo(mX - hB, eY, x, mY + vB, x, mY);       
         ctx.closePath();
    if (color && width){
     ctx.strokeStyle = color || "rgb(100, 100, 255)";
      ctx.lineWidth = width || 2;
      }
    if (fill) {
     ctx.fillStyle = setColor(fill, ctx);
     ctx.fill();
 
    }
      ctx.stroke();
      ctx.element_ = paper.canvas;
      return div;


 },
/* drawCircle : function(paper, x, y, rx, color, width, fill, shadow, image){
  var ctx = paper.getCtx();
  var div = document.createElement("<div style='position:absolute; cursor:move; left:" + x + "; top:" + y +
   "; width:" + rx + "; height:" + rx + "; '></div>");
  $(paper.canvas).append(div);
  ctx.element_ = div;
  $(div).draggable();
  x = y = 0;
  ctx.beginPath();
  ctx.arc(x, y, rx, 0, 2*Math.PI, true);
  if (color && width){
   ctx.strokeStyle = color || "rgb(100, 100, 255)";
      ctx.lineWidth = width || 2;
     }
  if (fill) {
   ctx.fillStyle = setColor(fill, ctx);
   ctx.fill();

  }
     ctx.stroke();
 },*/
 drawRect: function(paper, x, y, w, h, radius, color, width, fill, shadow, image) {
  function drawPath() {
   ctx.beginPath();
   if (!radius) {
    ctx.rect(x, y, w, h);
   } else {
    ctx.moveTo(x, y + radius);
    ctx.lineTo(x, y + h - radius);
    ctx.quadraticCurveTo(x, y + h, x + radius, y + h); // change: use bezier
    ctx.lineTo(x + w - radius, y + h);
    ctx.quadraticCurveTo(x + w, y + h, x + w, y + h - radius);
    ctx.lineTo(x + w, y + radius);
    ctx.quadraticCurveTo(x + w, y , x + w - radius, y);
    ctx.lineTo(x + radius, y);
    ctx.quadraticCurveTo(x , y, x, y + radius);
   }
   ctx.closePath();
  };

  var ctx = paper.ctx, normalizer = (width || 0) % 2 / 2;
  var div = document.createElement("<div id='" + paper.getId() + "' style='position:absolute; cursor:move; left:" + x + "; top:" + y +
   "; width:" + w + "; height:" + h + "; '></div>");
  $(paper.canvas).append(div);
  ctx.element_ = div;
  $(div).draggable({
   stop : function(event, ui){
    $.jvChart.reDrawConnections(paper);
   }
  });   
  x = y = 0;

  x = Math.round(x) + normalizer;
  y = Math.round(y) + normalizer;
  w = Math.round(w);
  h = Math.round(h);
  
  // apply the drop shadow
  if (shadow) for (var i = 1; i <= 3; i++) {
      drawRect(paper, x + 1, y + 1, w, h, radius, 'rgba(0, 0, 0, '+ (0.05 * i) +')',
       6 - 2 * i);
  }

  // apply the background image behind everything
  if (image) ctx.drawImage(image, x, y, w, h);
  
  drawPath();
  if (fill) {
   ctx.fillStyle = setColor(fill, ctx);
   ctx.fill();
   // draw path again
   if (win.G_vmlCanvasManager) drawPath();
  }
  if (width) {
   ctx.strokeStyle = color;
   ctx.lineWidth = width;
   ctx.stroke();
  }
  ctx.element_ = paper.canvas;

  return div;
 },
 drawConnection : function (paper, obj1, obj2, color, width){
  var ctx = paper.ctx;
     var p = [{x: parseInt($(obj1).css('left')) + $(obj1).width() / 2, y: parseInt($(obj1).css('top')) - 1},
         {x: parseInt($(obj1).css('left')) + $(obj1).width() / 2, y: parseInt($(obj1).css('top')) + $(obj1).height() + 1},
         {x: parseInt($(obj1).css('left')) - 1, y: parseInt($(obj1).css('top')) + $(obj1).height() / 2},
         {x: parseInt($(obj1).css('left')) + $(obj1).width() + 1, y: parseInt($(obj1).css('top')) + $(obj1).height() / 2},
         {x: parseInt($(obj2).css('left')) + $(obj2).width() / 2, y: parseInt($(obj2).css('top')) - 1},
         {x: parseInt($(obj2).css('left')) + $(obj2).width() / 2, y: parseInt($(obj2).css('top')) + $(obj2).height() + 1},
         {x: parseInt($(obj2).css('left')) - 1, y: parseInt($(obj2).css('top')) + $(obj2).height() / 2},
         {x: parseInt($(obj2).css('left')) + $(obj2).width() + 1, y: parseInt($(obj2).css('top')) + $(obj2).height() / 2}];
     var d = {}, dis = [];
     for (var i = 0; i < 4; i++) {
         for (var j = 4; j < 8; j++) {
             var dx = Math.abs(p[i].x - p[j].x),
                 dy = Math.abs(p[i].y - p[j].y);
             if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
                 dis.push(dx + dy);
                 d[dis[dis.length - 1]] = [i, j];
             }
         }
     }
     if (dis.length == 0) {
         var res = [0, 4];
     } else {
         var res = d[Math.min.apply(Math, dis)];
     }
     var x1 = p[res[0]].x,
         y1 = p[res[0]].y,
         x4 = p[res[1]].x,
         y4 = p[res[1]].y/*,
         dx = Math.max(Math.abs(x1 - x4) / 2, 10),
         dy = Math.max(Math.abs(y1 - y4) / 2, 10),
         x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3),
         y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3),
         x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3),
         y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3)*/;

  ctx.beginPath();
  ctx.strokeStyle = color;
  ctx.lineWidth = width;
  ctx.moveTo(x1, y1);
  ctx.lineTo(x4, y4);
  ctx.closePath();
     ctx.stroke();
 },
 reDrawConnections : function (paper){
  paper.edgePaper.ctx.clearRect(0, 0, paper.width, paper.height);
  $(paper.edgePaper.edges).each(function(i){
   $.jvChart.drawConnection(paper.edgePaper, document.getElementById(paper.edgePaper.edges[i][0]), document.getElementById(paper.edgePaper.edges[i][1]), 'rgb(0,0,0)', 2);
  });
 }

});
(function($) {
$.fn.jvChart = function(width, height) {
 var paper = {
  idCounter : 0,
  idPrefix  : "jvChart-element-",
  getId     : function() { return this.idPrefix + this.idCounter++; }
 };
 var edgePaper = {
  idCounter : 0,
  idPrefix  : "jvChart-edge-",
  getId     : function() { return this.idPrefix + this.idCounter++; },
  edges : []
 }; 
 function getCtx(paper){
  var cvs = $.jvChart.createElement('canvas', {
   id: paper.getId(),
   width: $(paper.canvas).width(),
   height: $(paper.canvas).height()
  }, {position: 'absolute'}, paper.canvas);

  if ($.browser.msie) {
   G_vmlCanvasManager.initElement(cvs);
   cvs = document.getElementById(cvs.id);
   $('div', cvs).first().attr('id', paper.idPrefix + 'div');
  }
  return cvs.getContext('2d');
 }
 
 return this.each( function() {
  paper.canvas = this;
  edgePaper.canvas = this;
  $(this).css({overflow:'hidden', position:'relative'});
  paper.ctx = getCtx(paper);
  edgePaper.ctx = getCtx(edgePaper);
  paper.edgePaper = edgePaper;
  paper.width = $(paper.canvas).width();
  paper.height = $(paper.canvas).height();
  this.paper = paper;
  this.edgePaper = edgePaper;
 });
   
};
 
$.fn.extend({
 circle : function (x, y, r, color, width, fill, shadow, image) {
  return $.jvChart.drawCircle($(this).attr('paper'), x || 0, y || 0, r || 0, color, width, fill, shadow, image);
 },
 ellipse : function (x, y, rx, ry, color, width, fill, shadow, image) {
  return $.jvChart.drawEllipse($(this).attr('paper'), x || 0, y || 0, rx || 0, ry || 0, color, width, fill, shadow, image);
 },
 rectangle : function (x, y, w, h, r, color, width, fill, shadow, image) {
        return $.jvChart.drawRect($(this).attr('paper'), x || 0, y || 0, w || 0, h || 0, r || 0, color, width, fill, shadow, image);
    },
    connection : function(obj1, obj2, color, width){
     var p = $(this).attr('edgePaper');
     $.jvChart.drawConnection(p, obj1, obj2, color, width);
     p.edges.push([$(obj1).attr('id'), $(obj2).attr('id')]);
    }
});
})(jQuery);

 

    调用的js如下

$(document).ready(function(){
$("#container").jvChart(600, 400);
var v1 = $("#container").ellipse(0, 120, 80, 40, 'rgb(0,0,0)', 2);
var v2 = $("#container").rectangle(100, 20, 80, 40, 10, 'rgb(0,0,0)', 2);
var v4 = $("#container").ellipse(300, 100, 50, 50, 'rgb(0,0,0)', 2);

var v3 = $("#container").rectangle(290, 180, 60, 40, 2, 'rgb(0,0,0)', 2);


$("#container").connection(v1, v2, 'rgb(0,0,0)', 2);
$("#container").connection(v2, v3, 'rgb(0,0,0)', 2);
$("#container").connection(v2, v4, 'rgb(0,0,0)', 2);
});

    container是一个div:<div id="container" style="width: 600px; height: 400px; background-color:rgb(255,255,255); "></div>

 

    时间很仓促,还有很多需要改进和优化的地方,以后有空了再写吧。这个脚本也可以用来画流程图。

  • 大小: 10.1 KB
0
2
分享到:
评论
3 楼 neusoft_jerry 2012-06-07  
同意楼下两位!
2 楼 cuisuqiang 2012-03-23  
把用到的JS和页面传上去,不然看一堆代码,郁闷
1 楼 Silverside 2010-12-31  
以后把写好的js文件上传不是更好吗?
如果需要特别说明,只需要贴部分代码即可,不必这样整段的贴。

相关推荐

Global site tag (gtag.js) - Google Analytics