D3实现简单业务拓扑图

PS: 这篇文章适合有一定D3基础的童鞋,因为没有多余的注释,只是笔者比较业余的代码分享,勿喷

目录
- HTML
- JS
- CSS
- 效果图

^ HTML

<div class="content-panel">
    <div id="object"></div>
    <div id="object-arrow"></div>
</div>

^ JS

(angularjs Controller的代码)

var url = $location.path();
    $scope.$storage = $localStorage;
    var defaultLocation;
    if (_.has($localStorage, 'multiObject')) {
      defaultLocation = $localStorage.multiObject;
    }

    var nodeNameMap = {};
    var newNodes = _.map(abjectData.nodes, function(node) {
      nodeNameMap[node.objectId] = node.name;
      var rNode = {};
      if (_.has(defaultLocation, node.objectId)) {
        rNode.name = node.name;
        rNode.objectId = node.objectId;
        rNode.instanceCount = + node.instanceCount;
        rNode.attrs = node.attrs;
        rNode.fixed = true;
        rNode.x = defaultLocation[node.objectId].x;
        rNode.y = defaultLocation[node.objectId].y;
      } else {
        rNode = node;
      }
      return rNode;
    });

    var width = window.innerWidth - 250,
        height = window.innerHeight - 200,
        boxWidth = 160,
        countR = 15;

    var objectContainer = d3.select('#object').append('div')
        .style('position', 'absolute')
        .attr('width', width)
        .attr('height', height);

    var force = d3.layout.force();

    force
        .nodes(newNodes)
        .links(abjectData.links)
        .size([width, height])
        .linkDistance(200)
        .charge(-2000)
        .chargeDistance(250)
        .start();

    var svg = d3.select('#object-arrow').append('svg')
        .attr('width', width)
        .attr('height', height);

    svg.append('defs').append('marker')
        .attr('id', 'end-arrow')
        .attr('refX', 4)
        .attr('refY', 4)
        .attr('viewBox', '0 0 8 8')
        .attr('markerWidth', 8)
        .attr('markerHeight', 8)
        .attr('orient', 'auto')
      .append('path')
        .attr('d', 'M0,0 8 4 0 8 4 4z')
        .attr('fill', '#7FABD2')
        .attr('stroke', 'none');

    var path = svg.append('g').selectAll('path')
        .data(force.links())
      .enter().append('path')
        .attr('class', 'link')
        .style('marker-end', 'url(' + url + '#end-arrow)');

    var objectEnter = objectContainer.selectAll('div')
        .data(newNodes)
        .enter();

    var object = objectEnter.append('div')
        .attr('class', 'object')
        .attr('id', function (d) {
          return d.objectId;
        });

    var objectHeader = object.append('div')
        .attr('class', 'object-header')
          .append('i')
          .attr('class', function(d) {
            return objectIconMap(d.objectId);
          })
          .text(function (d) {
            return ' ' + d.name;
          });

    object.append('div')
        .attr('class', 'object-attrs')
        .selectAll('p')
          .data(function(d) {
            return _.uniq(d.attrs);
          })
          .enter()
          .append('p')
          .text(function(d) {
            return nodeNameMap[d];
          });

    var objectToolBar = object.append('div')
        .attr('class', 'object-settings');

    objectToolBar.append('a')
        .attr('class', 'btn btn-primary btn-link btn-xs')
        .attr('href', function (d) {
          return url + 'attr/' + d.objectId;
        })
        .append('i')
        .attr('class', 'glyphicon glyphicon-cog');

    object.on('dblclick', function(d) {
        d3.select(this).classed('fixed', d.fixed = false);
      }).call(force.drag().on('dragstart', function(d) {
        d3.select(this).classed('fixed', d.fixed = true);
      })
    );

    objectHeader.on('click', function (d) {
      if (d3.event.defaultPrevented) { return; }
      //然后根据 d 的数据,做一些个性化的跳转判断, Dialog或$state.go('xx')等
    });

    force.on('tick', function() {
      path.attr('d', drawPath);
      object.style('left', function (d) {
        return Math.max(Math.min(d.x, width), 0) + 'px';
      }).style('top', function (d) {
        return Math.max(Math.min(d.y, height), countR) + 'px';
      });
    });

    function objectIconMap(objectId) {
      return OBJECTICONMAP[objectId] || 'ti-layout-media-overlay-alt';
    }

    //箭头定位算法, 明显比较挫,看效果就知道了喽
    function drawPath(d) {
      var dx = Math.abs(d.target.x - d.source.x),
          dy = Math.abs(d.target.y - d.source.y),
          headerHeight = 40,
          itemHeight = 25,
          arrowWidth = 5,
          itemStart = (_.indexOf(d.source.attrs, d.target.objectId) + 1) * itemHeight - itemHeight / 2,
          x1 = d.source.x + boxWidth,
          y1 = d.source.y + headerHeight + itemStart,
          x2 = x1 + dx / 4,
          y2 = y1,
          x4 = d.target.x - arrowWidth,
          y4 = d.target.y + headerHeight / 2,
          x3 = x4 - dx / 4,
          y3 = y4;

      if ((x1 - boxWidth) <= x4 && d.source.y >= d.target.y) {
        if (x1 > x4) {
          x1 -= boxWidth;
          x2 = Math.max(x1 - dx, 0);
          y2 -= dy / 4;
          x3 = Math.max(x4 - dx, 0);
          y3 = y4 + dy / 4;
        }
      } else if ((x1 - boxWidth) <= x4 && d.source.y < d.target.y) {
        if (x1 > x4) {
          x1 -= boxWidth;
          x2 = Math.max(x1 - dx, 0);
          y2 += dy / 2;
          x3 = Math.max(x4 - dx, 0);
        }
      } else {
        if ((x1 - boxWidth) < (x4 + boxWidth)) {
          x2 = Math.max(x1 + dx, 0);
          x4 += boxWidth + 2 * arrowWidth;
          x3 = Math.max(x4 + dx, 0);
        } else {
          x1 -= boxWidth;
          x2 = Math.max(x1 - dx / 4, 0);
          x4 += boxWidth + 2 * arrowWidth;
          x3 = Math.max(x4 + dx / 4, 0);
        }
      }

      if (x1 + arrowWidth === x4) {
        x2 = x1 + itemHeight + arrowWidth;
        x3 = x2;
      }

      return 'M' + x1 + ',' + y1 + ' C' + x2 + ',' + y2 + ' ' + x3 + ',' + y3 + ' ' + x4 + ',' + y4;
    }

    var save = function() {
      var defaultLocation = {};
      angular.forEach(object[0], function(node) {
        defaultLocation[node.id] = {
          x: node.offsetLeft,
          y: node.offsetTop
        };
      });
      $localStorage.multiObject = defaultLocation;
      toastr.success('保存成功');
    };
    $scope.save = save;
  }

