mxGraph开发手册

mxGraph简介

mxGraph是使用SVG和HTML进行渲染的完全客户端JavaScript图形库。

mxGraph支持IE 11, Chrome 43+, Firefox 45+, Safari 10 and later, Opera 30+,未使用第三方JS.mxGraph提供后端.net、java的接口,以支持在后端进行图形的修改、图形I/O、图形布局.

Hello World

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<html>
<head>
<title>Hello, World! example for mxGraph</title>

<!-- Sets the basepath for the library if not in same directory -->
<script type="text/javascript">
mxBasePath = '../src';
</script>

<!-- Loads and initializes the library -->
<script type="text/javascript" src="../src/js/mxClient.js"></script>

<!-- Example code -->
<script type="text/javascript">
// Program starts here. Creates a sample graph in the
// DOM node with the specified ID. This function is invoked
// from the onLoad event handler of the document (see below).
function main(container)
{
// Checks if the browser is supported
if (!mxClient.isBrowserSupported())
{
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
// Creates the graph inside the given container
var graph = new mxGraph(container);

// Enables rubberband selection
new mxRubberband(graph);

// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
var parent = graph.getDefaultParent();
// 禁止容器右键事件
mxEvent.disableContextMenu(ele);
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try
{
var v1 = graph.insertVertex(parent, null,
'Hello,', 20, 20, 80, 30);
var v2 = graph.insertVertex(parent, null,
'World!', 200, 150, 80, 30);
var e1 = graph.insertEdge(parent, null, '', v1, v2);
}
finally
{
// Updates the display
graph.getModel().endUpdate();
}
}
};
</script>
</head>

<!-- Page passes the container for the graph to the program -->
<body onload="main(document.getElementById('graphContainer'))">

<!-- Creates a container for the graph with a grid wallpaper -->
<div id="graphContainer"
style="overflow:hidden;width:321px;height:241px;background:url('editors/images/grid.gif')">
</div>
</body>
</html>

目前比较流行的用户制作(UML、ERD、BPMN)的图表库

目前比较流行的用户制作(UML、ERD、BPMN)的图表库有:

  • JointJS & Rappid(商业版本)
  • jsPlumb
  • GoJS
  • AntV G6

JointJS &Rappid(JointJS 的商业)

JointJS图表库,通过JavaScript和SVG为所有现代浏览器创建完全交互式的图表工具。MV体系结构将图形,元素和链接模型与它们的呈现分离开来,这使将JointJS轻松插入后端应用程序变得容易。 JointJS基于Backbone MVC库构建的,并依赖于jQuery和Lodash。

核心概念

每个概念分别对应view和model两种概念(前后分别是model和view概念):

  • element,elementView 元素
  • link,linkView 连线
  • graph,paper 画布

jointJS中,视图和模型是分离的,不同概念的模型和视图之间是不能发生联系的,比如把元素添加到画布上,可以使用element.addTo(graph) 或者 graph.add(element) ,但是不能使用element.addTo(paper)这样的操作,因为element是model概念,而paper是视图概念,两者不能直接操作。

mxGraph介绍

mxGraph是什么

mxGraph是一个JavaScript图表库,可以快速创建交互式图形和图表应用程序,这些应用程序可以在其供应商支持的任何主流浏览器中本地运行。

mxGraph是用JS编写,通过SVG和HTML进行绘图的渲染,没有依赖其他项目.

mxGraph在2005年创建,作为商业项目一直持续到2016年,2016年创建者以Apache 2.0开源协议在GitHub上公布源码。

但到现在还有维护更新,流行的免费绘图平台draw.io是基于mxGraph开发.

mxGraph支持目前所有主流的浏览器: (IE11, Chrome 43+,Firefox 45+,Safari 10, Edge 31+)

⚠️mxGraph提供图形关系视图绘制接口,业务场景中的功能需要自己调用接口实现.

draw.io是个图形绘制平台,提供了一套完整的图形绘制功能.

npm-link说明书

npm-link将本地的两个npm包建立软链接,方便在开发阶段快速调测.

假设项目my-project是我们开发项目, 需要用到独立my-utils模块. 在开发阶段my-utils中的修改我们希望可以实时同步到my-project项目中.

将两个npm包建立链接只需要2步.

十大经典排序算法(上)

算法是计算机世界永恒的主题,现在世界其实是被算法驱动着进步.学习算法并能熟练在自己业务场景中应用各种算法应该是每个程序员必备的素质.从最基础的十大经典排序算法作为开始,开启自己系统学习算法之路!

冒泡排序(Bubble Sort)

