前言

定位browser 的 chart,   VML,SVG, HTML5 Canvas使用的方式各不一样。

如果使用现有的js  library (各种实现js 图表的library汇总与比较) , 调用的API方式也肯定不同。

举个例子: draw2d 使用addFigure 和 setPosition 都可以设置图的位置。

混在特定技术或是特定library 里去layout , 很明显不是一个明智之举。

切分开来, layout 的功能对于任何的图形绘制都适用。就是本章所讨论的了。

实现思想

其实实现思想很简单,维护一个JS 的object(Graph)。 在这个Object 里记录节点,边的信息; 
节点包含有如下信息:
id  -- 表示符
x  -- 横坐标
y  -- 纵坐标
shape -- 绘制的图
这样的话, 在绘制一个图节点之前, 先要在这个Graph 维护这个图节点的一些信息。

Graph 示例

var Graph = function() {this.nodeSet = {};this.nodes = [];this.edges = [];this.adjacency = {};this.nextNodeId = 0;this.nextEdgeId = 0;this.eventListeners = [];
};var Node = function(id, data) {this.id = id;this.data = typeof(data) !== 'undefined' ? data : {};
};var Edge = function(id, source, target, data) {this.id = id;this.source = source;this.target = target;this.data = typeof(data) !== 'undefined' ? data : {};
};Graph.prototype.addNode = function(node) {if (typeof(this.nodeSet[node.id]) === 'undefined') {this.nodes.push(node);}this.nodeSet[node.id] = node;this.notify();return node;
};Graph.prototype.addEdge = function(edge) {var exists = false;this.edges.forEach(function(e) {if (edge.id === e.id) { exists = true; }});if (!exists) {this.edges.push(edge);}if (typeof(this.adjacency[edge.source.id]) === 'undefined') {this.adjacency[edge.source.id] = {};}if (typeof(this.adjacency[edge.source.id][edge.target.id]) === 'undefined') {this.adjacency[edge.source.id][edge.target.id] = [];}exists = false;this.adjacency[edge.source.id][edge.target.id].forEach(function(e) {if (edge.id === e.id) { exists = true; }});if (!exists) {this.adjacency[edge.source.id][edge.target.id].push(edge);}this.notify();return edge;
};Graph.prototype.newNode = function(data) {var node = new Node(this.nextNodeId++, data);this.addNode(node);return node;
};Graph.prototype.newEdge = function(source, target, data) {var edge = new Edge(this.nextEdgeId++, source, target, data);this.addEdge(edge);return edge;
};// find the edges from node1 to node2
Graph.prototype.getEdges = function(node1, node2) {if (typeof(this.adjacency[node1.id]) !== 'undefined'&& typeof(this.adjacency[node1.id][node2.id]) !== 'undefined') {return this.adjacency[node1.id][node2.id];}return [];
};// remove a node and it's associated edges from the graph
Graph.prototype.removeNode = function(node) {if (typeof(this.nodeSet[node.id]) !== 'undefined') {delete this.nodeSet[node.id];}for (var i = this.nodes.length - 1; i >= 0; i--) {if (this.nodes[i].id === node.id) {this.nodes.splice(i, 1);}}this.detachNode(node);};// removes edges associated with a given node
Graph.prototype.detachNode = function(node) {var tmpEdges = this.edges.slice();tmpEdges.forEach(function(e) {if (e.source.id === node.id || e.target.id === node.id) {this.removeEdge(e);}}, this);this.notify();
};// remove a node and it's associated edges from the graph
Graph.prototype.removeEdge = function(edge) {for (var i = this.edges.length - 1; i >= 0; i--) {if (this.edges[i].id === edge.id) {this.edges.splice(i, 1);}}for (var x in this.adjacency) {for (var y in this.adjacency[x]) {var edges = this.adjacency[x][y];for (var j=edges.length - 1; j>=0; j--) {if (this.adjacency[x][y][j].id === edge.id) {this.adjacency[x][y].splice(j, 1);}}}}this.notify();
};/* Merge a list of nodes and edges into the current graph. eg.
var o = {nodes: [{id: 123, data: {type: 'user', userid: 123, displayname: 'aaa'}},{id: 234, data: {type: 'user', userid: 234, displayname: 'bbb'}}],edges: [{from: 0, to: 1, type: 'submitted_design', directed: true, data: {weight: }}]
}
*/
Graph.prototype.merge = function(data) {var nodes = [];data.nodes.forEach(function(n) {nodes.push(this.addNode(new Node(n.id, n.data)));}, this);data.edges.forEach(function(e) {var from = nodes[e.from];var to = nodes[e.to];var id = (e.directed)? (id = e.type + "-" + from.id + "-" + to.id): (from.id < to.id) // normalise id for non-directed edges? e.type + "-" + from.id + "-" + to.id: e.type + "-" + to.id + "-" + from.id;var edge = this.addEdge(new Edge(id, from, to, e.data));edge.data.type = e.type;}, this);
};Graph.prototype.filterNodes = function(fn) {var tmpNodes = this.nodes.slice();tmpNodes.forEach(function(n) {if (!fn(n)) {this.removeNode(n);}}, this);
};Graph.prototype.filterEdges = function(fn) {var tmpEdges = this.edges.slice();tmpEdges.forEach(function(e) {if (!fn(e)) {this.removeEdge(e);}}, this);
};Graph.prototype.addGraphListener = function(obj) {this.eventListeners.push(obj);
};Graph.prototype.notify = function() {this.eventListeners.forEach(function(obj){obj.graphChanged();});
};

[Web Chart系列之四] 图形布局-Layout 之js设计实现相关推荐

  1. [Web Chart系列之三] 图形布局-Layout

    前言 从上一篇: [Web Chart系列之二] 各种实现js 图表的library汇总与比较 的介绍, 目前提供提供绘制矢量图的library 还是很多的.  如果只是需要绘制一些柱状图, 饼图, ...

  2. [Web Chart系列之五] 图形布局-Circle Layout 之实现

    前言 关于Circle Layout 的基本介绍, 可以参考: [Web Chart系列之三] 图形布局-Layout 布局的现实使用状况 这里使用这种布局来布局特定对象的关联. 这里的这些对象类似于 ...

  3. [Web Chart系列之一(续)]Web端图形绘制SVG,VML, HTML5 Canvas 简单实例

    前言 本篇是继 [Web Chart系列之一]Web端图形绘制SVG,VML, HTML5 Canvas 技术比较 的补充和实例说明各种技术的使用方式. VML 的用法和实例 引入命名空间之后,就可以 ...

  4. [Web Chart系列之六] canvas Chart 导出图文件

    介绍 使用SVG绘制的图形可以导出为svg 格式的文件,使用浏览器等可以查看. 是否可以导出为png, gif 格式的文件呢? 当然是可以. 只是在 web 直接创建和操作文件是不建议的,而且存在各浏 ...

  5. [Web Chart系列之一]Web端图形绘制SVG,VML, HTML5 Canvas 技术比较

    先介绍一下矢量图的概念: 矢量图使用直线和曲线来描述图形,这些图形的元素是一些点.线.矩形.多边形.圆和弧线等等,它们都是通过数学公式计算获得的.例如一幅花的矢量图形实际上是由线段形成外框轮廓,由外框 ...

  6. [Web Chart系列之五] 3. 实战draw2d 之图形填充色(纯色 or 渐变)

    颜色渐变 draw2d 目前没有提供直接对Figure 设置渐变效果的API. 但是raphael 有提供, 这样的话基本上在draw2d实现渐变成为可能. 颜色渐变功能来源 raphael 提供的图 ...

  7. [Web Chart系列之二] 各种实现js 图表的library汇总与比较

    前言 使用js 在浏览器展现图表, 参考系列一 Web端图形绘制SVG,VML, HTML5 Canvas 技术比较 汇总 目前实现web 图表的js library 数量是很多, 此处汇总: Nam ...

  8. [Web Chart系列之五] 1. 实战draw2d 之总体介绍

    draw2d 是什么? 首先需要明确的是这里指的draw2d是个什么东东? 用draw2d这个关键字,询问一下谷哥和度娘基本上会找到两个东西 一个是集成在eclipse(也可以单独使用) 里面使用SW ...

  9. [Web Chart系列之五] 4. 实战draw2d(Raphael)之取消Chrome中Label Text 全部选中

    情况描述 这里使用的是Rectangle , 里面加入一个Label 或多个Label 的组合图形. 在Chrome里拖拽图形的时候,偶尔会把所有Rectangle包含的Label 全部以深蓝色底色. ...

最新文章

  1. 圆方圆python入门:如何学习(二)
  2. rxjs of操作符里subscribeToArray的实现原理示意图及分析
  3. mac升级10.12后,安全和隐私中没有了安装任何来源的选项的解决办法
  4. 15种能力:决定了你的未来能走多远
  5. 分享30个应用HTML5的网站案例
  6. Kettle:创建资源库
  7. C#程序打包与部署,包括处理安装向导中用户输入的参数,创建卸载程序。
  8. 函数-函数进阶-装饰器
  9. 阿里云云计算 39在线实验--PolarDB MySQL
  10. 遗传算法讲解与实现(python)
  11. PowerBuilder 2017R3安装指南2021最新
  12. Flutter项目网络图片调试模式正常,打包后不显示(Android)
  13. 谷歌浏览器加载不了js_优化谷歌排名的必备技巧
  14. 猜数字(Bulls and Cows)游戏
  15. 稳压二极管与TVS管
  16. 华为matebook笔记本鸿蒙,聊聊鸿蒙对笔记本电脑行业的影响
  17. 企业微信怎么输入服务器id,微信企业号的agentid怎么查看?如何获取?
  18. Windows 使用命令强制删除文件及文件夹
  19. 科班出身程序员和培训出来的程序员区别在哪?
  20. 电力电子应用技术的matlab仿真

热门文章

  1. Atitit orm的实现模式 data-mapper模式和active-record模式有什么区别
  2. 如何在官网下载java JDK的历史版本
  3. CentOS中TFTP配置
  4. 修改 Chrome浏览器主页被劫持 chrome 主页被篡改成hao.qquu8.com的解决方案
  5. 【白皮书分享】2021智慧城市白皮书:城市建设运营数字化转型.pdf(附下载链接)...
  6. 【年度重磅】《2021营销自动化应用基准报告》正式发布!
  7. 【论文】Awesome Relation Extraction Paper(关系抽取)(PART V)
  8. 【数据结构与算法基础】线性表
  9. android第三方launcher,目前Android平台最好的Launcher
  10. php 关键词回复 图片,php微信开发之关键词回复功能