^ CSS

scss->css

path.link {
  fill: none;
  stroke: $brand-info;
  stroke-width: 1.5px;
}

.object {
  width: 160px;
  position: absolute; /* 注意 */
  // .object-settings {
  //   visibility: hidden;
  //   visibility: visible;
  // }
  // &:hover {
  //   .object-settings {
  //       padding: 5px;
  //       background-color: $gray-lighter;
  //       border: 1.5px solid $btn-primary-img-border;
  //       border-top-width: 0px;
  //       border-bottom-right-radius:0.3em;
  //       border-bottom-left-radius:0.3em;
  //       text-align: center;
  //       visibility: visible;
  //   }
  // }
}

.object-settings {
  padding: 5px;
  background-color: #FFFFFF;
  border: 1.5px solid $btn-primary-img-border;
  border-top-width: 0px;
  border-bottom-right-radius:0.3em;
  border-bottom-left-radius:0.3em;
  text-align: center;
}

.object-attrs {
  margin-top: 40px;
  width: 160px;
  background-color: #FFFFFF;
}
.object-attrs > p {
  text-align: center;
  margin: 0px;
  font-size: 15px;
  font-weight: normal;
  height: 25px;
  overflow: hidden;
  text-overflow: ellipsis;
  color: $brand-primary-dark;
  border: 1.5px solid $btn-primary-img-border;
  border-top-width: 0px;
}

.object-header {
  position: absolute;
  cursor: pointer;
  border-top-left-radius:0.2em;
  border-top-right-radius:0.2em;
  border-bottom-right-radius:0em;
  border-bottom-left-radius:0em;
  background-color: $brand-primary-dark;
  color: #FFF;
  width: 160px;
  height: 40px;
  font-size: 26px;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
}

^ 效果图

参考

D3 Mouse Events

SVG Marker-end 显示不出来问题

时间: 2024-09-29 12:32:11

D3实现简单业务拓扑图的相关文章

使用WebSphere Business Events REST接口从应用程序发出简单业务事件

简介 了解业务处理.更具灵敏性.近乎实时地监测管理和遵从性情况是不断增长的 企业业务线需求.基于事件的解决方案通过快速有效地利用机会和减少异常来支持业务和 IT 管理企业风险.当业务事件处理技术与业务线应用结合时,就创造了一个机会来构建解决方案 ,从而提供更多的灵活性并帮助检测关键遵从性和管理情况.事件支持即时发现机会和异常, 也可以发起适当的响应. IBM WebSphere Business Events(以下称为 Business Events)是一个复杂的事件处理引擎,有助于业务基于可操

d3.js实现简单的网络拓扑图实例代码_javascript技巧