思想

  • 冒泡排序只会操作相邻的两个元素
  • 每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求.如果不满足就让它们俩互换.
  • 冒泡排序算法最多进行 n-1次(n 排序数组长度),每次算法执行元素对比次数是n - i -1次(n 排序数组长度, i 当前算法循环次数)

4208590040-5ac42b210af83_articlex.gif

116807884-57dcd3a8c4bf4_articlex.gif

Proxy、Reflect

ECMAScript2015开始,JavaScript新增了ProxyReflect对象.通过这两个对象你可以拦截并自定义语言原来的操作行为(例如:属性查找、赋值、枚举、函数调用等).借助这两个对象你可以在JavaScript进行元级别进行编程(元编程).

面向对象设计模式原则

设计模式(Design Patterns):维护、扩展代码的组织形式。它是开发人员对于代码组织方式的总结,每一种设计模式都是针对不同的代码逻辑场景提出最优的代码组织方式。

每个设计模式都会遵循一个或多个设计原则,这些原则有:

  1. 单一职责原则(Single Responsibility Principle, SRP)
  2. 开闭原则(Open Closed Principle,OCP)
  3. 里氏代换原则(Liskov Substitution Principle,LSP)
  4. 接口隔离原则(Interface Segregation Principle,ISP)
  5. 依赖倒转原则(Dependency Inversion Principle,DIP)
  6. 迪米特法则(Law of Demeter,LOD)
  7. 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
标记 设计模式原则名称 简单定义
SRP 单一职责原则 一个类只负责一个功能领域中的相应职责
OCP 开闭原则 对扩展开放,对修改关闭
LSP 里氏代换原则 所有引用基类的地方必须能透明地使用其子类的对象
ISP 接口隔离原则 类之间的依赖关系应该建立在最小的接口上
DIP 依赖倒转原则 依赖于抽象,不能依赖于具体实现
LOD 迪米特法则 一个软件实体应当尽可能少的与其他实体发生相互作用
CARP 合成/聚合复用原则 尽量使用合成/聚合,而不是通过继承达到复用的目的

单一职责原则_、_开闭原则_、_里氏代换原则_、_接口隔离原则依赖倒转原则 就是我们平常熟知的SOLID

Object.defineProperty

Object.defineProperty可以用来给Object增加新的属性或更新已有属性,并返回该Object.

Object.defineProperty并不单单只是让我们手动给Object添加或修改属性值,它最大的特点是我们可以给对象单个属性值添加属性描述符(PropertyDescriptor).

属性描述符可以给当前对象属性添加额外的一些功能,例如:是否可以被修改、是否可以被枚举、捕获该属性的值的变化和读取.

注意: 冻结一个对象属性操作可以用 Object.freeze()

注意: 可以用Object.defineProperties批量给对象添加或修改属性描述符

requestAnimationFrame

在制作页面动画时,我们可以通过定时器(setTimeoutsetInterval)循环操作DOM节点来实现动画的效果.

但是Google 最佳JS实践要求使用requestAnimationFrame代替定时器.这是为什么呢?

原因有三个:

  1. setTimeout\setInterval并不和JS在一个线程上,虽然你可以模拟浏览器刷新频率(1000/60),但如果JS线程执行时间较长,JS出超过这个时间去保存有setTimeout\setInterval回调的队列中拿回调执行.这个时候页面会出现卡顿的情况.
  2. 在一些浏览器中,运行有setTimeout\setInterval的脚本的页面,即使当前未被打开,定时器脚本依然是在后台运行的.这就浪费了计算机资源.
  3. 并不是所有的浏览器都是每秒60帧频率,所以setTimeout\setInterval的定时时间需要适配设备.

requestAnimationFrame就不会有上面这三个问题!

设计模式-状态模式

状态模式是一种行为软件设计模式.一个对象在其内部状态改变时会改变它的行为.各种状态和状态改变行为的操作是被独立封装的..

一般情况是:如果一个事物有多钟状态,我们用一个变量保存当前状态名(string),通过if-else 做状态的判断,然后进行状态的变更.

这样最大的问题是: 你需要将所有的状态和变更状态后的行为都放在一个方法里.这个方法会变得很臃肿和复杂.会变的难以阅读和维护.

状态模式:将各种状态和状态之间切换的行为封装在一起.只需要一个Context来触发状态变化,而状态变化后引起的行为操作Context不用处理.

状态模式的优点:

  1. 状态和行为关系封装在一起,增加新的状态和状态转换会很容易
  2. 对象代替字符串保存当前状态,状态的可切换一目了然
  3. 避免了Context无限膨胀
  4. Context中的请求动作和状态类中封装的行为非常容易,它们独立变化而不互相影响

状态模式的缺陷:

  1. 逻辑分散在状态类中,虽然避免的条件分支但也导致了逻辑分散问题
  2. 新增了封装状态和行为变化的对象,增加了代码量.

设计模式-装饰者模式

饰模式是种动态的向一个类(方法)添加行为的设计模式.它不会直接修改原类(方法).

装饰模式比生成子类更灵活,它不会影响原来的类(方法),可以增对单独的方法增加新的行为.

在面向对象的编程中,装饰器模式是一种设计模式,它允许将行为静态或动态地添加到单个对象,而不会影响同一类中其他对象的行为。装饰器模式通常用于遵守单一责任原则,因为它允许在具有独特关注区域的类之间划分功能。

设计模式-职责链模式

职责链模式是一种行为型设计模式,它将一些列可能会处理请求的对象连接成在一起,请求在这些对象间传递,直到遇到可以处理它的对象.这些处理请求的对象称为链中的节点.

职责链模式优点:

  • 解耦请求的发送者和N个接受者之间复杂关系.
  • 手动指定起始节点.
  • 链中的节点对象可以灵活拆分重组.

注意: 职责链模式有个缺陷是,大部分的节点并没有实质的作用,它们的作用仅仅是让请求传递下去,从性能方面考虑我们要避免过长的职责链带来的性能消耗.

职责链模式可以很好地帮助我们管理代码,降低发起请求的对象和处理请求对象之间的耦合性.

5bd5b48157043.png

设计模式-中介者模式

中介者模式是一种行为型设计模式,它的目的是通过增加一个中介对象,解除对象与对象之间的紧耦合关系.

增加中介对象后,所有的相关对象都通过中介对象来通信,而不是互相引用,所有当一个对象发生改变时,只需要通知中介者对象即可.

mediator-pattern22.png

设计模式-享元模式

享元模式(Flyweight)是一种软件设计模式.是通过将类似的对象进行共享,达到最小化内存的使用对象.

享元模式要求将对象的属性划分为内部状态(不会改变属性)和外部状态(会动态变化的属性).享元模式的目标是尽量减少共享对象的数量.它的关键点是划分内部状态和外部状态.

享元模式特点:

  • 内部状态存储于对象内部
  • 内部状态可以被一些对象共享
  • 内部状态独立于具体的场景,通常不会变化
  • 外部状态取决于具体的场景,并根据场景而变化,外部状态不会被共享.

注意: 享元模式是一种用时间换空间的优化模式.

设计模式-模板方法模式

模板方法模式是一种行为设计模式,它是需要通过继承实现的设计模式.

模板方法模式有两个部分组成.

  1. 抽象父类.它定义了算法操作框架和具体的算法执行流程.(一般在父类定义 init 方法作执行算法)
  2. 具体实现抽象父类的子类. 子类实现了父类定义的算法结构,但最后的执行通过父类实现的方法执行.

注意: 父类只负责定义算法框架,具体实现有子类完成.不同的子类,实现抽象类定义的抽象方法可以不同,但子类不应该改变算法的执行步骤!

设计模式-适配器模式

适配器模式是一种很简单的软件设计模式,它允许将现有的类(方法)用作另一个接口.它通常用于使现有类(方法)与其他类(方法)一起工作而无需修改其源码.

适配器模式看起和装饰者模式、代理模式看起来很像.但它们在设计目的上还是有不同的:

  • 适配器模式主要是用来解决两个已有接口之间不匹配的问题,它不考虑这些接口具体的实现,也不考虑它们将如何演化.适配器不需要改变已有的接口,就能够使它们协同作用.
  • 装饰者模式和代理模式也不会改变原有对象的接口,但装饰者模式的作用是为了给对象增加功能.代理模式是为了控制对象的访问,通常也只包装一次.

设计模式-组合模式

组合模式是一种结构型设计模式,组合模式将对象以树形结构组合在一起,每一个对象具有相同的属性和方法.组合模式允许客户用统一的方式处理单个对象.

组合模式的特点:

  1. 表示树形结构.可以非常方便描述对象部分-整体层次结构.
  2. 利用对象多态性统一对待组合对象和单个对象.在组合模式中,使用者将统一地使用组合结构中的所有对象,而不用关心它究竟是组合对象还是单个对象.

设计模式-命令模式

命令模式(Command pattern)是一种行为设计模式,它封装的对象包含稍后执行所需要的方法名和该方法需要的参数.

命令对象发送者和接受者并不知道彼此,他们也不关心.这样就将可以消除的发送者和接受者之间的耦合关系.

命令模式带来的好处有:

  1. 重复多次操作(例如:重复下单)
  2. 取消操作(例如:下的订单取消掉)
  3. 取消后重做操作(例如:订单的支付取消,然后再进行支付)
  4. 操作行为回溯(例如:象棋中的悔棋操作)