前言 了解了D3.js的基本开发和组件以后,我们开始应用它激动人心之处:绚丽的预定义图形,应用D3.js,我们在它的示例文件的基础上稍加变动即可应用于我们的数据可视化工作中,D3.js将后台的运算已经预定义好,我们只需少量代码和规范的数据,就能做出很花哨(请原谅我的用词不当)的效果. 力学图(也称为导向图,也有叫网络拓补图的,反正就是通过排斥得到关系远近的结构)在社交网络研究.信息传播途径等群体关系研究中应用非常广泛,它可以直观地反映群体与群体之间联系的渠道.交集多少,群体内部成员的联系强度等.

Linux主流架构运维工作简单剖析

随着IT运维的不断发展,尤其的Linux的飞速发展,越来越多的企业开始使用Linux操作系统平台,例如CentOS.RedHat.Ubuntu.Fedora等等,成千上亿个网站涌现在当今互联网,互联网已经成为必不可少的工具,那今天我们跟大家一起来分享讨论目前用的最多的Linux下主流网站架构: LVS+KEEPALIVED(heartbeat)+Squid+Nginx/Apache+JAVA/PHP +MySQL/MariaDB等,分享一个简单的拓扑图,供各位同学实验参考 一般网站总体分为四层,

Linux主流架构运维工作简单剖

随着IT运维的不断发展,尤其的Linux的飞速发展,越来越多的企业开始使用Linux操作系统平台,例如CentOS.RedHat.Ubuntu.Fedora等等,成千上亿个网站涌现在当今互联网,互联网已经成为必不可少的工具,那今天我们跟大家一起来分享讨论目前用的最多的Linux下主流网站架构: LVS+KEEPALIVED(heartbeat)+Squid+Nginx/Apache+JAVA/PHP +MySQL/MariaDB等,分享一个简单的拓扑图,供各位同学实验参考 一般网站总体分为四层,

听云APM:新经济环境下的精益化应用管理

3月23日,第八届中国金融云高峰论坛在上海盛大召开,来自国内外政府机构.行业协会.金融银行的首席信息官.数据中心经理.软件开发主任等齐聚一堂,针对银行业新核心系统开发.中小银行如何把握金融创新.大数据技术在银行数据中心的建设等多个热点话题展开讨论,听云华东技术总监王凡就传统金融的互联网转型在会场与现场观众进行了相关分享. 以下为演讲内容: 一.2017年金融市场的三大热词 非常高兴有机会能够和大家一起探讨一下在新经济形势下精益化的应用性能管理.   2017年经济将会有些变动,前段时间刚好两会召

云终端:让云应用向普通人普及

康钊:各位来宾大家好,我们开始云终端的论坛.自我介绍一下,我是新浪网的首席记者,我主要是在科技领域从事报道,有些说我是新浪科技的报道实际上是一回事.我今天有幸来主持这个论坛,今天是2012年云计算大会的召开日,前面大家也都已经是聆听了的发言,接下来是云终端的论坛,云这个东西,今天其实大家都已经很熟悉了,各位专家讲了很多见解,我不多说了.关键是下一场的终端,如果云的对象应用的话,如果没有终端,我认为只能叫云设备了,中国电信就够用了.只有有了终端,我们才能够实现个人办公用或者说单位配备给个人用,所以

Lvs+keepalived 高可用性负载均衡自动化配置

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://navyaijm.blog.51cto.com/4647068/809397 前言* 随着互联网的发展,提供用户访问的web服务器,必须要保证每天24不间断服务,访问量不断增加,有什么好的web架构既能实现高可用性负载均衡,而且价格又是免费的呢?答案有木有?有!lvs+keepalived 是不错的选择!   一.实验环境:4台centos 5.4 ,以及简单的拓扑图: LVS-

利用Spring框架改进J2EE编程

j2ee|编程 摘要 J2EE编程正在变得越来越复杂.J2EE已经发展为一个API.复杂化的编程和配置的复杂网络.为了应对这种复杂性,新的框架和方法不断涌现.这些框架高度依赖于一个称为IoC(Inversion of Control,反向控制)的概念.本文将探讨这种方法的一些特性和优点,因为这种方法与J2EE编程相关,而且可以使J2EE编程变得更轻松. 简介 马克·吐温的一句话常被引用:"--关于我死亡的报道是一种夸张."现在已经出现了很多关于.Net的流言,以及认为J2EE API的

电信网管中的Java客户端(二)

客户端|网管 电信网管中的Java客户端(二) 1.概述前文讲述了用Java开发电信网管界面系统遇到的困难.其中,制作网络拓扑图是我们第一个必须克服的困难.本文概述如何使用和制作网络拓扑图的产品和方法和思路. 2.电信网络拓扑组件的要求网络拓扑图是电信网管客户端的核心.对于电信网络,在使用任何网络拓扑组件时,必须注意电信网络的一些特点: · 数据量大.一般电信网络的规模都比较大,网络设备数量多,拓扑复杂.网络拓扑图界面必须考虑到能够处理大数据量的网络节点和连接. · 多层次展示网络.在一个综合电