CRLF -> LF

This commit is contained in:
Jackson Tian 2012-11-26 18:31:44 +08:00
parent c1e8f006e8
commit 3c71e8e49b
16 changed files with 9517 additions and 9511 deletions

View File

@ -1,308 +1,314 @@
# DataV项目编码规范
一套良好的编码规范如果在团队开发中被遵守可以降低团队成员之间交流的成本同时也降低犯错的几率。可以说编码规范只需花费20%的精力来遵循却可以降低80%的犯低级错误几率。
这一版的编码规范主要查考了Douglas Crockford的JSLint的检查条件和过去的一些编码经验整理而出。
## 命名空间
项目的总命名空间为:**`DataV`**。
除了Rapheal和D3自身的代码外我们提交的任何方法都应该挂载在`DataV`命名空间中。
例外:某些方法和功能可以独立抽取出来,适用于别的项目。但是也应该由一个命名空间来管理它们。
## 语法
### 缩进规范
由于该项目是普通的前端JavaScript项目所以缩进采用4个空格的方式。禁止使用tab符号。
推荐更改编辑器中的设置使得按tab键可以自动插入4个空格。
每一层级之间,要保证缩进是正确的。
### 空格
* `=`前后应该存在一个空格
* `(`前面应该存在一个空格
* `)`后面应该存在一个空格
* `{`前面应该存在一个空格
### 分号
每一个申明或者定义,都应该以分号结尾。
var username = "Jackson";
var foo = function () {};
每一行调用都应该明确以分号结尾。
foo();
### 大括号
请明确使用`{}`来约束代码段。
推荐:
if (condition) {
foo = "bar";
}
不推荐:
if (condition) boo = "bar";
## 命名规范
### 变量
采用驼峰首字母小写,后续单词均需大写首字母,不得在中间包含下划线。
每一个变量都应该通过`var`申明,以防止变量污染。
正确:
var pipeChart;
错误:
var pipechart;
var pipe_chart;
### 方法
方法名同变量名,采用驼峰式命名。
定义方法均通过`var foo = function () {};`而不是`function foo () {}`
var foo = function () {
// TODO
};
方法名应该可以表示方法的行为和暗示方法的返回值。善用`set``get``is``has`等方法前缀。
### 类
由于JavaScript中类和方法的关键字都是`function`,为了区别两者的混淆,类名的定义通常是大写首字母,以表示它是一个作为类来调用的。
var Person = function () {
// TODO
};
类的方法请尽量赋值在`prototype`属性上,使得通过原型链查找的方式降低内存占用。
类的数据请尽量在构造函数中赋值,以加快执行时的查找速度。
var Person = function (age) {
this.age = age; // 在构造函数中赋值数据
};
// 在原型链中设置方法
Person.prototype.getAge = function () {
return this.age;
};
对于私有方法,在前面添加下划线表示不推荐被外部调用。
Persion.prototype._sleep = function () {};
### 模块
为了统一规划,我们的类均需通过模块的定义方式,与命名空间结合,以保证环境的干净。
(function () {
var private = "I am private";
var Person = function () {
this.username = private;
};
DataV.Person = Person;
}());
## 注释
注释对于团队而言是十分重要的,每一个方法都应该包含说明。
必选的注释是方法的说明,方法的参数,和一个例子。
任何诡异的地方,都应该附有简单的注释来描述它,以提醒后来人注意,以区别对待。
/**
* Create chart panel by passin width and height
* @param {string} type Type name
* @param {number} width Chart panel's width value
* @param {number} height Chart panel's height value
* @example
* createChart("pipe", 500, 500);
*/
var createChart = function (type, width, height) {
// Trick comments
trickCall();
};
通过[jsdoc](http://code.google.com/p/jsdoc-toolkit/w/list)的注释将利于我们后期导出API文档。
## 文件名
文件名的方式也是通过驼峰式,但是以下划线分割单词,一律小写单词。如:
d3.js
child_process.js
## JSLint扫描代码
JSLint的调用方式如下
node precommit.js file
配置方式存放在`config.json`中。
## 目录结构说明
目前datav组件库的目录结构如下
```
JacksonTianmatoMacBook-Pro:datav.js jacksontian$ tree -d
.
├── bin
├── deps
├── doc
├── example
├── lib
└── test
```
其中详细说明一下:
- `bin`目录用于存放一些可运行的脚本或者工具,例如`jslint`
- `deps`目录用于存放项目的依赖文件,其中有`raphael``d3`的相关文件。
- `doc`目录用于用于存放项目的文档如API生成文档或一些说明文档。
- `example`目录存放案例代码。
- `lib`目录为组件库具体代码,根据每个图的类型不同,存为对应文件。
- `test`目录存放单元测试代码或自动化测试代码。
## 单元测试
`DataV`项目采用[`QUnit`](http://docs.jquery.com/QUnit)作为测试框架,详细文档请见。
简单测试例子:
```
// 分模块
module("DataV");
// 测试用例
test("Themes.get", function () {
// 单个断言
equal(DataV.Themes.get("inexsit"), undefined, "Should get undefined when key is inexsit");
equal(DataV.Themes.get("COLOR_MODE"), "gradient", "Should get gradient when key is COLOR_MODE");
equal(typeof DataV.Themes.get("COLOR_ARGS"), "object", "COLOR_ARGS should be an object");
equal(DataV.Themes.get("COLOR_ARGS").length, 2, "COLOR_ARGS should have two items");
});
```
## 数据格式
数据格式统一采用二维表的方式,结构比较类似数据库中的表。列名通过文档详细来描述,写在代码的[jsdoc](http://code.google.com/p/jsdoc-toolkit/w/list)的注释中。
标准数据格式例子如下:
```
/**
* 设置数据源
* Example 举个例字假设下面的数组表示2个人在一年4个季度的消费。第一个人在4个季度里消费了1、2、3、9元。第二个人消费了3、4、6、3元。
* [
* [1,2,3,9],
* [3,4,6,3]
* ]
* @param {Array} source 数据源数组.
*/
Stream.prototype.setSource = function (source) {
// TODO
};
```
所有的组件库的调用都是相同的接口`setSource`
```
var stream = new DataV.Stream("chart");
stream.setSource(source);
stream.render();
```
## 事件注入
每一个组件都可能向外提供一些事件钩子包括DOM事件或者业务逻辑事件。绑定的方式十分简单
```
stream.on("click", function (event) {
console.log(event);
});
stream.on("dblclick", function (event) {
alert("double click");
});
stream.on("contextmenu", function (event) {
alert("mouse right");
});
```
组件的内部实现是通过继承`EventProxy`提供自定义方式,在创建画布后,就绑定一些必要的事件到画布节点上,然后将事件触发出去。如果用户如上文,侦听了这些业务事件,将会调用执行。
```
Stream.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = Raphael(this.node, conf.width, conf.height);
this.DOMNode = $(this.canvas.canvas);
var that = this;
this.DOMNode.click(function (event) {
that.trigger("click", event);
});
this.DOMNode.dblclick(function (event) {
that.trigger("dblclick", event);
});
this.DOMNode.bind("contextmenu", function (event) {
that.trigger("contextmenu", event);
});
this.DOMNode.delegate("path", "click", function (event) {
that.trigger("path_click", event);
});
};
```
## 常见错误
### 判断一个对象是否是数组
下面是宁朗写的:
```
if (color.constructor !== Array) {
throw new Error("The color should be Array");
}
```
下面是Underscore的方法
```
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) == '[object Array]';
};
```
### 数组去重
```
// make an array's every element unique by delete other same element
Array.prototype.uniq = function () {
var temp = {},
len = this.length;
for (var i = 0; i < len; i++) {
if (typeof temp[this[i]] == "undefined") {
temp[this[i]] = 1;
}
}
this.length = 0;
len = 0;
for (var i in temp) {
this[len++] = i;
}
return this;
};
```
这里可以调用underscore的uniq方法即可。节省N行代码量
### 元素是否存在数组中
```
//check if a string is in an array
var _strInArray = function (str, array) {
var i = 0,
l = 0;
for (i = 0, l = array.length; i < l; i++) {
if (array[i] === str) {
return true;
}
}
return false;
};
```
换用`_.indexOf(array, value)`可以节省代码量且返回值比boolean值更有价值
### meta
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
希望大家潮一点,别在写上面那行代码了。下面的表达方式更简洁,且无任何副作用。
<meta charset="utf-8" />
### script标签的type属性
<script type="text/javascript" src="../../deps/d3.js"></script>
如果是默认的text/javascript的话就可以直接省略掉。变成下面这样子
# DataV项目编码规范
一套良好的编码规范如果在团队开发中被遵守可以降低团队成员之间交流的成本同时也降低犯错的几率。可以说编码规范只需花费20%的精力来遵循却可以降低80%的犯低级错误几率。
这一版的编码规范主要查考了Douglas Crockford的JSLint的检查条件和过去的一些编码经验整理而出。
## 命名空间
项目的总命名空间为:**`DataV`**。
除了Rapheal和D3自身的代码外我们提交的任何方法都应该挂载在`DataV`命名空间中。
例外:某些方法和功能可以独立抽取出来,适用于别的项目。但是也应该由一个命名空间来管理它们。
## 语法
### 缩进规范
由于该项目是普通的前端JavaScript项目所以缩进采用2个空格的方式。禁止使用tab符号。
推荐更改编辑器中的设置使得按tab键可以自动插入2个空格。
每一层级之间,要保证缩进是正确的。
### 空格
* `=`前后应该存在一个空格
* `(`前面应该存在一个空格
* `)`后面应该存在一个空格
* `{`前面应该存在一个空格
### 分号
每一个申明或者定义,都应该以分号结尾。
var username = "Jackson";
var foo = function () {};
每一行调用都应该明确以分号结尾。
foo();
### 大括号
请明确使用`{}`来约束代码段。
推荐:
if (condition) {
foo = "bar";
}
不推荐:
if (condition) boo = "bar";
## 命名规范
### 变量
采用驼峰首字母小写,后续单词均需大写首字母,不得在中间包含下划线。
每一个变量都应该通过`var`申明,以防止变量污染。
正确:
var pipeChart;
错误:
var pipechart;
var pipe_chart;
### 方法
方法名同变量名,采用驼峰式命名。
定义方法均通过`var foo = function () {};`而不是`function foo () {}`
var foo = function () {
// TODO
};
方法名应该可以表示方法的行为和暗示方法的返回值。善用`set``get``is``has`等方法前缀。
### 类
由于JavaScript中类和方法的关键字都是`function`,为了区别两者的混淆,类名的定义通常是大写首字母,以表示它是一个作为类来调用的。
var Person = function () {
// TODO
};
类的方法请尽量赋值在`prototype`属性上,使得通过原型链查找的方式降低内存占用。
类的数据请尽量在构造函数中赋值,以加快执行时的查找速度。
var Person = function (age) {
this.age = age; // 在构造函数中赋值数据
};
// 在原型链中设置方法
Person.prototype.getAge = function () {
return this.age;
};
对于私有方法,在前面添加下划线表示不推荐被外部调用。
Persion.prototype._sleep = function () {};
### 模块
为了统一规划,我们的类均需通过模块的定义方式,与命名空间结合,以保证环境的干净。
(function () {
var private = "I am private";
var Person = function () {
this.username = private;
};
DataV.Person = Person;
}());
## 注释
注释对于团队而言是十分重要的,每一个方法都应该包含说明。
必选的注释是方法的说明,方法的参数,和一个例子。
任何诡异的地方,都应该附有简单的注释来描述它,以提醒后来人注意,以区别对待。
/**
* Create chart panel by passin width and height
* @param {string} type Type name
* @param {number} width Chart panel's width value
* @param {number} height Chart panel's height value
* @example
* createChart("pipe", 500, 500);
*/
var createChart = function (type, width, height) {
// Trick comments
trickCall();
};
通过[jsdoc](http://code.google.com/p/jsdoc-toolkit/w/list)的注释将利于我们后期导出API文档。
## 文件名
文件名的方式也是通过驼峰式,但是以下划线分割单词,一律小写单词。如:
d3.js
child_process.js
## 文件内容
### 换行符
请用Unix的CRLF换行符
### 文件编码
请用UTF-8 without BOM作为文件内容的编码
## JSLint扫描代码
JSLint的调用方式如下
node precommit.js file
配置方式存放在`config.json`中。
## 目录结构说明
目前datav组件库的目录结构如下
```
JacksonTianmatoMacBook-Pro:datav.js jacksontian$ tree -d
.
├── bin
├── deps
├── doc
├── example
├── lib
└── test
```
其中详细说明一下:
- `bin`目录用于存放一些可运行的脚本或者工具,例如`jslint`
- `deps`目录用于存放项目的依赖文件,其中有`raphael``d3`的相关文件。
- `doc`目录用于用于存放项目的文档如API生成文档或一些说明文档。
- `example`目录存放案例代码。
- `lib`目录为组件库具体代码,根据每个图的类型不同,存为对应文件。
- `test`目录存放单元测试代码或自动化测试代码。
## 单元测试
`DataV`项目采用[`QUnit`](http://docs.jquery.com/QUnit)作为测试框架,详细文档请见。
简单测试例子:
```
// 分模块
module("DataV");
// 测试用例
test("Themes.get", function () {
// 单个断言
equal(DataV.Themes.get("inexsit"), undefined, "Should get undefined when key is inexsit");
equal(DataV.Themes.get("COLOR_MODE"), "gradient", "Should get gradient when key is COLOR_MODE");
equal(typeof DataV.Themes.get("COLOR_ARGS"), "object", "COLOR_ARGS should be an object");
equal(DataV.Themes.get("COLOR_ARGS").length, 2, "COLOR_ARGS should have two items");
});
```
## 数据格式
数据格式统一采用二维表的方式,结构比较类似数据库中的表。列名通过文档详细来描述,写在代码的[jsdoc](http://code.google.com/p/jsdoc-toolkit/w/list)的注释中。
标准数据格式例子如下:
```
/**
* 设置数据源
* Example 举个例字假设下面的数组表示2个人在一年4个季度的消费。第一个人在4个季度里消费了1、2、3、9元。第二个人消费了3、4、6、3元。
* [
* [1,2,3,9],
* [3,4,6,3]
* ]
* @param {Array} source 数据源数组.
*/
Stream.prototype.setSource = function (source) {
// TODO
};
```
所有的组件库的调用都是相同的接口`setSource`
```
var stream = new DataV.Stream("chart");
stream.setSource(source);
stream.render();
```
## 事件注入
每一个组件都可能向外提供一些事件钩子包括DOM事件或者业务逻辑事件。绑定的方式十分简单
```
stream.on("click", function (event) {
console.log(event);
});
stream.on("dblclick", function (event) {
alert("double click");
});
stream.on("contextmenu", function (event) {
alert("mouse right");
});
```
组件的内部实现是通过继承`EventProxy`提供自定义方式,在创建画布后,就绑定一些必要的事件到画布节点上,然后将事件触发出去。如果用户如上文,侦听了这些业务事件,将会调用执行。
```
Stream.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = Raphael(this.node, conf.width, conf.height);
this.DOMNode = $(this.canvas.canvas);
var that = this;
this.DOMNode.click(function (event) {
that.trigger("click", event);
});
this.DOMNode.dblclick(function (event) {
that.trigger("dblclick", event);
});
this.DOMNode.bind("contextmenu", function (event) {
that.trigger("contextmenu", event);
});
this.DOMNode.delegate("path", "click", function (event) {
that.trigger("path_click", event);
});
};
```
## 常见错误
### 判断一个对象是否是数组
下面是宁朗写的:
```
if (color.constructor !== Array) {
throw new Error("The color should be Array");
}
```
下面是Underscore的方法
```
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) == '[object Array]';
};
```
### 数组去重
```
// make an array's every element unique by delete other same element
Array.prototype.uniq = function () {
var temp = {},
len = this.length;
for (var i = 0; i < len; i++) {
if (typeof temp[this[i]] == "undefined") {
temp[this[i]] = 1;
}
}
this.length = 0;
len = 0;
for (var i in temp) {
this[len++] = i;
}
return this;
};
```
这里可以调用underscore的uniq方法即可。节省N行代码量
### 元素是否存在数组中
```
//check if a string is in an array
var _strInArray = function (str, array) {
var i = 0,
l = 0;
for (i = 0, l = array.length; i < l; i++) {
if (array[i] === str) {
return true;
}
}
return false;
};
```
换用`_.indexOf(array, value)`可以节省代码量且返回值比boolean值更有价值
### meta
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
希望大家潮一点,别在写上面那行代码了。下面的表达方式更简洁,且无任何副作用。
<meta charset="utf-8" />
### script标签的type属性
<script type="text/javascript" src="../../deps/d3.js"></script>
如果是默认的text/javascript的话就可以直接省略掉。变成下面这样子
<script src="../../deps/d3.js"></script>

View File

@ -1,326 +1,326 @@
//copy codes from d3.js, add 4 functions: tickAttr, tickTextAttr, minorTickAttr and domainAttr;
//axis() changes, need a raphael paper object param, return raphael set object.
//examples in ../examples/axis/ to know the usage.
//a basic part for other data visualization format
/*global d3*/
/*!
* Axis兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Axis', function (require) {
/**
* function from d3, get scaleRange of an ordinal scale
* @param {Array} domain ordinal scale's range
*/
function d3_scaleExtent(domain) {
var start = domain[0], stop = domain[domain.length - 1];
return start < stop ? [start, stop] : [stop, start];
}
/**
* function from d3, get scaleRange of a scale
*/
function d3_scaleRange(scale) {
return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
}
/**
* function from d3, get subticks
* @param scale, scale
* @param ticks, major ticks of scale
* @param m, number of subdivide
*/
function d3_svg_axisSubdivide(scale, ticks, m) {
var subticks = [];
if (m && ticks.length > 1) {
var extent = d3_scaleExtent(scale.domain()),
i = -1,
n = ticks.length,
d = (ticks[1] - ticks[0]) / ++m,
j,
v;
while (++i < n) {
for (j = m; --j > 0;) {
if ((v = +ticks[i] - j * d) >= extent[0]) {
subticks.push(v);
}
}
}
for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) {
subticks.push(v);
}
}
return subticks;
}
var Axis = function () {
var scale = d3.scale.linear(),
orient = "bottom",
tickMajorSize = 6,
tickMinorSize = 6,
tickEndSize = 6,
tickPadding = 3,
tickArguments_ = [10],
tickFormat_,
tickSubdivide = 0,
tickAttr_ = {},
tickTextAttr_ = {},
minorTickAttr_ = {},
domainAttr_ = {};
/**
* @param paper: raphael's paper object.
* @return axisSet: raphael's set object.
*/
function axis(paper) {
// Ticks for quantitative scale, or domain values for ordinal scale.
var ticks = scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain(),
tickFormat = tickFormat_ === undefined ?
(scale.tickFormat ?
scale.tickFormat.apply(scale, tickArguments_)
: String)
: tickFormat_;
var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide);
var range = d3_scaleRange(scale);
var axisSet = paper.set();
switch (orient) {
case "bottom":
subticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + tickMinorSize + "V0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + tickMajorSize + "V0")
.attr(tickAttr_));
axisSet.push(paper
.text(tickX, Math.max(tickMajorSize, 0) + tickPadding + 2,
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "middle"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize)
.attr(domainAttr_));
break;
case "top":
subticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + -tickMinorSize + "V0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + -tickMajorSize + "V0")
.attr(tickAttr_));
axisSet.push(paper
.text(tickX, -(Math.max(tickMajorSize, 0) + tickPadding + 2),
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "middle"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize)
.attr(domainAttr_));
break;
case "left":
subticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + -tickMinorSize + "," + tickY + "H0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + -tickMajorSize + "," + tickY + "H0")
.attr(tickAttr_));
axisSet.push(paper
.text(-(Math.max(tickMajorSize, 0) + tickPadding), tickY,
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "end"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize)
.attr(domainAttr_));
break;
case "right":
subticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickMinorSize + "," + tickY + "H0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickMajorSize + "," + tickY + "H0")
.attr(tickAttr_));
axisSet.push(paper
.text(Math.max(tickMajorSize, 0) + tickPadding, tickY,
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "start"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize)
.attr(domainAttr_));
break;
}
return axisSet;
}
/**
* get or set axis' scale.
*/
axis.scale = function (x) {
if (!arguments.length) {
return scale;
}
scale = x;
return axis;
};
/**
* get or set axis' orinet: "bottom", "top", "left", "right", default orient is bottom.
*/
axis.orient = function (x) {
if (!arguments.length) {
return orient;
}
orient = x;
return axis;
};
/**
* get or set axis' ticks number.
*/
axis.ticks = function () {
if (!arguments.length) {
return tickArguments_;
}
tickArguments_ = arguments;
return axis;
};
/**
* get or set axis' ticks format function, it's a function change format style.
* from one string format to another string format.
*/
axis.tickFormat = function (x) {
if (!arguments.length) {
return tickFormat_;
}
tickFormat_ = x;
return axis;
};
/**
* get or set axis' tick size(length of tick line, unit: px).
* @param arguments.length === 0, get axis' major tick size.
* @param arguments.length === 1, set axis' all tick sizes as x.
* @param arguments.length === 2, get axis' major tick size as x, minor and end size as y.
* @param arguments.length === 3, get axis' major tick size as x, minor size as y, end size as z.
*/
axis.tickSize = function (x, y, z) {
if (!arguments.length) {
return tickMajorSize;
}
var n = arguments.length - 1;
tickMajorSize = +x;
tickMinorSize = n > 1 ? +y : tickMajorSize;
tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
return axis;
};
/**
* get or set axis' tick padding(the distance between tick text and axis).
* @param x is a number, unit is px;
*/
axis.tickPadding = function (x) {
if (!arguments.length) {
return tickPadding;
}
tickPadding = +x;
return axis;
};
/**
* get or set axis' sub tick divide number(divide number between two major ticks).
*/
axis.tickSubdivide = function (x) {
if (!arguments.length) {
return tickSubdivide;
}
tickSubdivide = +x;
return axis;
};
/**
* get or set axis' tick attribute(Raphael format).
*/
axis.tickAttr = function (x) {
if (!arguments.length) {
return tickAttr_;
}
tickAttr_ = x;
return axis;
};
/**
* get or set axis' tick text attribute(Raphael format).
*/
axis.tickTextAttr = function (x) {
if (!arguments.length) {
return tickTextAttr_;
}
tickTextAttr_ = x;
return axis;
};
/**
* get or set axis' minor tick attribute(Raphael format).
*/
axis.minorTickAttr = function (x) {
if (!arguments.length) {
return minorTickAttr_;
}
minorTickAttr_ = x;
return axis;
};
/**
* get or set axis' domain(axis line) attribute(Raphael format).
*/
axis.domainAttr = function (x) {
if (!arguments.length) {
return domainAttr_;
}
domainAttr_ = x;
return axis;
};
return axis;
};
return Axis;
});
//copy codes from d3.js, add 4 functions: tickAttr, tickTextAttr, minorTickAttr and domainAttr;
//axis() changes, need a raphael paper object param, return raphael set object.
//examples in ../examples/axis/ to know the usage.
//a basic part for other data visualization format
/*global d3*/
/*!
* Axis兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Axis', function (require) {
/**
* function from d3, get scaleRange of an ordinal scale
* @param {Array} domain ordinal scale's range
*/
function d3_scaleExtent(domain) {
var start = domain[0], stop = domain[domain.length - 1];
return start < stop ? [start, stop] : [stop, start];
}
/**
* function from d3, get scaleRange of a scale
*/
function d3_scaleRange(scale) {
return scale.rangeExtent ? scale.rangeExtent() : d3_scaleExtent(scale.range());
}
/**
* function from d3, get subticks
* @param scale, scale
* @param ticks, major ticks of scale
* @param m, number of subdivide
*/
function d3_svg_axisSubdivide(scale, ticks, m) {
var subticks = [];
if (m && ticks.length > 1) {
var extent = d3_scaleExtent(scale.domain()),
i = -1,
n = ticks.length,
d = (ticks[1] - ticks[0]) / ++m,
j,
v;
while (++i < n) {
for (j = m; --j > 0;) {
if ((v = +ticks[i] - j * d) >= extent[0]) {
subticks.push(v);
}
}
}
for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) {
subticks.push(v);
}
}
return subticks;
}
var Axis = function () {
var scale = d3.scale.linear(),
orient = "bottom",
tickMajorSize = 6,
tickMinorSize = 6,
tickEndSize = 6,
tickPadding = 3,
tickArguments_ = [10],
tickFormat_,
tickSubdivide = 0,
tickAttr_ = {},
tickTextAttr_ = {},
minorTickAttr_ = {},
domainAttr_ = {};
/**
* @param paper: raphael's paper object.
* @return axisSet: raphael's set object.
*/
function axis(paper) {
// Ticks for quantitative scale, or domain values for ordinal scale.
var ticks = scale.ticks ? scale.ticks.apply(scale, tickArguments_) : scale.domain(),
tickFormat = tickFormat_ === undefined ?
(scale.tickFormat ?
scale.tickFormat.apply(scale, tickArguments_)
: String)
: tickFormat_;
var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide);
var range = d3_scaleRange(scale);
var axisSet = paper.set();
switch (orient) {
case "bottom":
subticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + tickMinorSize + "V0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + tickMajorSize + "V0")
.attr(tickAttr_));
axisSet.push(paper
.text(tickX, Math.max(tickMajorSize, 0) + tickPadding + 2,
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "middle"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize)
.attr(domainAttr_));
break;
case "top":
subticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + -tickMinorSize + "V0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickX = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickX + "," + -tickMajorSize + "V0")
.attr(tickAttr_));
axisSet.push(paper
.text(tickX, -(Math.max(tickMajorSize, 0) + tickPadding + 2),
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "middle"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize)
.attr(domainAttr_));
break;
case "left":
subticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + -tickMinorSize + "," + tickY + "H0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + -tickMajorSize + "," + tickY + "H0")
.attr(tickAttr_));
axisSet.push(paper
.text(-(Math.max(tickMajorSize, 0) + tickPadding), tickY,
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "end"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize)
.attr(domainAttr_));
break;
case "right":
subticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickMinorSize + "," + tickY + "H0")
.attr(minorTickAttr_));
});
ticks.forEach(function (d, i, arr) {
var tickY = scale.ticks ? scale(d) : scale(d) + scale.rangeBand() / 2;
axisSet.push(paper
.path("M" + tickMajorSize + "," + tickY + "H0")
.attr(tickAttr_));
axisSet.push(paper
.text(Math.max(tickMajorSize, 0) + tickPadding, tickY,
typeof tickFormat === "function" ? tickFormat(d) : tickFormat)
.attr({"text-anchor": "start"})
.attr(tickTextAttr_));
});
axisSet.push(paper
.path("M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize)
.attr(domainAttr_));
break;
}
return axisSet;
}
/**
* get or set axis' scale.
*/
axis.scale = function (x) {
if (!arguments.length) {
return scale;
}
scale = x;
return axis;
};
/**
* get or set axis' orinet: "bottom", "top", "left", "right", default orient is bottom.
*/
axis.orient = function (x) {
if (!arguments.length) {
return orient;
}
orient = x;
return axis;
};
/**
* get or set axis' ticks number.
*/
axis.ticks = function () {
if (!arguments.length) {
return tickArguments_;
}
tickArguments_ = arguments;
return axis;
};
/**
* get or set axis' ticks format function, it's a function change format style.
* from one string format to another string format.
*/
axis.tickFormat = function (x) {
if (!arguments.length) {
return tickFormat_;
}
tickFormat_ = x;
return axis;
};
/**
* get or set axis' tick size(length of tick line, unit: px).
* @param arguments.length === 0, get axis' major tick size.
* @param arguments.length === 1, set axis' all tick sizes as x.
* @param arguments.length === 2, get axis' major tick size as x, minor and end size as y.
* @param arguments.length === 3, get axis' major tick size as x, minor size as y, end size as z.
*/
axis.tickSize = function (x, y, z) {
if (!arguments.length) {
return tickMajorSize;
}
var n = arguments.length - 1;
tickMajorSize = +x;
tickMinorSize = n > 1 ? +y : tickMajorSize;
tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
return axis;
};
/**
* get or set axis' tick padding(the distance between tick text and axis).
* @param x is a number, unit is px;
*/
axis.tickPadding = function (x) {
if (!arguments.length) {
return tickPadding;
}
tickPadding = +x;
return axis;
};
/**
* get or set axis' sub tick divide number(divide number between two major ticks).
*/
axis.tickSubdivide = function (x) {
if (!arguments.length) {
return tickSubdivide;
}
tickSubdivide = +x;
return axis;
};
/**
* get or set axis' tick attribute(Raphael format).
*/
axis.tickAttr = function (x) {
if (!arguments.length) {
return tickAttr_;
}
tickAttr_ = x;
return axis;
};
/**
* get or set axis' tick text attribute(Raphael format).
*/
axis.tickTextAttr = function (x) {
if (!arguments.length) {
return tickTextAttr_;
}
tickTextAttr_ = x;
return axis;
};
/**
* get or set axis' minor tick attribute(Raphael format).
*/
axis.minorTickAttr = function (x) {
if (!arguments.length) {
return minorTickAttr_;
}
minorTickAttr_ = x;
return axis;
};
/**
* get or set axis' domain(axis line) attribute(Raphael format).
*/
axis.domainAttr = function (x) {
if (!arguments.length) {
return domainAttr_;
}
domainAttr_ = x;
return axis;
};
return axis;
};
return Axis;
});

File diff suppressed because it is too large Load Diff

View File

@ -1,349 +1,349 @@
/*global Raphael, d3 */
/*!
* Bullet的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Bullet', function (require) {
var DataV = require('DataV');
var Axis = require('Axis');
/**
* Bullet构造函数
* Options:
*
* - `width` 数字图片宽度默认为200表示图片高200px
* - `height` 数字图片高度默认为80
* - `orient` string图片方向默认为"horizonal"表示水平方向若为"vertical"则表示垂直方向
* - `axisStyle` string, 坐标系类型默认为"linear"表示坐标系为线性坐标系若为"log"则表示对数坐标系
* - `logBase` 数字, 采用对数坐标系时的对数基默认为Math.E
* - `tickDivide` 数字表示坐标的标尺的分段数默认为5
* - `margin` 数字数组表示图片上左的边距默认为 [20, 20, 20, 20]
* - `centerBarRatio` 数字表示中间的测度条的高度与背景条高度的比值 默认为0.3
* - `markerWidth` 数字表示标记条的宽度 默认为4单位为像素
* - `markerRatio` 数字表示标记条的高度与背景条高度的比值默认为0.7
* - `titleRatio` 数字表示子弹图title的高度与背景条高度的比值默认为0.6此时title与subtitle的比值
* - `backgroundColor` string数组表示背景条颜色的渐变数组默认为["#666", "#ddd"],背景条颜色就是这两种颜色的渐变
* - `measureColor` string数组表示测度条颜色的渐变数组默认为["steelblue", "#B0C4DE"],测度条颜色就是这两种颜色的渐变
* - `markerColor` string表示标记条的颜色默认为"#000"
*
* Examples:
* ```
* //Create bullet in a dom node with id "chart", width is 500; height is 600px;
* var bullet = new Bullet("chart", {
* "width": 500,
* "height": 600,
* "margin": [10, 10, 20, 70]
* });
* //Create bullet with log base;
* var log = new Bullet("chart2", {
* width: 300,
* height: 60,
* margin: [10, 10, 20, 70],
* backgroundColor: ["#66f", "#ddf"],
* measureColor: ["#000", "#000"],
* markerColor: "#44f",
* axisStyle: "log",
* logBase: 10
* });
* ```
* @param {Mix} node The dom node or dom node Id
* @param {Object} options options json object for determin stream style.
*/
var Bullet = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Bullet";
this.node = this.checkContainer(node);
// Properties
this.defaults.orient = "horizonal"; // "horizonal", "vertical"
this.defaults.axisStyle = "linear"; // "linear", "log"
this.defaults.logBase = Math.E;
this.defaults.tickDivide = 5;
this.defaults.margin = [10, 10, 20, 80];//top, right, bottom, left
this.defaults.centerBarRatio = 0.3;
this.defaults.markerWidth = 4;
this.defaults.markerRatio = 0.7;
this.defaults.titleRatio = 0.6; //title's text height : subtitle's text height = 6:4
this.defaults.backgroundColor = ["#666", "#ddd"]; //dark, light
this.defaults.measureColor = ["steelblue", "#B0C4DE"]; //dark, light
this.defaults.markerColor = "#000";
// canvas
this.defaults.width = 200;
this.defaults.height = 80;
this.setOptions(options);
this.createCanvas();
}
});
/*!
* 创建画布
*/
Bullet.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.width, conf.height);
};
/**
* 设置数据源
* Examples:
* ```
* bullet.setSource({
* title: "Sample",
* subtitle: "ratio",
* ranges: [0, 0.5, 0.8, 1],
* measures: [0.7, 0.9],
* markers: [0.6],
* rangeTitles: ["below 50%", "top 20% - 50%", "top 20%"],
* measureTitles: ["value is 0.7", "value is 0.9"],
* markerTitles: ["mean is 0.6"]
* })
* ```
* @param {Object} source 数据源
*/
Bullet.prototype.setSource = function (source) {
var conf = this.defaults,
range,
axisOrient;
this.data = source;
if (conf.orient === "horizonal") {
axisOrient = "bottom";
range = [conf.margin[3], conf.width - conf.margin[1]];
} else if (conf.orient === "vertical") {
axisOrient = "left";
range = [conf.height - conf.margin[2], conf.margin[0]];
}
if (conf.axisStyle === "linear") {
this.scale = d3.scale.linear();
} else if (conf.axisStyle === "log") {
this.scale = d3.scale.log();
}
this.data.min = this.data.ranges[0];
this.data.max = this.data.ranges[this.data.ranges.length - 1];
this.scale.domain([this.data.min, this.data.max])
.range(range);
if (conf.axisStyle === "linear") {
this.axis = Axis().scale(this.scale).orient(axisOrient).ticks(conf.tickDivide).domainAttr({"stroke": "none"});
} else if (conf.axisStyle === "log") {
this.logScale = d3.scale.linear()
.domain([Math.log(this.data.min)/Math.log(conf.logBase), Math.log(this.data.max)/Math.log(conf.logBase)])
.range(range);
this.axis = Axis()
.orient(axisOrient)
.scale(this.logScale)
.ticks(conf.tickDivide)
.tickFormat(function (d) {return Math.round(Math.pow(conf.logBase, d));})
.domainAttr({"stroke": "none"});
}
};
/*!
* generate bullet dom path
*/
Bullet.prototype.generatePaths = function () {
var conf = this.defaults;
//get color function
if (conf.backgroundColor) {
this.color = d3.interpolateRgb.apply(null, [conf.backgroundColor[0], conf.backgroundColor[1]]);
}
if (conf.measureColor) {
this.measureColor = d3.interpolateRgb.apply(null, [conf.measureColor[0], conf.measureColor[1]]);
}
if (conf.orient === "horizonal") {
this.paintHorizonal();
} else if (conf.orient === "vertical") {
this.paintVertical();
}
};
/*!
* paint orient horizonal bullet
*/
Bullet.prototype.paintHorizonal = function () {
var conf = this.defaults;
var paper = this.canvas,
data = this.data,
m = conf.margin,
ranges = [],
measures = [],
markers = [],
rangeTitles = [],
i,
l,
rect,
titleRatio,
w,
h = conf.height - m[0] - m[2],
left;
//axis
this.axis(paper).attr({transform: "t" + 0 + ',' + (conf.height - m[2])});
//color rect
ranges = data.ranges;
if (data.rangeTitles) {
rangeTitles = data.rangeTitles;
}
left = m[3];
for (i = 0, l = ranges.length - 1; i < l; i++) {
w = this.scale(ranges[i + 1]) - this.scale(ranges[i]);
rect = paper.rect(left, m[0], w, h)
.attr({"stroke": "none",
"fill": this.color(l === 1 ? 1 : i / (l - 1)),
"title": rangeTitles[i] ? rangeTitles[i] : ""});
left += w;
}
//measure bar
data.measures.forEach(function (d, i) {
var mTitles = data.measureTitles;
var mTitle = mTitles && mTitles[i] ? mTitles[i] : "";
measures.push({measure: d, measureTitle: mTitle});
});
measures.sort(function (a, b) { return d3.ascending(a.measure, b.measure); });
left = this.scale(data.min);
for (i = 0, l = measures.length; i < l; i++) {
value = Math.max(data.min, Math.min(data.max, measures[i].measure));
w = this.scale(value) - left;
paper.rect(left,
m[0] + h * (1 - conf.centerBarRatio) / 2,
w,
h * conf.centerBarRatio)
.attr({"stroke": "none", "fill": this.measureColor(l === 1 ? 1 : i / (l - 1)), "title": measures[i].measureTitle});
left += w;
}
//marker bar
markers = data.markers;
for (i = 0, l = markers.length; i < l; i++) {
paper.rect(this.scale(markers[i]) - conf.markerWidth / 2,
m[0] + h * (1 - conf.markerRatio) / 2,
conf.markerWidth,
h * conf.markerRatio)
.attr({"stroke": "none", "fill": conf.markerColor,
"title": data.markerTitles && data.markerTitles[i] ? data.markerTitles[i] : ""});
}
//title
if (data.title) {
titleRatio = data.subtitle ? conf.titleRatio : 1;
this.title = paper.text(m[3] - 5, m[0] + h / 2, data.title)
.attr({"text-anchor": "end", "font-weight": "bold", "font-size": h * titleRatio * 0.9});
}
//subtitle
if (data.subtitle) {
this.subtitle = paper.text(m[3] - 5, conf.height - m[2], data.subtitle)
.attr({"text-anchor": "end", "font-size": h * (1 - conf.titleRatio) * 0.9});
}
};
/*!
* paint orient vertical bullet
*/
Bullet.prototype.paintVertical = function () {
var conf = this.defaults;
var paper = this.canvas,
data = this.data,
m = conf.margin,
ranges = [],
measures = [],
markers = [],
rangeTitles = [],
i,
l,
rect,
titleRatio,
w = conf.width - m[1] - m[3],
h,
bottom;
//axis
this.axis(paper).attr({transform: "t" + m[3] + ',' + 0});
//color rect
ranges = data.ranges;
if (data.rangeTitles) {
rangeTitles = data.rangeTitles;
}
bottom = conf.height - m[2];
for (i = 0, l = ranges.length - 1; i < l; i++) {
h = -this.scale(ranges[i + 1]) + this.scale(ranges[i]);
rect = paper.rect(m[3], bottom - h, w, h)
.attr({"stroke": "none",
"fill": this.color(l === 1 ? 1 : i / (l - 1)),
"title": rangeTitles[i] ? rangeTitles[i] : ""});
bottom -= h;
}
//measure bar
data.measures.forEach(function (d, i) {
var mTitles = data.measureTitles;
var mTitle = mTitles && mTitles[i] ? mTitles[i] : "";
measures.push({measure: d, measureTitle: mTitle});
});
measures.sort(function (a, b) { return d3.ascending(a.measure, b.measure); });
bottom = this.scale(data.min);
for (i = 0, l = measures.length; i < l; i++) {
value = Math.max(data.min, Math.min(data.max, measures[i].measure));
h = -this.scale(value) + bottom;
paper.rect(m[3] + w * (1 - conf.centerBarRatio) / 2,
bottom - h,
w * conf.centerBarRatio,
h)
.attr({"stroke": "none", "fill": this.measureColor(l === 1 ? 1 : i / (l - 1)), "title": measures[i].measureTitle});
bottom -= h;
}
//marker bar
markers = data.markers;
for (i = 0, l = markers.length; i < l; i++) {
paper.rect(m[3] + w * (1 - conf.markerRatio) / 2,
this.scale(markers[i]) - conf.markerWidth / 2,
w * conf.markerRatio,
conf.markerWidth)
.attr({"stroke": "none", "fill": conf.markerColor,
"title": data.markerTitles && data.markerTitles[i] ? data.markerTitles[i] : ""});
}
//title
if (data.title) {
titleRatio = data.subtitle ? conf.titleRatio : 1;
m[0] *= 0.9; //some ratio adjust;
this.title = paper.text((conf.width + m[3] - m[1])/ 2, m[0] * titleRatio / 2, data.title)
.attr({"text-anchor": "middle", "font-weight": "bold", "font-size": m[0] * titleRatio * 0.8});
}
//subtitle
if (data.subtitle) {
this.subtitle = paper.text((conf.width + m[3] - m[1])/ 2, m[0] * (1 - (1 - titleRatio) / 2), data.subtitle)
.attr({"text-anchor": "middle", "font-size": m[0] * (1 - titleRatio) * 0.8});
}
};
/*!
* clean canvas
*/
Bullet.prototype.clearCanvas = function () {
this.canvas.clear();
};
/**
* render bullet
*/
Bullet.prototype.render = function (options) {
this.setOptions(options);
this.generatePaths();
};
return Bullet;
});
/*global Raphael, d3 */
/*!
* Bullet的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Bullet', function (require) {
var DataV = require('DataV');
var Axis = require('Axis');
/**
* Bullet构造函数
* Options:
*
* - `width` 数字图片宽度默认为200表示图片高200px
* - `height` 数字图片高度默认为80
* - `orient` string图片方向默认为"horizonal"表示水平方向若为"vertical"则表示垂直方向
* - `axisStyle` string, 坐标系类型默认为"linear"表示坐标系为线性坐标系若为"log"则表示对数坐标系
* - `logBase` 数字, 采用对数坐标系时的对数基默认为Math.E
* - `tickDivide` 数字表示坐标的标尺的分段数默认为5
* - `margin` 数字数组表示图片上左的边距默认为 [20, 20, 20, 20]
* - `centerBarRatio` 数字表示中间的测度条的高度与背景条高度的比值 默认为0.3
* - `markerWidth` 数字表示标记条的宽度 默认为4单位为像素
* - `markerRatio` 数字表示标记条的高度与背景条高度的比值默认为0.7
* - `titleRatio` 数字表示子弹图title的高度与背景条高度的比值默认为0.6此时title与subtitle的比值
* - `backgroundColor` string数组表示背景条颜色的渐变数组默认为["#666", "#ddd"],背景条颜色就是这两种颜色的渐变
* - `measureColor` string数组表示测度条颜色的渐变数组默认为["steelblue", "#B0C4DE"],测度条颜色就是这两种颜色的渐变
* - `markerColor` string表示标记条的颜色默认为"#000"
*
* Examples:
* ```
* //Create bullet in a dom node with id "chart", width is 500; height is 600px;
* var bullet = new Bullet("chart", {
* "width": 500,
* "height": 600,
* "margin": [10, 10, 20, 70]
* });
* //Create bullet with log base;
* var log = new Bullet("chart2", {
* width: 300,
* height: 60,
* margin: [10, 10, 20, 70],
* backgroundColor: ["#66f", "#ddf"],
* measureColor: ["#000", "#000"],
* markerColor: "#44f",
* axisStyle: "log",
* logBase: 10
* });
* ```
* @param {Mix} node The dom node or dom node Id
* @param {Object} options options json object for determin stream style.
*/
var Bullet = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Bullet";
this.node = this.checkContainer(node);
// Properties
this.defaults.orient = "horizonal"; // "horizonal", "vertical"
this.defaults.axisStyle = "linear"; // "linear", "log"
this.defaults.logBase = Math.E;
this.defaults.tickDivide = 5;
this.defaults.margin = [10, 10, 20, 80];//top, right, bottom, left
this.defaults.centerBarRatio = 0.3;
this.defaults.markerWidth = 4;
this.defaults.markerRatio = 0.7;
this.defaults.titleRatio = 0.6; //title's text height : subtitle's text height = 6:4
this.defaults.backgroundColor = ["#666", "#ddd"]; //dark, light
this.defaults.measureColor = ["steelblue", "#B0C4DE"]; //dark, light
this.defaults.markerColor = "#000";
// canvas
this.defaults.width = 200;
this.defaults.height = 80;
this.setOptions(options);
this.createCanvas();
}
});
/*!
* 创建画布
*/
Bullet.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.width, conf.height);
};
/**
* 设置数据源
* Examples:
* ```
* bullet.setSource({
* title: "Sample",
* subtitle: "ratio",
* ranges: [0, 0.5, 0.8, 1],
* measures: [0.7, 0.9],
* markers: [0.6],
* rangeTitles: ["below 50%", "top 20% - 50%", "top 20%"],
* measureTitles: ["value is 0.7", "value is 0.9"],
* markerTitles: ["mean is 0.6"]
* })
* ```
* @param {Object} source 数据源
*/
Bullet.prototype.setSource = function (source) {
var conf = this.defaults,
range,
axisOrient;
this.data = source;
if (conf.orient === "horizonal") {
axisOrient = "bottom";
range = [conf.margin[3], conf.width - conf.margin[1]];
} else if (conf.orient === "vertical") {
axisOrient = "left";
range = [conf.height - conf.margin[2], conf.margin[0]];
}
if (conf.axisStyle === "linear") {
this.scale = d3.scale.linear();
} else if (conf.axisStyle === "log") {
this.scale = d3.scale.log();
}
this.data.min = this.data.ranges[0];
this.data.max = this.data.ranges[this.data.ranges.length - 1];
this.scale.domain([this.data.min, this.data.max])
.range(range);
if (conf.axisStyle === "linear") {
this.axis = Axis().scale(this.scale).orient(axisOrient).ticks(conf.tickDivide).domainAttr({"stroke": "none"});
} else if (conf.axisStyle === "log") {
this.logScale = d3.scale.linear()
.domain([Math.log(this.data.min)/Math.log(conf.logBase), Math.log(this.data.max)/Math.log(conf.logBase)])
.range(range);
this.axis = Axis()
.orient(axisOrient)
.scale(this.logScale)
.ticks(conf.tickDivide)
.tickFormat(function (d) {return Math.round(Math.pow(conf.logBase, d));})
.domainAttr({"stroke": "none"});
}
};
/*!
* generate bullet dom path
*/
Bullet.prototype.generatePaths = function () {
var conf = this.defaults;
//get color function
if (conf.backgroundColor) {
this.color = d3.interpolateRgb.apply(null, [conf.backgroundColor[0], conf.backgroundColor[1]]);
}
if (conf.measureColor) {
this.measureColor = d3.interpolateRgb.apply(null, [conf.measureColor[0], conf.measureColor[1]]);
}
if (conf.orient === "horizonal") {
this.paintHorizonal();
} else if (conf.orient === "vertical") {
this.paintVertical();
}
};
/*!
* paint orient horizonal bullet
*/
Bullet.prototype.paintHorizonal = function () {
var conf = this.defaults;
var paper = this.canvas,
data = this.data,
m = conf.margin,
ranges = [],
measures = [],
markers = [],
rangeTitles = [],
i,
l,
rect,
titleRatio,
w,
h = conf.height - m[0] - m[2],
left;
//axis
this.axis(paper).attr({transform: "t" + 0 + ',' + (conf.height - m[2])});
//color rect
ranges = data.ranges;
if (data.rangeTitles) {
rangeTitles = data.rangeTitles;
}
left = m[3];
for (i = 0, l = ranges.length - 1; i < l; i++) {
w = this.scale(ranges[i + 1]) - this.scale(ranges[i]);
rect = paper.rect(left, m[0], w, h)
.attr({"stroke": "none",
"fill": this.color(l === 1 ? 1 : i / (l - 1)),
"title": rangeTitles[i] ? rangeTitles[i] : ""});
left += w;
}
//measure bar
data.measures.forEach(function (d, i) {
var mTitles = data.measureTitles;
var mTitle = mTitles && mTitles[i] ? mTitles[i] : "";
measures.push({measure: d, measureTitle: mTitle});
});
measures.sort(function (a, b) { return d3.ascending(a.measure, b.measure); });
left = this.scale(data.min);
for (i = 0, l = measures.length; i < l; i++) {
value = Math.max(data.min, Math.min(data.max, measures[i].measure));
w = this.scale(value) - left;
paper.rect(left,
m[0] + h * (1 - conf.centerBarRatio) / 2,
w,
h * conf.centerBarRatio)
.attr({"stroke": "none", "fill": this.measureColor(l === 1 ? 1 : i / (l - 1)), "title": measures[i].measureTitle});
left += w;
}
//marker bar
markers = data.markers;
for (i = 0, l = markers.length; i < l; i++) {
paper.rect(this.scale(markers[i]) - conf.markerWidth / 2,
m[0] + h * (1 - conf.markerRatio) / 2,
conf.markerWidth,
h * conf.markerRatio)
.attr({"stroke": "none", "fill": conf.markerColor,
"title": data.markerTitles && data.markerTitles[i] ? data.markerTitles[i] : ""});
}
//title
if (data.title) {
titleRatio = data.subtitle ? conf.titleRatio : 1;
this.title = paper.text(m[3] - 5, m[0] + h / 2, data.title)
.attr({"text-anchor": "end", "font-weight": "bold", "font-size": h * titleRatio * 0.9});
}
//subtitle
if (data.subtitle) {
this.subtitle = paper.text(m[3] - 5, conf.height - m[2], data.subtitle)
.attr({"text-anchor": "end", "font-size": h * (1 - conf.titleRatio) * 0.9});
}
};
/*!
* paint orient vertical bullet
*/
Bullet.prototype.paintVertical = function () {
var conf = this.defaults;
var paper = this.canvas,
data = this.data,
m = conf.margin,
ranges = [],
measures = [],
markers = [],
rangeTitles = [],
i,
l,
rect,
titleRatio,
w = conf.width - m[1] - m[3],
h,
bottom;
//axis
this.axis(paper).attr({transform: "t" + m[3] + ',' + 0});
//color rect
ranges = data.ranges;
if (data.rangeTitles) {
rangeTitles = data.rangeTitles;
}
bottom = conf.height - m[2];
for (i = 0, l = ranges.length - 1; i < l; i++) {
h = -this.scale(ranges[i + 1]) + this.scale(ranges[i]);
rect = paper.rect(m[3], bottom - h, w, h)
.attr({"stroke": "none",
"fill": this.color(l === 1 ? 1 : i / (l - 1)),
"title": rangeTitles[i] ? rangeTitles[i] : ""});
bottom -= h;
}
//measure bar
data.measures.forEach(function (d, i) {
var mTitles = data.measureTitles;
var mTitle = mTitles && mTitles[i] ? mTitles[i] : "";
measures.push({measure: d, measureTitle: mTitle});
});
measures.sort(function (a, b) { return d3.ascending(a.measure, b.measure); });
bottom = this.scale(data.min);
for (i = 0, l = measures.length; i < l; i++) {
value = Math.max(data.min, Math.min(data.max, measures[i].measure));
h = -this.scale(value) + bottom;
paper.rect(m[3] + w * (1 - conf.centerBarRatio) / 2,
bottom - h,
w * conf.centerBarRatio,
h)
.attr({"stroke": "none", "fill": this.measureColor(l === 1 ? 1 : i / (l - 1)), "title": measures[i].measureTitle});
bottom -= h;
}
//marker bar
markers = data.markers;
for (i = 0, l = markers.length; i < l; i++) {
paper.rect(m[3] + w * (1 - conf.markerRatio) / 2,
this.scale(markers[i]) - conf.markerWidth / 2,
w * conf.markerRatio,
conf.markerWidth)
.attr({"stroke": "none", "fill": conf.markerColor,
"title": data.markerTitles && data.markerTitles[i] ? data.markerTitles[i] : ""});
}
//title
if (data.title) {
titleRatio = data.subtitle ? conf.titleRatio : 1;
m[0] *= 0.9; //some ratio adjust;
this.title = paper.text((conf.width + m[3] - m[1])/ 2, m[0] * titleRatio / 2, data.title)
.attr({"text-anchor": "middle", "font-weight": "bold", "font-size": m[0] * titleRatio * 0.8});
}
//subtitle
if (data.subtitle) {
this.subtitle = paper.text((conf.width + m[3] - m[1])/ 2, m[0] * (1 - (1 - titleRatio) / 2), data.subtitle)
.attr({"text-anchor": "middle", "font-size": m[0] * (1 - titleRatio) * 0.8});
}
};
/*!
* clean canvas
*/
Bullet.prototype.clearCanvas = function () {
this.canvas.clear();
};
/**
* render bullet
*/
Bullet.prototype.render = function (options) {
this.setOptions(options);
this.generatePaths();
};
return Bullet;
});

View File

@ -1,424 +1,424 @@
/*global EventProxy, d3, Raphael, self, packages, $ */
/*!
* Bundle的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Bundle', function (require) {
var DataV = require('DataV');
/**
* 构造函数node参数表示在html的哪个容器中绘制该组件
* options对象为用户自定义的组件的属性比如画布大小
*/
var Bundle = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Bundle";
this.node = this.checkContainer(node);
this.json = {};
// 图的半径
this.defaults.diameter = 960;
this.defaults.radius = this.defaults.diameter / 2;
this.defaults.innerRadius = this.defaults.radius - 120;
this.defaults.tension = 0.85;
this.defaults.color = {
defaultLineColor: "#4065AF",
defaultWordColor: "#000000",
lineHoverColor: "#02B0ED",
nodeHoverColor: "#02B0ED",
importNodesColor: "#5DA714", //被引用的节点
exportNodesColor: "#FE3919" //引用当前节点的节点
};
this.setOptions(options);
this.createCanvas();
}
});
/**
* 设置用户自定义属性
*/
Bundle.prototype.setOptions = function (options) {
if (options) {
var prop;
for (prop in options) {
if (options.hasOwnProperty(prop)) {
this.defaults[prop] = options[prop];
if (prop === "diameter") {
this.defaults.radius = this.defaults.diameter / 2;
this.defaults.innerRadius = this.defaults.radius - 120;
} else if (prop === "radius") {
this.defaults.diameter = this.defaults.radius * 2;
this.defaults.innerRadius = this.defaults.radius - 120;
} else if (prop === "innerRadius") {
this.defaults.radius = this.defaults.innerRadius + 120;
this.defaults.diameter = this.defaults.radius * 2;
} else if (prop === "width") {
this.defaults.diameter = this.defaults.width;
this.defaults.radius = this.defaults.diameter / 2;
this.defaults.innerRadius = this.defaults.radius - 120;
}
}
}
}
};
/**
* 对原始数据进行处理
* TODO: 改进为获取值时运算
*/
Bundle.prototype.setSource = function (source) {
if (source[0] && source[0] instanceof Array) {
// csv or 2d array source
if (source[0][0] === "name") {
source = source.slice(1); // 从第一行开始第0行舍去
}
var nData = [];
var imports = [];
//var isNode = true;
var nodeNum;
var that = this;
source.forEach(function (d, i) {
if (d[0] === "") {
throw new Error("name can not be empty(line:" + (i + 1) + ").");
}
if (d[1] !== "") {
imports = d[1].split(" ");
}
nData[i] = {
name: d[0],
imports: imports
};
});
this.json = nData;
} else {
// json source
this.json = source;
}
};
/**
* 创建画布
*/
Bundle.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.diameter, conf.diameter);
//var c = this.canvas.circle(50, 50, 40);
};
/**
* 布局
*/
Bundle.prototype.layout = function () {
var packages = {
// Lazily construct the package hierarchy from class names.
root: function (classes) {
var map = {};
function construct(name, data) {
var node = map[name], i;
if (!node) {
node = map[name] = data || {name: name, children: []};
if (name.length) {
node.parent = construct(name.substring(0, i = name.lastIndexOf(".")));
node.parent.children.push(node);
node.key = name.substring(i + 1);
}
}
return node;
}
classes.forEach(function (d) {
construct(d.name, d);
});
return map[""];
},
// Return a list of imports for the given array of nodes.
imports: function (nodes) {
var map = {},
imports = [];
// Compute a map from name to node.
nodes.forEach(function (d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
nodes.forEach(function (d) {
if (d.imports) {
d.imports.forEach(function (i) {imports.push({source: map[d.name], target: map[i]});
});
}
});
return imports;
}
};
var cluster = d3.layout.cluster()
.size([360, this.defaults.innerRadius]) //.size(角度,半径)
.sort(null)
.value(function (d) {
return d.size;
});
this.nodes = cluster.nodes(packages.root(this.json));
this.links = packages.imports(this.nodes);
};
/**
* 渲染弦图
*/
Bundle.prototype.render = function () {
this.layout();
this.generatePaths();
};
/**
* 生成路径
*/
Bundle.prototype.generatePaths = function (options) {
var that = this;
var canvas = this.canvas;
var rNodes = canvas.set();
var rLinks = canvas.set();
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(this.defaults.tension)
.radius(function (d) {
return d.y;
})
.angle(function (d) {
return d.x / 180 * Math.PI;
});
//定义图中的弦和节点
var nodes = this.nodes;
var links = this.links;
var linksCount = links.length;
var paths = bundle(links);
var locateStr = ""; //对文字进行平移和旋转
var locateBBox = ""; //对文字的bounding box进行平移和旋转
var r = 0;
var angle = 0;
var xTrans = 0;
var yTrans = 0;
var anchor; //text-anchor: start or end
var rotateStr = "";
//element data cache
var nodeRelatedElements = {};// {key: {targetLink: [], sourceLink: [], targetNode: [], sourceNode: []}}
var nodeElements = {}; //{key: Els}
var bBoxElements = {}; //{key: Els}
var i,
j,
key,
textEl,
bBox,
bBoxNew,
tCenterX,
tCenterY,
bBoxEl,
linkEl;
var mouseoverLink = function () {
var current = this;
//var color = that.data("color");
if (rLinks.preLink) {
rLinks.preLink.attr("stroke", that.defaults.color.defaultLineColor)
.attr("stroke-width", 1)
.attr("stroke-opacity", 0.6);
}
rLinks.preLink = this;
current.attr("stroke", that.defaults.color.lineHoverColor)
.attr("stroke-width", 2)
.attr("stroke-opacity", 1.0)
.toFront(); //把当前弦移到画布最上层
};
var mouseoverNode = function () {
var relatedEl = this.data("relatedElements");
//高亮所选节点的文字颜色
this.data("relatedNode").attr({"fill": that.defaults.color.nodeHoverColor,
"fill-opacity": 1.0, "font-weight": "600"});
//将包围盒颜色设为透明
this.attr({"fill": that.defaults.color.nodeHoverColor, "fill-opacity": 0.0/*, "font-weight": "600"*/});
relatedEl.sourceLink.forEach(function (d) { //set green
d.attr({"stroke": that.defaults.color.importNodesColor, "stroke-width": 1, "stroke-opacity": 0.9})
.toFront();
});
relatedEl.sourceNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.importNodesColor, "font-weight": "600"});
});
relatedEl.targetLink.forEach(function (d) { //set red
d.attr({"stroke": that.defaults.color.exportNodesColor, "stroke-width": 1, "stroke-opacity": 0.9})
.toFront();
});
relatedEl.targetNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.exportNodesColor, "font-weight": "600"});
});
};
var mouseoutNode = function () {
var relatedEl = this.data("relatedElements");
this.data("relatedNode").attr({"fill": that.defaults.color.defaultWordColor,
"font-weight": "400", "fill-opacity": 1.0});
relatedEl.targetLink.forEach(function (d) {
d.attr({"stroke": that.defaults.color.defaultLineColor, "stroke-width": 1, "stroke-opacity": 0.6});
});
relatedEl.targetNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.defaultWordColor, "font-weight": "400"});
});
relatedEl.sourceLink.forEach(function (d) {
d.attr({"stroke": that.defaults.color.defaultLineColor, "stroke-width": 1, "stroke-opacity": 0.6});
});
relatedEl.sourceNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.defaultWordColor, "font-weight": "400"});
});
};
for (j = 0; j < nodes.length; j++) {
//若为叶子节点
if (!nodes[j].children) {
locateStr = "T" + that.defaults.radius + "," + that.defaults.radius + "R"; //使用大写T、R、S--绝对not相对
//半径: add a padding between lines and words
r = nodes[j].y + 20;
//计算旋转角度和水平、竖直方向所需平移的距离
angle = (nodes[j].x - 90) * Math.PI / 180;
xTrans = r * Math.cos(angle);
yTrans = r * Math.sin(angle);
//计算text-anchor
if (nodes[j].x < 180) {
anchor = "start";
} else {
anchor = "end";
}
//计算文字方向是否需要旋转180度
if (nodes[j].x < 180) {
rotateStr = "";
} else {
rotateStr = "R180";
}
//计算文字需要如何经过平移和旋转被排列在圆周上
locateStr += (nodes[j].x - 90) + rotateStr + "T" + xTrans + "," + yTrans;
//绘制文字
textEl = canvas.text()
.attr("font", "11px arial")
.data("color", that.defaults.color)
.attr("text", nodes[j].key)
//.attr("title", nodes[j].size)
.transform(locateStr)
.attr("text-anchor", anchor)
.attr("fill", that.defaults.color.defaultWordColor);
//获取旋转平移之前文字的bounding box
bBox = textEl.getBBox(true);
//canvas.rect(bBox.x, bBox.y, bBox.width, bBox.height);
//获取旋转平移之后文字的bounding box
bBoxNew = textEl.getBBox();
//adjust vml box center
if (Raphael.vml) {
//vml's word bbox is not related to text-anchor, always middle;
//svg's word bbox is related to text-anchor;
bBoxNew.x = bBoxNew.x + bBox.width / 2 * Math.cos(angle);
bBoxNew.y = bBoxNew.y + bBox.width / 2 * Math.sin(angle);
}
//canvas.rect(bBoxNew.x, bBoxNew.y, bBoxNew.width, bBoxNew.height);
//新旧bounding box的中心坐标变化
tCenterX = bBoxNew.x + bBoxNew.width / 2 - bBox.x - bBox.width / 2;
tCenterY = bBoxNew.y + bBoxNew.height / 2 - bBox.y - bBox.height / 2;
//对bounding box进行平移和旋转
locateBBox = "T" + tCenterX + "," + tCenterY + "R" + (nodes[j].x - 90) + rotateStr;
// 包围盒
bBoxEl = canvas.rect(bBox.x, bBox.y, bBox.width, bBox.height)
.transform(locateBBox)
.data("relatedNode", textEl)
.attr({"fill": "#fff", "opacity": 0.01});
key = nodes[j].key;
nodeElements[key] = textEl;
bBoxElements[key] = bBoxEl;
nodeRelatedElements[key] = {targetLink: [], sourceLink: [], targetNode: [], sourceNode: []};
rNodes.push(textEl);
}
}
//绘制曲线
for (i = 0; i < linksCount; i++) {
var l = paths[i];
//对paths数组中的每一项进行计算由路径节点信息得到坐标值
var spline = line(l);
var sourceKey = links[i].source.key;
var targetKey = links[i].target.key;
var tips = "link source: " + sourceKey + "\n"
+ "link target: " + targetKey;
linkEl = canvas.path(spline)
//.attr("stroke", that.defaults.defaultLineColor)
.attr("stroke-opacity", 0.6)
.attr("title", tips)
.attr("d", spline)
.attr("stroke", that.defaults.color.defaultLineColor)
.translate(that.defaults.radius, that.defaults.radius)
.mouseover(mouseoverLink);
//.mouseout(mouseoutLink);
linkEl[0].el = linkEl;
nodeRelatedElements[sourceKey].targetLink.push(linkEl);
nodeRelatedElements[sourceKey].targetNode.push(nodeElements[targetKey]);
nodeRelatedElements[targetKey].sourceLink.push(linkEl);
nodeRelatedElements[targetKey].sourceNode.push(nodeElements[sourceKey]);
rLinks.push(linkEl);
}
$(this.canvas.canvas).mousemove(function (e) {
if(!e.target.el && rLinks.preLink){
rLinks.preLink.attr("stroke", that.defaults.color.defaultLineColor)
.attr("stroke-width", 1)
.attr("stroke-opacity", 0.6);
rLinks.preLink = undefined;
//console.log("a");
}
});
//bind text words hover event
for (key in bBoxElements) {
if (bBoxElements.hasOwnProperty(key)) {
bBoxElements[key].data("relatedElements", nodeRelatedElements[key])
.mouseover(mouseoverNode)
.mouseout(mouseoutNode);
}
}
};
return Bundle;
});
/*global EventProxy, d3, Raphael, self, packages, $ */
/*!
* Bundle的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Bundle', function (require) {
var DataV = require('DataV');
/**
* 构造函数node参数表示在html的哪个容器中绘制该组件
* options对象为用户自定义的组件的属性比如画布大小
*/
var Bundle = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Bundle";
this.node = this.checkContainer(node);
this.json = {};
// 图的半径
this.defaults.diameter = 960;
this.defaults.radius = this.defaults.diameter / 2;
this.defaults.innerRadius = this.defaults.radius - 120;
this.defaults.tension = 0.85;
this.defaults.color = {
defaultLineColor: "#4065AF",
defaultWordColor: "#000000",
lineHoverColor: "#02B0ED",
nodeHoverColor: "#02B0ED",
importNodesColor: "#5DA714", //被引用的节点
exportNodesColor: "#FE3919" //引用当前节点的节点
};
this.setOptions(options);
this.createCanvas();
}
});
/**
* 设置用户自定义属性
*/
Bundle.prototype.setOptions = function (options) {
if (options) {
var prop;
for (prop in options) {
if (options.hasOwnProperty(prop)) {
this.defaults[prop] = options[prop];
if (prop === "diameter") {
this.defaults.radius = this.defaults.diameter / 2;
this.defaults.innerRadius = this.defaults.radius - 120;
} else if (prop === "radius") {
this.defaults.diameter = this.defaults.radius * 2;
this.defaults.innerRadius = this.defaults.radius - 120;
} else if (prop === "innerRadius") {
this.defaults.radius = this.defaults.innerRadius + 120;
this.defaults.diameter = this.defaults.radius * 2;
} else if (prop === "width") {
this.defaults.diameter = this.defaults.width;
this.defaults.radius = this.defaults.diameter / 2;
this.defaults.innerRadius = this.defaults.radius - 120;
}
}
}
}
};
/**
* 对原始数据进行处理
* TODO: 改进为获取值时运算
*/
Bundle.prototype.setSource = function (source) {
if (source[0] && source[0] instanceof Array) {
// csv or 2d array source
if (source[0][0] === "name") {
source = source.slice(1); // 从第一行开始第0行舍去
}
var nData = [];
var imports = [];
//var isNode = true;
var nodeNum;
var that = this;
source.forEach(function (d, i) {
if (d[0] === "") {
throw new Error("name can not be empty(line:" + (i + 1) + ").");
}
if (d[1] !== "") {
imports = d[1].split(" ");
}
nData[i] = {
name: d[0],
imports: imports
};
});
this.json = nData;
} else {
// json source
this.json = source;
}
};
/**
* 创建画布
*/
Bundle.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.diameter, conf.diameter);
//var c = this.canvas.circle(50, 50, 40);
};
/**
* 布局
*/
Bundle.prototype.layout = function () {
var packages = {
// Lazily construct the package hierarchy from class names.
root: function (classes) {
var map = {};
function construct(name, data) {
var node = map[name], i;
if (!node) {
node = map[name] = data || {name: name, children: []};
if (name.length) {
node.parent = construct(name.substring(0, i = name.lastIndexOf(".")));
node.parent.children.push(node);
node.key = name.substring(i + 1);
}
}
return node;
}
classes.forEach(function (d) {
construct(d.name, d);
});
return map[""];
},
// Return a list of imports for the given array of nodes.
imports: function (nodes) {
var map = {},
imports = [];
// Compute a map from name to node.
nodes.forEach(function (d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
nodes.forEach(function (d) {
if (d.imports) {
d.imports.forEach(function (i) {imports.push({source: map[d.name], target: map[i]});
});
}
});
return imports;
}
};
var cluster = d3.layout.cluster()
.size([360, this.defaults.innerRadius]) //.size(角度,半径)
.sort(null)
.value(function (d) {
return d.size;
});
this.nodes = cluster.nodes(packages.root(this.json));
this.links = packages.imports(this.nodes);
};
/**
* 渲染弦图
*/
Bundle.prototype.render = function () {
this.layout();
this.generatePaths();
};
/**
* 生成路径
*/
Bundle.prototype.generatePaths = function (options) {
var that = this;
var canvas = this.canvas;
var rNodes = canvas.set();
var rLinks = canvas.set();
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(this.defaults.tension)
.radius(function (d) {
return d.y;
})
.angle(function (d) {
return d.x / 180 * Math.PI;
});
//定义图中的弦和节点
var nodes = this.nodes;
var links = this.links;
var linksCount = links.length;
var paths = bundle(links);
var locateStr = ""; //对文字进行平移和旋转
var locateBBox = ""; //对文字的bounding box进行平移和旋转
var r = 0;
var angle = 0;
var xTrans = 0;
var yTrans = 0;
var anchor; //text-anchor: start or end
var rotateStr = "";
//element data cache
var nodeRelatedElements = {};// {key: {targetLink: [], sourceLink: [], targetNode: [], sourceNode: []}}
var nodeElements = {}; //{key: Els}
var bBoxElements = {}; //{key: Els}
var i,
j,
key,
textEl,
bBox,
bBoxNew,
tCenterX,
tCenterY,
bBoxEl,
linkEl;
var mouseoverLink = function () {
var current = this;
//var color = that.data("color");
if (rLinks.preLink) {
rLinks.preLink.attr("stroke", that.defaults.color.defaultLineColor)
.attr("stroke-width", 1)
.attr("stroke-opacity", 0.6);
}
rLinks.preLink = this;
current.attr("stroke", that.defaults.color.lineHoverColor)
.attr("stroke-width", 2)
.attr("stroke-opacity", 1.0)
.toFront(); //把当前弦移到画布最上层
};
var mouseoverNode = function () {
var relatedEl = this.data("relatedElements");
//高亮所选节点的文字颜色
this.data("relatedNode").attr({"fill": that.defaults.color.nodeHoverColor,
"fill-opacity": 1.0, "font-weight": "600"});
//将包围盒颜色设为透明
this.attr({"fill": that.defaults.color.nodeHoverColor, "fill-opacity": 0.0/*, "font-weight": "600"*/});
relatedEl.sourceLink.forEach(function (d) { //set green
d.attr({"stroke": that.defaults.color.importNodesColor, "stroke-width": 1, "stroke-opacity": 0.9})
.toFront();
});
relatedEl.sourceNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.importNodesColor, "font-weight": "600"});
});
relatedEl.targetLink.forEach(function (d) { //set red
d.attr({"stroke": that.defaults.color.exportNodesColor, "stroke-width": 1, "stroke-opacity": 0.9})
.toFront();
});
relatedEl.targetNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.exportNodesColor, "font-weight": "600"});
});
};
var mouseoutNode = function () {
var relatedEl = this.data("relatedElements");
this.data("relatedNode").attr({"fill": that.defaults.color.defaultWordColor,
"font-weight": "400", "fill-opacity": 1.0});
relatedEl.targetLink.forEach(function (d) {
d.attr({"stroke": that.defaults.color.defaultLineColor, "stroke-width": 1, "stroke-opacity": 0.6});
});
relatedEl.targetNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.defaultWordColor, "font-weight": "400"});
});
relatedEl.sourceLink.forEach(function (d) {
d.attr({"stroke": that.defaults.color.defaultLineColor, "stroke-width": 1, "stroke-opacity": 0.6});
});
relatedEl.sourceNode.forEach(function (d) {
d.attr({"fill": that.defaults.color.defaultWordColor, "font-weight": "400"});
});
};
for (j = 0; j < nodes.length; j++) {
//若为叶子节点
if (!nodes[j].children) {
locateStr = "T" + that.defaults.radius + "," + that.defaults.radius + "R"; //使用大写T、R、S--绝对not相对
//半径: add a padding between lines and words
r = nodes[j].y + 20;
//计算旋转角度和水平、竖直方向所需平移的距离
angle = (nodes[j].x - 90) * Math.PI / 180;
xTrans = r * Math.cos(angle);
yTrans = r * Math.sin(angle);
//计算text-anchor
if (nodes[j].x < 180) {
anchor = "start";
} else {
anchor = "end";
}
//计算文字方向是否需要旋转180度
if (nodes[j].x < 180) {
rotateStr = "";
} else {
rotateStr = "R180";
}
//计算文字需要如何经过平移和旋转被排列在圆周上
locateStr += (nodes[j].x - 90) + rotateStr + "T" + xTrans + "," + yTrans;
//绘制文字
textEl = canvas.text()
.attr("font", "11px arial")
.data("color", that.defaults.color)
.attr("text", nodes[j].key)
//.attr("title", nodes[j].size)
.transform(locateStr)
.attr("text-anchor", anchor)
.attr("fill", that.defaults.color.defaultWordColor);
//获取旋转平移之前文字的bounding box
bBox = textEl.getBBox(true);
//canvas.rect(bBox.x, bBox.y, bBox.width, bBox.height);
//获取旋转平移之后文字的bounding box
bBoxNew = textEl.getBBox();
//adjust vml box center
if (Raphael.vml) {
//vml's word bbox is not related to text-anchor, always middle;
//svg's word bbox is related to text-anchor;
bBoxNew.x = bBoxNew.x + bBox.width / 2 * Math.cos(angle);
bBoxNew.y = bBoxNew.y + bBox.width / 2 * Math.sin(angle);
}
//canvas.rect(bBoxNew.x, bBoxNew.y, bBoxNew.width, bBoxNew.height);
//新旧bounding box的中心坐标变化
tCenterX = bBoxNew.x + bBoxNew.width / 2 - bBox.x - bBox.width / 2;
tCenterY = bBoxNew.y + bBoxNew.height / 2 - bBox.y - bBox.height / 2;
//对bounding box进行平移和旋转
locateBBox = "T" + tCenterX + "," + tCenterY + "R" + (nodes[j].x - 90) + rotateStr;
// 包围盒
bBoxEl = canvas.rect(bBox.x, bBox.y, bBox.width, bBox.height)
.transform(locateBBox)
.data("relatedNode", textEl)
.attr({"fill": "#fff", "opacity": 0.01});
key = nodes[j].key;
nodeElements[key] = textEl;
bBoxElements[key] = bBoxEl;
nodeRelatedElements[key] = {targetLink: [], sourceLink: [], targetNode: [], sourceNode: []};
rNodes.push(textEl);
}
}
//绘制曲线
for (i = 0; i < linksCount; i++) {
var l = paths[i];
//对paths数组中的每一项进行计算由路径节点信息得到坐标值
var spline = line(l);
var sourceKey = links[i].source.key;
var targetKey = links[i].target.key;
var tips = "link source: " + sourceKey + "\n"
+ "link target: " + targetKey;
linkEl = canvas.path(spline)
//.attr("stroke", that.defaults.defaultLineColor)
.attr("stroke-opacity", 0.6)
.attr("title", tips)
.attr("d", spline)
.attr("stroke", that.defaults.color.defaultLineColor)
.translate(that.defaults.radius, that.defaults.radius)
.mouseover(mouseoverLink);
//.mouseout(mouseoutLink);
linkEl[0].el = linkEl;
nodeRelatedElements[sourceKey].targetLink.push(linkEl);
nodeRelatedElements[sourceKey].targetNode.push(nodeElements[targetKey]);
nodeRelatedElements[targetKey].sourceLink.push(linkEl);
nodeRelatedElements[targetKey].sourceNode.push(nodeElements[sourceKey]);
rLinks.push(linkEl);
}
$(this.canvas.canvas).mousemove(function (e) {
if(!e.target.el && rLinks.preLink){
rLinks.preLink.attr("stroke", that.defaults.color.defaultLineColor)
.attr("stroke-width", 1)
.attr("stroke-opacity", 0.6);
rLinks.preLink = undefined;
//console.log("a");
}
});
//bind text words hover event
for (key in bBoxElements) {
if (bBoxElements.hasOwnProperty(key)) {
bBoxElements[key].data("relatedElements", nodeRelatedElements[key])
.mouseover(mouseoverNode)
.mouseout(mouseoutNode);
}
}
};
return Bundle;
});

File diff suppressed because it is too large Load Diff

View File

@ -1,481 +1,481 @@
/*global Raphael, d3, $, define */
/*!
* Chord的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) {
return this[id];
});
}
})('Chord', function (require) {
var DataV = require('DataV');
/**
* 构造函数
* @param {Object} node 表示在html的哪个容器中绘制该组件
* @param {Object} options 为用户自定义的组件的属性比如画布大小
*/
var Chord = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Chord";
this.node = this.checkContainer(node);
this.matrix = [];
this.groupNames = []; //数组记录每个group的名字
//图的大小设置
this.defaults.legend = true;
this.defaults.width = 800;
this.defaults.height = 800;
//设置用户指定的属性
this.setOptions(options);
this.legendArea = [20, (this.defaults.height - 20 - 220), 200, 220];
if (this.defaults.legend) {
this.xOffset = this.legendArea[2];
} else {
this.xOffset = 0;
}
this.defaults.innerRadius = Math.min((this.defaults.width - this.xOffset), this.defaults.height) * 0.38;
this.defaults.outerRadius = this.defaults.innerRadius * 1.10;
//创建画布
this.createCanvas();
}
});
/**
* 创建画布
*/
Chord.prototype.createCanvas = function () {
this.canvas = new Raphael(this.node, this.defaults.width, this.defaults.height);
canvasStyle = this.node.style;
canvasStyle.position = "relative";
this.floatTag = DataV.FloatTag()(this.node);
this.floatTag.css({
"visibility": "hidden"
});
};
/**
* 获取颜色
* @param {Number} i 元素类别编号
* @return {String} 返回颜色值
*/
Chord.prototype.getColor = function (i) {
var color = DataV.getColor();
return color[i % color.length][0];
};
/**
* 绘制弦图
*/
Chord.prototype.render = function () {
this.layout();
if (this.defaults.legend) {
this.legend();
}
};
/**
* 绘制图例
*/
Chord.prototype.legend = function () {
var that = this;
var paper = this.canvas;
var legendArea = this.legendArea;
var rectBn = paper.set();
this.underBn = [];
var underBn = this.underBn;
for (i = 0; i <= this.groupNum; i++) {
//底框
underBn.push(paper.rect(legendArea[0] + 10, legendArea[1] + 10 + (20 + 3) * i, 180, 20).attr({
"fill": "#ebebeb",
"stroke": "none"
//"r": 3
}).hide());
//色框
paper.rect(legendArea[0] + 10 + 3, legendArea[1] + 10 + (20 + 3) * i + 6, 16, 8).attr({
"fill": this.getColor(i),
"stroke": "none"
});
//文字
paper.text(legendArea[0] + 10 + 3 + 16 + 8, legendArea[1] + 10 + (20 + 3) * i + 10, this.groupNames[i]).attr({
"fill": "black",
"fill-opacity": 1,
"font-family": "Verdana",
"font-size": 12
}).attr({
"text-anchor": "start"
});
//选框
rectBn.push(paper.rect(legendArea[0] + 10, legendArea[1] + 10 + (20 + 3) * i, 180, 20).attr({
"fill": "white",
"fill-opacity": 0,
"stroke": "none"
//"r": 3
})).data("clicked", 0);
}
rectBn.forEach(function (d, i) {
d.mouseover(function () {
if (d.data("clicked") === 0) {
underBn[i].attr('opacity', 0.5);
underBn[i].show();
}
}).mouseout(function () {
if (d.data("clicked") === 0) {
underBn[i].hide();
}
});
d.click(function () {
for (j = 0; j < underBn.length; j++) {
if (j === i) {
underBn[j].show();
} else {
underBn[j].hide();
}
}
rectBn.forEach(function (eachBn) {
if (eachBn !== d) {
eachBn.data("clicked", 0);
}
});
if (d.data("clicked") === 0) {
underBn[i].attr('opacity', 1);
underBn[i].show();
that.chordGroups.forEach(function (d) {
if (d.data('source') !== i && d.data('target') !== i) {
d.attr({
'fill-opacity': 0.1
});
} else {
d.attr({
'fill-opacity': 0.6
});
}
});
d.data("clicked", 1);
} else if (d.data("clicked") === 1) {
underBn[i].hide();
d.data("clicked", 0);
that.chordGroups.forEach(function (d) {
d.attr({
'fill-opacity': 0.6
});
});
}
});
});
};
/**
*对原始数据进行处理
* @param {Array} table 将要被绘制成饼图的二维表数据
*/
Chord.prototype.setSource = function (table) {
if (table[0][0] !== null) {
var t;
for (t = 0; t < table[0].length; t++) {
this.groupNames[t] = table[0][t];
}
table = table.slice(1); // 从第一行开始第0行舍去
}
var group = [];
this.groupNum = table[0].length;
var groupNum = this.groupNum;
var that = this;
table.forEach(function (d, i) {
if (d.length !== groupNum || table.length !== groupNum) {
throw new Error("The source data should be an n * n matrix!");
}
group[i] = [];
var s;
for (s = 0; s < groupNum; s++) {
group[i][s] = Number(d[s]);
}
});
var r;
for (r = 0; r < groupNum; r++) {
that.matrix[r] = group[r];
}
};
/**
*创建chord布局
*/
Chord.prototype.layout = function () {
var floatTag = this.floatTag;
var that = this;
that.canvas.clear();
/*var see = [
[11975, 5871, 8916, 2868],
[1951, 10048, 2060, 6171],
[8010, 16145, 8090, 8045],
[1013, 990, 940, 6907]
];*/
var chordLayout = d3.layout.chord().padding(0.05) //chord segments之间的padding间隔
.sortSubgroups(d3.descending) //chord segments细分后的排序规则
.matrix(that.matrix);
/*var fillColor = d3.scale.ordinal()
.domain(d3.range(4))
.range(["#000000", "#FFDD89", "#957244", "#F26223"]);*/
//groups数组获取每个组的起始角度、数值、索引等属性
var groups = chordLayout.groups();
//由内外半径、起始角度计算路径字符串
var pathCalc = d3.svg.arc().innerRadius(that.defaults.innerRadius).outerRadius(that.defaults.outerRadius).startAngle(function (d) {
return d.startAngle;
}).endAngle(function (d) {
return d.endAngle;
});
var chords = chordLayout.chords();
//计算弦的路径曲线
var chordCalc = d3.svg.chord().radius(that.defaults.innerRadius);
//Raphael: Paper.path()
var donutEle;
//获取每个环形的字符串表示
var spline;
//表示每条弦的element
var chordEle;
//每条弦的字符串表示
var belt;
var num; //每个group分割小格数
var unitAngle; //每个group所占的角度
var angle;
var radian;
var tickLine;
var tickStr; //每个tick的路径
var xTrans, yTrans;
var aX, aY, bX, bY; //每个tick起始端点的坐标
var anchor;
var rotateStr;
var wordStr;
var word;
var textEl;
var wXTrans, wYTrans;
var tips;
var minValue = 1000;
that.chordGroups = that.canvas.set();
that.donutGroups = that.canvas.set();
$(this.node).append(this.floatTag);
//计算某条弦被赋值为target或source的颜色
var colorCalc = function (index) {
var i = chords[index].target.value > chords[index].source.value ? chords[index].target.index : chords[index].source.index;
return i;
};
//添加透明效果
var mouseOverDonut = function () {
floatTag.html('<div style = "text-align: center;margin:auto;color:'
//+ jqNode.color
+
"#ffffff" + '">' + this.data('text') + '</div>');
floatTag.css({
"visibility": "visible"
});
that.underBn.forEach(function (d) {
d.hide();
});
index = this.data("donutIndex");
that.chordGroups.forEach(function (d) {
if (d.data('source') !== index && d.data('target') !== index) {
d.attr({
'fill-opacity': 0.1
});
} else {
d.attr({
'fill-opacity': 0.6
});
}
});
//fade(this.data("donutIndex"), 0.2);
that.underBn[index].attr('opacity', 0.5).show();
};
var mouseOutDonut = function () {
floatTag.css({
"visibility": "hidden"
});
index = this.data("donutIndex");
that.chordGroups.forEach(function (d) {
if (d.data('source') !== index && d.data('target') !== index) {
d.attr({
'fill-opacity': 0.6
});
}
});
//fade(this.data("donutIndex"), 0.6);
that.underBn[index].hide();
};
var mouseoverChord = function () {
floatTag.html('<div style="text-align: center;margin:auto;color:#ffffff">' + this.data('text') + '</div>');
floatTag.css({
"visibility": "visible"
});
that.underBn.forEach(function (d) {
d.hide();
});
that.chordGroups.forEach(function (d) {
d.attr("fill-opacity", 0.1);
});
if (navigator.appName !== "Microsoft Internet Explorer") {
this.toFront(); //把当前弦移到画布最上层
}
this.attr("fill-opacity", 0.7);
that.underBn[this.data('source')].attr('opacity', 0.5).show();
};
var mouseoutChord = function () {
floatTag.css({
"visibility": "hidden"
});
//alert("***");
that.chordGroups.forEach(function (d) {
d.attr("fill-opacity", 0.6);
});
//this.attr("fill-opacity", 0.6);
that.underBn[this.data('source')].hide();
};
//画弦*********************************************************
var t;
for (t = 0; t <= chords.length - 1; t++) {
//alert(chords.length);
belt = chordCalc(chords[t]);
//hover到弦上时的效果
tips = that.groupNames[chords[t].source.index] + " to " + that.groupNames[chords[t].target.index] + ": " + that.matrix[chords[t].source.index][chords[t].target.index] + "," + that.groupNames[chords[t].target.index] + " to " + that.groupNames[chords[t].source.index] + ": " + that.matrix[chords[t].target.index][chords[t].source.index];
chordEle = that.canvas.path(belt).
translate((that.defaults.width - this.xOffset) / 2 + this.xOffset, that.defaults.height / 2).attr({
"path": belt,
"fill": that.getColor(colorCalc(t)),
"fill-opacity": 0.6,
"stroke": "#d6d6d6",
"stroke-opacity": 0.1
}).hover(mouseoverChord, mouseoutChord).data("source", chords[t].source.index).data("target", chords[t].target.index);
//.attr("fill", fillColor(chords[t].target.index))
chordEle.data('text', tips);
that.chordGroups.push(chordEle);
}
//画圆弧*********************************************************
var i, r;
var donutName;
var nameStr;
var nameX, nameY;
var ro, a;
var sum = 0;
for (r = 0; r <= groups.length - 1; r++) {
sum += groups[r].value;
}
for (i = 0; i <= groups.length - 1; i++) {
//画外圈的pie图**************************************
//计算每个group的path
spline = pathCalc(groups[i]);
tips = that.groupNames[i] + ": " + Math.round(groups[i].value) + " " + (groups[i].value * 100 / sum).toFixed(2) + "%";
donutEle = that.canvas.path(spline).translate((that.defaults.width - this.xOffset) / 2 + this.xOffset, that.defaults.height / 2).data("donutIndex", i).attr({
"path": spline,
"fill": that.getColor(i),
"stroke": that.getColor(i)
}).mouseover(mouseOverDonut).mouseout(mouseOutDonut);
donutEle.data('text', tips);
that.donutGroups.push(donutEle);
//每个donut上显示名称
ro = groups[i].startAngle * 180 / Math.PI - 86 + 90;
a = (groups[i].startAngle * 180 / Math.PI - 86) * Math.PI / 180;
nameX = ((that.defaults.outerRadius - that.defaults.innerRadius) / 2 + that.defaults.innerRadius) * Math.cos(a);
nameY = ((that.defaults.outerRadius - that.defaults.innerRadius) / 2 + that.defaults.innerRadius) * Math.sin(a);
nameStr = "T" + ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + "," + that.defaults.height / 2 + "R" + ro + "T" + nameX + "," + nameY;
if ((groups[i].endAngle - groups[i].startAngle) * 180 / Math.PI > 10) {
donutName = that.canvas.text().attr("font", "12px Verdana").attr("text", that.groupNames[i]).transform(nameStr);
}
//画刻度和刻度值**************************************
num = groups[i].value / 5000;
//最细分的每个小格代表的数值大小
unitAngle = (groups[i].endAngle - groups[i].startAngle) * 180 / Math.PI / num;
var j;
for (j = 0; j <= num; j++) {
//计算旋转角度和水平、竖直方向所需平移的距离
radian = ((groups[i].startAngle * 180 / Math.PI - 90) + j * unitAngle);
angle = radian * Math.PI / 180;
xTrans = that.defaults.outerRadius * Math.cos(angle);
yTrans = that.defaults.outerRadius * Math.sin(angle);
tickStr = "T" + ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + "," + that.defaults.height / 2 + "T" + xTrans + "," + yTrans;
//刻度线的起点终点坐标
aX = ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + xTrans;
aY = that.defaults.height / 2 + yTrans;
bX = ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + (that.defaults.outerRadius + 6) * Math.cos(angle);
bY = that.defaults.height / 2 + (that.defaults.outerRadius + 6) * Math.sin(angle);
tickLine = "M" + aX + "," + aY + "L" + bX + "," + bY;
that.canvas.path(tickLine).attr({
'stroke': "#929292",
"stroke-width": '1px'
}); //绘制刻度
//每隔五个刻度,绘制一次文字
if (j % 2 === 0) {
//计算text-anchor
if (radian + 90 < 180) {
anchor = "start";
} else {
anchor = "end";
}
//计算文字方向是否需要旋转180度
if (radian + 90 < 180) {
rotateStr = null;
} else {
rotateStr = "R180";
}
wXTrans = (that.defaults.outerRadius + 10) * Math.cos(angle);
wYTrans = (that.defaults.outerRadius + 10) * Math.sin(angle);
word = j % 2 ? "" : Math.round(((groups[i].value / num) * j) / 1000);
wordStr = "T" + ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + "," + that.defaults.height / 2 + "R" + radian
/*(groups[i].startAngle * 180 / Math.PI - 90)*/ + rotateStr + "T" + wXTrans + "," + wYTrans;
//绘制文字
textEl = that.canvas.text(0, 0, word).attr("font", "12px Verdana").transform(wordStr).attr("text-anchor", anchor).attr('fill', "#929292");
}
}
}
/*this.canvas.text().attr("font", "12px arial").translate((that.defaults.width - this.xOffset) / 2 + this.xOffset, this.defaults.height).attr("text", "The unit of the scale on the periphery is 1000. \n 刻度值的单位为1000。");
*/
};
return Chord;
/*global Raphael, d3, $, define */
/*!
* Chord的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) {
return this[id];
});
}
})('Chord', function (require) {
var DataV = require('DataV');
/**
* 构造函数
* @param {Object} node 表示在html的哪个容器中绘制该组件
* @param {Object} options 为用户自定义的组件的属性比如画布大小
*/
var Chord = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Chord";
this.node = this.checkContainer(node);
this.matrix = [];
this.groupNames = []; //数组记录每个group的名字
//图的大小设置
this.defaults.legend = true;
this.defaults.width = 800;
this.defaults.height = 800;
//设置用户指定的属性
this.setOptions(options);
this.legendArea = [20, (this.defaults.height - 20 - 220), 200, 220];
if (this.defaults.legend) {
this.xOffset = this.legendArea[2];
} else {
this.xOffset = 0;
}
this.defaults.innerRadius = Math.min((this.defaults.width - this.xOffset), this.defaults.height) * 0.38;
this.defaults.outerRadius = this.defaults.innerRadius * 1.10;
//创建画布
this.createCanvas();
}
});
/**
* 创建画布
*/
Chord.prototype.createCanvas = function () {
this.canvas = new Raphael(this.node, this.defaults.width, this.defaults.height);
canvasStyle = this.node.style;
canvasStyle.position = "relative";
this.floatTag = DataV.FloatTag()(this.node);
this.floatTag.css({
"visibility": "hidden"
});
};
/**
* 获取颜色
* @param {Number} i 元素类别编号
* @return {String} 返回颜色值
*/
Chord.prototype.getColor = function (i) {
var color = DataV.getColor();
return color[i % color.length][0];
};
/**
* 绘制弦图
*/
Chord.prototype.render = function () {
this.layout();
if (this.defaults.legend) {
this.legend();
}
};
/**
* 绘制图例
*/
Chord.prototype.legend = function () {
var that = this;
var paper = this.canvas;
var legendArea = this.legendArea;
var rectBn = paper.set();
this.underBn = [];
var underBn = this.underBn;
for (i = 0; i <= this.groupNum; i++) {
//底框
underBn.push(paper.rect(legendArea[0] + 10, legendArea[1] + 10 + (20 + 3) * i, 180, 20).attr({
"fill": "#ebebeb",
"stroke": "none"
//"r": 3
}).hide());
//色框
paper.rect(legendArea[0] + 10 + 3, legendArea[1] + 10 + (20 + 3) * i + 6, 16, 8).attr({
"fill": this.getColor(i),
"stroke": "none"
});
//文字
paper.text(legendArea[0] + 10 + 3 + 16 + 8, legendArea[1] + 10 + (20 + 3) * i + 10, this.groupNames[i]).attr({
"fill": "black",
"fill-opacity": 1,
"font-family": "Verdana",
"font-size": 12
}).attr({
"text-anchor": "start"
});
//选框
rectBn.push(paper.rect(legendArea[0] + 10, legendArea[1] + 10 + (20 + 3) * i, 180, 20).attr({
"fill": "white",
"fill-opacity": 0,
"stroke": "none"
//"r": 3
})).data("clicked", 0);
}
rectBn.forEach(function (d, i) {
d.mouseover(function () {
if (d.data("clicked") === 0) {
underBn[i].attr('opacity', 0.5);
underBn[i].show();
}
}).mouseout(function () {
if (d.data("clicked") === 0) {
underBn[i].hide();
}
});
d.click(function () {
for (j = 0; j < underBn.length; j++) {
if (j === i) {
underBn[j].show();
} else {
underBn[j].hide();
}
}
rectBn.forEach(function (eachBn) {
if (eachBn !== d) {
eachBn.data("clicked", 0);
}
});
if (d.data("clicked") === 0) {
underBn[i].attr('opacity', 1);
underBn[i].show();
that.chordGroups.forEach(function (d) {
if (d.data('source') !== i && d.data('target') !== i) {
d.attr({
'fill-opacity': 0.1
});
} else {
d.attr({
'fill-opacity': 0.6
});
}
});
d.data("clicked", 1);
} else if (d.data("clicked") === 1) {
underBn[i].hide();
d.data("clicked", 0);
that.chordGroups.forEach(function (d) {
d.attr({
'fill-opacity': 0.6
});
});
}
});
});
};
/**
*对原始数据进行处理
* @param {Array} table 将要被绘制成饼图的二维表数据
*/
Chord.prototype.setSource = function (table) {
if (table[0][0] !== null) {
var t;
for (t = 0; t < table[0].length; t++) {
this.groupNames[t] = table[0][t];
}
table = table.slice(1); // 从第一行开始第0行舍去
}
var group = [];
this.groupNum = table[0].length;
var groupNum = this.groupNum;
var that = this;
table.forEach(function (d, i) {
if (d.length !== groupNum || table.length !== groupNum) {
throw new Error("The source data should be an n * n matrix!");
}
group[i] = [];
var s;
for (s = 0; s < groupNum; s++) {
group[i][s] = Number(d[s]);
}
});
var r;
for (r = 0; r < groupNum; r++) {
that.matrix[r] = group[r];
}
};
/**
*创建chord布局
*/
Chord.prototype.layout = function () {
var floatTag = this.floatTag;
var that = this;
that.canvas.clear();
/*var see = [
[11975, 5871, 8916, 2868],
[1951, 10048, 2060, 6171],
[8010, 16145, 8090, 8045],
[1013, 990, 940, 6907]
];*/
var chordLayout = d3.layout.chord().padding(0.05) //chord segments之间的padding间隔
.sortSubgroups(d3.descending) //chord segments细分后的排序规则
.matrix(that.matrix);
/*var fillColor = d3.scale.ordinal()
.domain(d3.range(4))
.range(["#000000", "#FFDD89", "#957244", "#F26223"]);*/
//groups数组获取每个组的起始角度、数值、索引等属性
var groups = chordLayout.groups();
//由内外半径、起始角度计算路径字符串
var pathCalc = d3.svg.arc().innerRadius(that.defaults.innerRadius).outerRadius(that.defaults.outerRadius).startAngle(function (d) {
return d.startAngle;
}).endAngle(function (d) {
return d.endAngle;
});
var chords = chordLayout.chords();
//计算弦的路径曲线
var chordCalc = d3.svg.chord().radius(that.defaults.innerRadius);
//Raphael: Paper.path()
var donutEle;
//获取每个环形的字符串表示
var spline;
//表示每条弦的element
var chordEle;
//每条弦的字符串表示
var belt;
var num; //每个group分割小格数
var unitAngle; //每个group所占的角度
var angle;
var radian;
var tickLine;
var tickStr; //每个tick的路径
var xTrans, yTrans;
var aX, aY, bX, bY; //每个tick起始端点的坐标
var anchor;
var rotateStr;
var wordStr;
var word;
var textEl;
var wXTrans, wYTrans;
var tips;
var minValue = 1000;
that.chordGroups = that.canvas.set();
that.donutGroups = that.canvas.set();
$(this.node).append(this.floatTag);
//计算某条弦被赋值为target或source的颜色
var colorCalc = function (index) {
var i = chords[index].target.value > chords[index].source.value ? chords[index].target.index : chords[index].source.index;
return i;
};
//添加透明效果
var mouseOverDonut = function () {
floatTag.html('<div style = "text-align: center;margin:auto;color:'
//+ jqNode.color
+
"#ffffff" + '">' + this.data('text') + '</div>');
floatTag.css({
"visibility": "visible"
});
that.underBn.forEach(function (d) {
d.hide();
});
index = this.data("donutIndex");
that.chordGroups.forEach(function (d) {
if (d.data('source') !== index && d.data('target') !== index) {
d.attr({
'fill-opacity': 0.1
});
} else {
d.attr({
'fill-opacity': 0.6
});
}
});
//fade(this.data("donutIndex"), 0.2);
that.underBn[index].attr('opacity', 0.5).show();
};
var mouseOutDonut = function () {
floatTag.css({
"visibility": "hidden"
});
index = this.data("donutIndex");
that.chordGroups.forEach(function (d) {
if (d.data('source') !== index && d.data('target') !== index) {
d.attr({
'fill-opacity': 0.6
});
}
});
//fade(this.data("donutIndex"), 0.6);
that.underBn[index].hide();
};
var mouseoverChord = function () {
floatTag.html('<div style="text-align: center;margin:auto;color:#ffffff">' + this.data('text') + '</div>');
floatTag.css({
"visibility": "visible"
});
that.underBn.forEach(function (d) {
d.hide();
});
that.chordGroups.forEach(function (d) {
d.attr("fill-opacity", 0.1);
});
if (navigator.appName !== "Microsoft Internet Explorer") {
this.toFront(); //把当前弦移到画布最上层
}
this.attr("fill-opacity", 0.7);
that.underBn[this.data('source')].attr('opacity', 0.5).show();
};
var mouseoutChord = function () {
floatTag.css({
"visibility": "hidden"
});
//alert("***");
that.chordGroups.forEach(function (d) {
d.attr("fill-opacity", 0.6);
});
//this.attr("fill-opacity", 0.6);
that.underBn[this.data('source')].hide();
};
//画弦*********************************************************
var t;
for (t = 0; t <= chords.length - 1; t++) {
//alert(chords.length);
belt = chordCalc(chords[t]);
//hover到弦上时的效果
tips = that.groupNames[chords[t].source.index] + " to " + that.groupNames[chords[t].target.index] + ": " + that.matrix[chords[t].source.index][chords[t].target.index] + "," + that.groupNames[chords[t].target.index] + " to " + that.groupNames[chords[t].source.index] + ": " + that.matrix[chords[t].target.index][chords[t].source.index];
chordEle = that.canvas.path(belt).
translate((that.defaults.width - this.xOffset) / 2 + this.xOffset, that.defaults.height / 2).attr({
"path": belt,
"fill": that.getColor(colorCalc(t)),
"fill-opacity": 0.6,
"stroke": "#d6d6d6",
"stroke-opacity": 0.1
}).hover(mouseoverChord, mouseoutChord).data("source", chords[t].source.index).data("target", chords[t].target.index);
//.attr("fill", fillColor(chords[t].target.index))
chordEle.data('text', tips);
that.chordGroups.push(chordEle);
}
//画圆弧*********************************************************
var i, r;
var donutName;
var nameStr;
var nameX, nameY;
var ro, a;
var sum = 0;
for (r = 0; r <= groups.length - 1; r++) {
sum += groups[r].value;
}
for (i = 0; i <= groups.length - 1; i++) {
//画外圈的pie图**************************************
//计算每个group的path
spline = pathCalc(groups[i]);
tips = that.groupNames[i] + ": " + Math.round(groups[i].value) + " " + (groups[i].value * 100 / sum).toFixed(2) + "%";
donutEle = that.canvas.path(spline).translate((that.defaults.width - this.xOffset) / 2 + this.xOffset, that.defaults.height / 2).data("donutIndex", i).attr({
"path": spline,
"fill": that.getColor(i),
"stroke": that.getColor(i)
}).mouseover(mouseOverDonut).mouseout(mouseOutDonut);
donutEle.data('text', tips);
that.donutGroups.push(donutEle);
//每个donut上显示名称
ro = groups[i].startAngle * 180 / Math.PI - 86 + 90;
a = (groups[i].startAngle * 180 / Math.PI - 86) * Math.PI / 180;
nameX = ((that.defaults.outerRadius - that.defaults.innerRadius) / 2 + that.defaults.innerRadius) * Math.cos(a);
nameY = ((that.defaults.outerRadius - that.defaults.innerRadius) / 2 + that.defaults.innerRadius) * Math.sin(a);
nameStr = "T" + ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + "," + that.defaults.height / 2 + "R" + ro + "T" + nameX + "," + nameY;
if ((groups[i].endAngle - groups[i].startAngle) * 180 / Math.PI > 10) {
donutName = that.canvas.text().attr("font", "12px Verdana").attr("text", that.groupNames[i]).transform(nameStr);
}
//画刻度和刻度值**************************************
num = groups[i].value / 5000;
//最细分的每个小格代表的数值大小
unitAngle = (groups[i].endAngle - groups[i].startAngle) * 180 / Math.PI / num;
var j;
for (j = 0; j <= num; j++) {
//计算旋转角度和水平、竖直方向所需平移的距离
radian = ((groups[i].startAngle * 180 / Math.PI - 90) + j * unitAngle);
angle = radian * Math.PI / 180;
xTrans = that.defaults.outerRadius * Math.cos(angle);
yTrans = that.defaults.outerRadius * Math.sin(angle);
tickStr = "T" + ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + "," + that.defaults.height / 2 + "T" + xTrans + "," + yTrans;
//刻度线的起点终点坐标
aX = ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + xTrans;
aY = that.defaults.height / 2 + yTrans;
bX = ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + (that.defaults.outerRadius + 6) * Math.cos(angle);
bY = that.defaults.height / 2 + (that.defaults.outerRadius + 6) * Math.sin(angle);
tickLine = "M" + aX + "," + aY + "L" + bX + "," + bY;
that.canvas.path(tickLine).attr({
'stroke': "#929292",
"stroke-width": '1px'
}); //绘制刻度
//每隔五个刻度,绘制一次文字
if (j % 2 === 0) {
//计算text-anchor
if (radian + 90 < 180) {
anchor = "start";
} else {
anchor = "end";
}
//计算文字方向是否需要旋转180度
if (radian + 90 < 180) {
rotateStr = null;
} else {
rotateStr = "R180";
}
wXTrans = (that.defaults.outerRadius + 10) * Math.cos(angle);
wYTrans = (that.defaults.outerRadius + 10) * Math.sin(angle);
word = j % 2 ? "" : Math.round(((groups[i].value / num) * j) / 1000);
wordStr = "T" + ((that.defaults.width - that.xOffset) / 2 + that.xOffset) + "," + that.defaults.height / 2 + "R" + radian
/*(groups[i].startAngle * 180 / Math.PI - 90)*/ + rotateStr + "T" + wXTrans + "," + wYTrans;
//绘制文字
textEl = that.canvas.text(0, 0, word).attr("font", "12px Verdana").transform(wordStr).attr("text-anchor", anchor).attr('fill', "#929292");
}
}
}
/*this.canvas.text().attr("font", "12px arial").translate((that.defaults.width - this.xOffset) / 2 + this.xOffset, this.defaults.height).attr("text", "The unit of the scale on the periphery is 1000. \n 刻度值的单位为1000。");
*/
};
return Chord;
});

File diff suppressed because it is too large Load Diff

View File

@ -1,261 +1,261 @@
/*global EventProxy, d3, Raphael, $ */
/*!
* Flow的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Flow', function (require) {
var DataV = require('DataV');
var theme = DataV.Themes;
/**
* Flow构造函数
*/
var Flow = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Flow";
this.node = this.checkContainer(node);
// Properties
this.font = {};
// Canvas
this.defaults.width = 500;
this.defaults.height = 400;
this.defaults.deep = 150;
this.defaults.radius = 50;
this.defaults.xStep = 300;
this.defaults.xStart = 200;
this.defaults.yStart = 50;
this.setOptions(options);
this.createCanvas();
}
});
Flow.prototype.setSource = function (source) {
var conf = this.defaults;
this.rawData = source;
this.source = this.remapSource(source);
};
Flow.prototype.remapSource = function (data) {
console.log(data);
var dataLength = data.length;
var remapData = [];
var total;
var i;
for (i = 0; i < dataLength; i++){
if (!data[i][3]) {
total = data[i][2];
remapData.push({id: data[i][0], name: data[i][1], value: data[i][2], pid: data[i][3], child: [], deep: 0});
} else {
remapData.push({id: data[i][0], name: data[i][1], value: data[i][2], pid: data[i][3], child: [], deep: 0});
}
}
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var radius = conf.radius;
var xStep = conf.xStep;
var xStart = conf.xStart;
var yStart = conf.yStart;
var depth = 0;
for (i = 0; i < dataLength; i++){
if (remapData[i].pid) {
remapData[i].deep = remapData[remapData[i].pid - 1].deep + 1;
remapData[remapData[i].pid - 1].child.push(remapData[i].id - 1);
if (remapData[i].deep > depth) {
depth = remapData[i].deep;
}
}
// remapData[remapData[i].pid].child.push(remapData[i].id);
}
this.depth = depth;
radius = Math.min(Math.min((width - xStep * (depth - 1) - xStart * 2) / depth, height*0.55), radius);
console.log("r:" + radius);
for (i = 0; i < dataLength; i++){
remapData[i].percent = remapData[i].value / total;
remapData[i].radius = radius * remapData[i].percent;
}
return remapData;
// return data;
};
Flow.prototype.layout = function () {
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var xStart = conf.xStart;
var yStart = conf.yStart;
var xStep = conf.xStep;
var remapData = this.source;
//console.log(this.source);
var circleData = [];
circleData.push({x: width * 0.24, y: height * 0.42, radius: Math.max(10, remapData[0].radius), deep: remapData[0].deep, name: remapData[0].name, value: remapData[0].value});
circleData.push({x: width * 0.5, y: height * 0.245, radius: Math.max(10, remapData[1].radius), deep: remapData[1].deep, name: remapData[1].name, value: remapData[1].value});
circleData.push({x: width * 0.5, y: height * 0.6, radius: Math.max(10, remapData[2].radius), deep: remapData[2].deep, name: remapData[2].name, value: remapData[2].value});
circleData.push({x: width * 0.72, y: height * 0.5, radius: Math.max(10, remapData[3].radius), deep: remapData[3].deep, name: remapData[3].name, value: remapData[3].value});
circleData.push({x: width * 0.72, y: height * 0.817, radius: Math.max(10, remapData[4].radius), deep: remapData[4].deep, name: remapData[4].name, value: remapData[4].value});
for (i = 0;i < circleData.length; i++) {
console.log(circleData[i].x);
}
this.circleData = circleData;
};
Flow.prototype.getColor = function () {
var colorMatrix = DataV.getColor();
return color;
};
// Tree.prototype.getFont = function () {
// //var conf = this.defaults;
// return DataV.getFont();
// };
Flow.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.width, conf.height);
this.DOMNode = $(this.canvas.canvas);
var that = this;
this.DOMNode.click(function (event) {
that.trigger("click", event);
});
this.DOMNode.dblclick(function (event) {
that.trigger("dblclick", event);
});
var mousewheel = document.all ? "mousewheel" : "DOMMouseScroll";
this.DOMNode.bind(mousewheel, function (event) {
that.trigger("mousewheel", event);
});
this.DOMNode.bind("contextmenu", function (event) {
that.trigger("contextmenu", event);
});
this.DOMNode.delegate("circle", "click", function (event) {
that.trigger("circle_click", event);
});
this.DOMNode.delegate("circle", "mouseover", function (event) {
that.trigger("circle_mouseover", event);
});
this.DOMNode.delegate("circle", "mouseout", function (event) {
that.trigger("circle_mouseout", event);
});
//console.log(this.canvas);
};
Flow.prototype.getLinkPath = function (fx, fy, tx, ty) {
var conf = this.defaults;
var c1x = fx + (tx - fx) / 1.5;
var c1y = fy;
var c2x = tx - (tx - fx) / 4;
var c2y = ty - (ty - fy) / 2;
var link_path = [["M", fx, fy],
["S", c1x, c1y, tx, ty]];
return link_path;
};
Flow.prototype.generatePaths = function () {
var canvas = this.canvas;
var source = this.source;
var conf = this.defaults;
var radius = conf.radius;
//canvas.clear();
// var font = this.getFont();
var font_family = '微软雅黑';
var font_size = 8;
var depth = this.depth;
var crilceData = this.circleData;
var l = crilceData.length;
var getLinkPath = this.getLinkPath;
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[0].x, crilceData[0].y, crilceData[1].x, crilceData[1].y)});
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[0].x, crilceData[0].y, crilceData[2].x, crilceData[2].y)});
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[2].x, crilceData[2].y, crilceData[3].x, crilceData[3].y)});
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[2].x, crilceData[2].y, crilceData[4].x, crilceData[4].y)});
var i, d;
var thisRadius;
var thisColor;
var titelPath = [];
var valuePath = [];
for (i = 0 ; i < l ; i++) {
d = crilceData[i];
thisRadius = Math.max(27, d.radius);
if (i === 1) {
thisColor = "#b4e481";
} else if (i === 4) {
thisColor = "#cd3a19";
} else {
thisColor = "#ffe79d";
}
canvas.circle(d.x, d.y, thisRadius)
.attr({"stroke": "none", fill: thisColor});
titelPath.push(canvas.text(0, 0, d.name).attr({'font-size': 12}));
if (i < l - 2) {
titelPath[i].transform("t" + d.x + "," + (d.y - thisRadius - titelPath[i].getBBox().height/2 - 5));
} else {
titelPath[i].transform("t" + d.x + "," + (d.y - thisRadius - titelPath[i].getBBox().height/2 - 5)).attr({"text-anchor": "start"});
}
if (i < l - 1) {
valuePath.push(canvas.text(d.x, d.y, d.value + "人").attr({'font-size': 12}));
} else {
valuePath.push(canvas.text(d.x, d.y, d.value + "人").attr({fill: "#ffffff", 'font-size': 12}));
}
}
var n = 0;
var node;
var num = 0;
var nodes = canvas.set();
var path = [];
var textpath = [];
var tree = this;
};
Flow.prototype.render = function (options) {
var st = new Date().getTime();
this.canvas.clear();
this.setOptions(options);
this.layout();
var st2 = new Date().getTime();
console.log(st2 - st);
this.generatePaths();
var et = new Date().getTime();
console.log(et - st2);
//this.canvas.renderfix();
};
return Flow;
});
/*global EventProxy, d3, Raphael, $ */
/*!
* Flow的兼容性定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Flow', function (require) {
var DataV = require('DataV');
var theme = DataV.Themes;
/**
* Flow构造函数
*/
var Flow = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Flow";
this.node = this.checkContainer(node);
// Properties
this.font = {};
// Canvas
this.defaults.width = 500;
this.defaults.height = 400;
this.defaults.deep = 150;
this.defaults.radius = 50;
this.defaults.xStep = 300;
this.defaults.xStart = 200;
this.defaults.yStart = 50;
this.setOptions(options);
this.createCanvas();
}
});
Flow.prototype.setSource = function (source) {
var conf = this.defaults;
this.rawData = source;
this.source = this.remapSource(source);
};
Flow.prototype.remapSource = function (data) {
console.log(data);
var dataLength = data.length;
var remapData = [];
var total;
var i;
for (i = 0; i < dataLength; i++){
if (!data[i][3]) {
total = data[i][2];
remapData.push({id: data[i][0], name: data[i][1], value: data[i][2], pid: data[i][3], child: [], deep: 0});
} else {
remapData.push({id: data[i][0], name: data[i][1], value: data[i][2], pid: data[i][3], child: [], deep: 0});
}
}
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var radius = conf.radius;
var xStep = conf.xStep;
var xStart = conf.xStart;
var yStart = conf.yStart;
var depth = 0;
for (i = 0; i < dataLength; i++){
if (remapData[i].pid) {
remapData[i].deep = remapData[remapData[i].pid - 1].deep + 1;
remapData[remapData[i].pid - 1].child.push(remapData[i].id - 1);
if (remapData[i].deep > depth) {
depth = remapData[i].deep;
}
}
// remapData[remapData[i].pid].child.push(remapData[i].id);
}
this.depth = depth;
radius = Math.min(Math.min((width - xStep * (depth - 1) - xStart * 2) / depth, height*0.55), radius);
console.log("r:" + radius);
for (i = 0; i < dataLength; i++){
remapData[i].percent = remapData[i].value / total;
remapData[i].radius = radius * remapData[i].percent;
}
return remapData;
// return data;
};
Flow.prototype.layout = function () {
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var xStart = conf.xStart;
var yStart = conf.yStart;
var xStep = conf.xStep;
var remapData = this.source;
//console.log(this.source);
var circleData = [];
circleData.push({x: width * 0.24, y: height * 0.42, radius: Math.max(10, remapData[0].radius), deep: remapData[0].deep, name: remapData[0].name, value: remapData[0].value});
circleData.push({x: width * 0.5, y: height * 0.245, radius: Math.max(10, remapData[1].radius), deep: remapData[1].deep, name: remapData[1].name, value: remapData[1].value});
circleData.push({x: width * 0.5, y: height * 0.6, radius: Math.max(10, remapData[2].radius), deep: remapData[2].deep, name: remapData[2].name, value: remapData[2].value});
circleData.push({x: width * 0.72, y: height * 0.5, radius: Math.max(10, remapData[3].radius), deep: remapData[3].deep, name: remapData[3].name, value: remapData[3].value});
circleData.push({x: width * 0.72, y: height * 0.817, radius: Math.max(10, remapData[4].radius), deep: remapData[4].deep, name: remapData[4].name, value: remapData[4].value});
for (i = 0;i < circleData.length; i++) {
console.log(circleData[i].x);
}
this.circleData = circleData;
};
Flow.prototype.getColor = function () {
var colorMatrix = DataV.getColor();
return color;
};
// Tree.prototype.getFont = function () {
// //var conf = this.defaults;
// return DataV.getFont();
// };
Flow.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.width, conf.height);
this.DOMNode = $(this.canvas.canvas);
var that = this;
this.DOMNode.click(function (event) {
that.trigger("click", event);
});
this.DOMNode.dblclick(function (event) {
that.trigger("dblclick", event);
});
var mousewheel = document.all ? "mousewheel" : "DOMMouseScroll";
this.DOMNode.bind(mousewheel, function (event) {
that.trigger("mousewheel", event);
});
this.DOMNode.bind("contextmenu", function (event) {
that.trigger("contextmenu", event);
});
this.DOMNode.delegate("circle", "click", function (event) {
that.trigger("circle_click", event);
});
this.DOMNode.delegate("circle", "mouseover", function (event) {
that.trigger("circle_mouseover", event);
});
this.DOMNode.delegate("circle", "mouseout", function (event) {
that.trigger("circle_mouseout", event);
});
//console.log(this.canvas);
};
Flow.prototype.getLinkPath = function (fx, fy, tx, ty) {
var conf = this.defaults;
var c1x = fx + (tx - fx) / 1.5;
var c1y = fy;
var c2x = tx - (tx - fx) / 4;
var c2y = ty - (ty - fy) / 2;
var link_path = [["M", fx, fy],
["S", c1x, c1y, tx, ty]];
return link_path;
};
Flow.prototype.generatePaths = function () {
var canvas = this.canvas;
var source = this.source;
var conf = this.defaults;
var radius = conf.radius;
//canvas.clear();
// var font = this.getFont();
var font_family = '微软雅黑';
var font_size = 8;
var depth = this.depth;
var crilceData = this.circleData;
var l = crilceData.length;
var getLinkPath = this.getLinkPath;
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[0].x, crilceData[0].y, crilceData[1].x, crilceData[1].y)});
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[0].x, crilceData[0].y, crilceData[2].x, crilceData[2].y)});
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[2].x, crilceData[2].y, crilceData[3].x, crilceData[3].y)});
canvas.path().attr({stroke: "#cdcdcd", "stroke-width": 2}).attr({path: getLinkPath(crilceData[2].x, crilceData[2].y, crilceData[4].x, crilceData[4].y)});
var i, d;
var thisRadius;
var thisColor;
var titelPath = [];
var valuePath = [];
for (i = 0 ; i < l ; i++) {
d = crilceData[i];
thisRadius = Math.max(27, d.radius);
if (i === 1) {
thisColor = "#b4e481";
} else if (i === 4) {
thisColor = "#cd3a19";
} else {
thisColor = "#ffe79d";
}
canvas.circle(d.x, d.y, thisRadius)
.attr({"stroke": "none", fill: thisColor});
titelPath.push(canvas.text(0, 0, d.name).attr({'font-size': 12}));
if (i < l - 2) {
titelPath[i].transform("t" + d.x + "," + (d.y - thisRadius - titelPath[i].getBBox().height/2 - 5));
} else {
titelPath[i].transform("t" + d.x + "," + (d.y - thisRadius - titelPath[i].getBBox().height/2 - 5)).attr({"text-anchor": "start"});
}
if (i < l - 1) {
valuePath.push(canvas.text(d.x, d.y, d.value + "人").attr({'font-size': 12}));
} else {
valuePath.push(canvas.text(d.x, d.y, d.value + "人").attr({fill: "#ffffff", 'font-size': 12}));
}
}
var n = 0;
var node;
var num = 0;
var nodes = canvas.set();
var path = [];
var textpath = [];
var tree = this;
};
Flow.prototype.render = function (options) {
var st = new Date().getTime();
this.canvas.clear();
this.setOptions(options);
this.layout();
var st2 = new Date().getTime();
console.log(st2 - st);
this.generatePaths();
var et = new Date().getTime();
console.log(et - st2);
//this.canvas.renderfix();
};
return Flow;
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,434 +1,434 @@
/*global EventProxy, d3, Raphael, $ */
/*!
* Matrix的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Matrix', function (require) {
var DataV = require('DataV');
var theme = DataV.Themes;
/**
* 构造函数
*/
var Matrix = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Matrix";
this.node = this.checkContainer(node);
// Properties
this.font = {};
// Canvas
this.defaults.width = 1200;
this.defaults.height = 1200;
this.defaults.axisWidth = 40;
this.setOptions(options);
this.createCanvas();
this.move = false;
}
});
Matrix.prototype.getDataTable = function (table) {
var title = table[0];
table = table.slice(1);
var titleLength = title.length;
var tableWidth = table[0].length;
var tableHeight = table.length;
this.tableWidth = tableWidth;
this.tableHeight = tableHeight;
//for symmetric matrix
if (tableWidth !== title.length || tableHeight !== title.length) {
throw new Error("This matrix is not symmetric matrix!!!");
} else {
this.tableWidth = tableWidth;
this.tableHeight = tableHeight;
}
this.title = title;
return table;
};
Matrix.prototype.setSource = function (source) {
var conf = this.defaults;
this.source = this.getDataTable(source);
this.hasSort = false;
// this.source = this.remapSource(source);
};
Matrix.prototype.layout = function () {
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var tableWidth = this.tableWidth;
var tableHeight = this.tableHeight;
var axisWidth = conf.axisWidth;
this.cellWidth = Math.min((width - axisWidth) / tableWidth, (height - axisWidth) / tableHeight);
var startX;
var startY;
var bRectWidth;
var matrixWidth;
if (width > height) {
startX = (width - height)/2 + axisWidth;
startY = axisWidth;
bRectWidth = height - axisWidth;
matrixWidth = bRectWidth - axisWidth;
} else if (height > width) {
startX = axisWidth;
startY = (height - width) + axisWidth;
bRectWidth = width - axisWidth;
} else {
startX = axisWidth;
startY = axisWidth;
bRectWidth = width - axisWidth;
matrixWidth = bRectWidth - axisWidth;
}
this.startX = startX;
this.startY = startY;
this.bRectWidth = bRectWidth;
this.matrixWidth = matrixWidth;
};
Matrix.prototype.getColor = function (i) {
var colorMatrix = DataV.getColor();
var length = colorMatrix.length;
var num = i % length;
//var color = '#939598';
var color = '#FFFFFF';
if (num !== 0) {
color = colorMatrix[num][0];
}
return color;
};
Matrix.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.width, conf.height);
this.DOMNode = $(this.canvas.canvas);
var that = this;
this.DOMNode.click(function (event) {
that.trigger("click", event);
that.update();
});
this.DOMNode.dblclick(function (event) {
that.trigger("dblclick", event);
});
var mousewheel = document.all ? "mousewheel" : "DOMMouseScroll";
this.DOMNode.bind(mousewheel, function (event) {
that.trigger("mousewheel", event);
});
this.DOMNode.bind("contextmenu", function (event) {
that.trigger("contextmenu", event);
});
this.DOMNode.delegate("circle", "click", function (event) {
that.trigger("circle_click", event);
});
this.DOMNode.delegate("circle", "mouseover", function (event) {
that.trigger("circle_mouseover", event);
});
this.DOMNode.delegate("circle", "mouseout", function (event) {
that.trigger("circle_mouseout", event);
});
};
Matrix.prototype.generatePaths = function () {
var canvas = this.canvas;
var source = this.source;
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var startX = this.startX;
var startY = this.startY;
var cellWidth = this.cellWidth;
var tableWidth = this.tableWidth;
var tableHeight = this.tableHeight;
var bRectWidth = this.bRectWidth;
var matrixWidth = this.matrixWidth;
//canvas.clear();
// var color = this.getColor();
// var font = this.getFont();
var font_family = '微软雅黑';
var font_size = 8;
var title = this.title;
var row = [];
var columnLine = [];
var columnText = [];
var backgroundRect = canvas.rect(startX, startY, bRectWidth, bRectWidth);
//backgroundRect.attr({fill: "#939598", stroke: "none", "fill-opacity": 0.8});
backgroundRect.attr({fill: "#ffffff", stroke: "none", "fill-opacity": 0.8});
backgroundRect.toBack();
var sort;
if (this.hasSort) {
sort = this.sort;
}
var i, j, a, b, color, rect;
var rects = []; //for column change move rect
for (i = 0; i < tableHeight; i++) {
if (!this.hasSort){
a = i;
} else {
for (j = 0; j < sort.length; j++) {
if (sort[j] === i) {
a = j;
}
}
}
var rowRect = canvas.set();
canvas.path("M" + startX + " " + (startY + cellWidth * i) + "L" + (startX + matrixWidth + 10 + cellWidth) + " "
+ (startY + cellWidth * i)).attr({stroke: "#D1D1D1", "stroke-width": 1});
rowRect.push(canvas.text(-20, cellWidth / 2, title[i])
.attr({"fill": "#000000",
"fill-opacity": 0.7,
"font-family": "Verdana",
//"font-weight": "bold",
"font-size": 12}));
for (j = 0; j < tableWidth; j++) {
if (!this.hasSort) {
color = this.getColor(source[i][j]);
} else {
color = this.getColor(source[i][sort[j]]);
}
rect = canvas.rect(cellWidth * j, 0, cellWidth, cellWidth)
.attr({stroke: "none", fill: color, "fill-opacity": 0.8});
rowRect.push(rect);
rects.push(rect);
}
rowRect.transform("t" + startX + ", " + (startY + cellWidth * a));
row.push(rowRect);
}
canvas.path("M" + startX + " " + (startY + cellWidth * tableHeight) + "L" + (startX + matrixWidth + 10 + cellWidth) + " "
+ (startY + cellWidth * tableHeight)).attr({stroke: "#D1D1D1", "stroke-width": 1});
for (i = 0; i < tableWidth; i++) {
// var columnLine = canvas.set();
// var columnText = canvas.set();
if (!this.hasSort){
a = i;
} else {
for (j = 0; j < sort.length; j++) {
if (sort[j] === i) {
a = j;
}
}
}
columnLine.push(canvas.path("M0 0L0 " + matrixWidth + 10 + cellWidth)
.attr({stroke: "#D1D1D1", "stroke-width": 1})
.transform("t" + (startX + cellWidth * a) + ", " + startY));
columnText.push(canvas.text(cellWidth / 2, -20, title[i])
.attr({"fill": "#000000",
"fill-opacity": 0.7,
"font-family": "Verdana",
//"font-weight": "bold",
"font-size": 12})
.transform("t" + (startX + cellWidth * a) + ", " + startY + "r90"));
}
columnLine.push(canvas.path("M0 0L0 " + matrixWidth + 10 + cellWidth)
.attr({stroke: "#D1D1D1", "stroke-width": 1})
.transform("t" + (startX + cellWidth * tableWidth) + ", " + startY));
this.row = row;
this.columnText = columnText;
this.columnLine = columnLine;
this.rects = rects;
};
Matrix.prototype.getSort = function (source) {
var sumQueue = [];
var sort = [];
var rowData;
var rowLength;
var sum;
var means;
var matrixD = [];
var quareSum;
var rowquareSum = [];
var i, j, k;
for (i = 0 ; i < source.length ; i++) {
rowData = source[i];
rowLength = rowData.length;
sum = 0;
quareSum = 0;
for (j = 0 ; j < rowLength ; j++) {
sum = sum + rowData[j];
}
means = sum / rowLength;
for (j = 0 ; j < rowLength ; j++) {
rowData[j] = rowData[j] - means;
quareSum = quareSum + Math.pow(rowData[j], 2);
}
quareSum = Math.sqrt(quareSum);
rowquareSum.push(quareSum);
matrixD.push(rowData);
}
var rowI;
var rowJ;
var matrixR = [];
for (i = 0 ; i < source.length ; i++) {
matrixR[i] = [];
for (j = 0 ; j < source.length ; j++) {
matrixR[i][j] = 0;
}
}
for (i = 0 ; i < source.length ; i++) {
rowI = matrixD[i];
matrixR[i][i] = source[i][i];
for (j = i + 1 ; j < source.length ; j++) {
sum = 0;
rowJ = matrixD[j];
for (k = 0; k < rowLength; k++) {
sum = sum + rowI[k] * rowJ[k];
}
sum = sum / (rowquareSum[i] * rowquareSum[j]);
matrixR[i][j] = sum;
matrixR[j][i] = sum;
}
}
return matrixR;
};
Matrix.prototype.update = function () {
var i, j;
var source = [];
for(i = 0; i < this.source.length ; i++){
source[i] = this.source[i].concat();
}
var sort = [];
for (i = 0; i < source[0].length; i++) {
sort.push(i);
}
if (this.hasSort) {
this.sort = sort;
this.hasSort = false;
} else {
var getSort = this.getSort;
var i, j;
var pt;
var nowSort = [];
var iterations = 12;
for (i = 0; i < iterations; i++) {
source = getSort(source);
}
nowSort = source[0];
var a, b;
for (i = 1; i < sort.length; i++) {
a = sort[i];
for (j = i + 1; j < sort.length; j++) {
b = sort[j];
if (nowSort[a] < nowSort[b]) {
pt = sort[i];
sort[i] = sort[j];
sort[j] = pt;
}
}
}
sort = [0,7,5,2,8,3,1,9,6,14,15,4,13,10,16,11,12];
this.sort = sort;
this.hasSort = true;
}
if (!this.move) {
this.move = true;
var rects = this.rects;
var num;
var startX = this.startX;
var startY = this.startY;
var cellWidth = this.cellWidth;
var rowAnim;
var columnLineAnim;
var columnTextAnim;
var anim;
for (i = 0; i < sort.length; i++) {
num = sort[i];
// if (num != i) {
rowAnim = Raphael.animation({transform: ["t", startX, (startY + cellWidth * i)]}, 200, "<>");
this.row[num].animate(rowAnim.delay(100 * i));
// }
}
var that = this;
var moveEnd = function () {
that.move = false;
};
for (i = 0; i < sort.length; i++) {
num = sort[i];
// if (num != i) {
//columnLineAnim = Raphael.animation({transform: ["t", (startX + cellWidth * i), startY]}, 1000, "<>");
columnTextAnim = Raphael.animation({transform: ["t", (startX + cellWidth * i), startY, "r", 90]},
200, "<>");
//this.columnLine[num].animate(columnLineAnim.delay(500 * (i + sort.length + 1)));
this.columnText[num].animate(columnTextAnim.delay(100 * (i + sort.length + 1)));
for (j = 0; j < sort.length; j++) {
if (i === sort.length - 1 && j === sort.length - 1) {
anim = Raphael.animation({'x': cellWidth * i}, 200, "<>", moveEnd);
} else {
anim = Raphael.animation({'x': cellWidth * i}, 200, "<>");
}
rects[j * sort.length + num].animate(anim.delay(100 * (i + sort.length + 1)));
}
// }
}
}
};
Matrix.prototype.render = function (options) {
if (!this.move) {
this.canvas.clear();
this.setOptions(options);
this.layout();
this.generatePaths();
}
};
return Matrix;
/*global EventProxy, d3, Raphael, $ */
/*!
* Matrix的兼容定义
*/
;(function (name, definition) {
if (typeof define === 'function') { // Module
define(definition);
} else { // Assign to common namespaces or simply the global object (window)
this[name] = definition(function (id) { return this[id];});
}
})('Matrix', function (require) {
var DataV = require('DataV');
var theme = DataV.Themes;
/**
* 构造函数
*/
var Matrix = DataV.extend(DataV.Chart, {
initialize: function (node, options) {
this.type = "Matrix";
this.node = this.checkContainer(node);
// Properties
this.font = {};
// Canvas
this.defaults.width = 1200;
this.defaults.height = 1200;
this.defaults.axisWidth = 40;
this.setOptions(options);
this.createCanvas();
this.move = false;
}
});
Matrix.prototype.getDataTable = function (table) {
var title = table[0];
table = table.slice(1);
var titleLength = title.length;
var tableWidth = table[0].length;
var tableHeight = table.length;
this.tableWidth = tableWidth;
this.tableHeight = tableHeight;
//for symmetric matrix
if (tableWidth !== title.length || tableHeight !== title.length) {
throw new Error("This matrix is not symmetric matrix!!!");
} else {
this.tableWidth = tableWidth;
this.tableHeight = tableHeight;
}
this.title = title;
return table;
};
Matrix.prototype.setSource = function (source) {
var conf = this.defaults;
this.source = this.getDataTable(source);
this.hasSort = false;
// this.source = this.remapSource(source);
};
Matrix.prototype.layout = function () {
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var tableWidth = this.tableWidth;
var tableHeight = this.tableHeight;
var axisWidth = conf.axisWidth;
this.cellWidth = Math.min((width - axisWidth) / tableWidth, (height - axisWidth) / tableHeight);
var startX;
var startY;
var bRectWidth;
var matrixWidth;
if (width > height) {
startX = (width - height)/2 + axisWidth;
startY = axisWidth;
bRectWidth = height - axisWidth;
matrixWidth = bRectWidth - axisWidth;
} else if (height > width) {
startX = axisWidth;
startY = (height - width) + axisWidth;
bRectWidth = width - axisWidth;
} else {
startX = axisWidth;
startY = axisWidth;
bRectWidth = width - axisWidth;
matrixWidth = bRectWidth - axisWidth;
}
this.startX = startX;
this.startY = startY;
this.bRectWidth = bRectWidth;
this.matrixWidth = matrixWidth;
};
Matrix.prototype.getColor = function (i) {
var colorMatrix = DataV.getColor();
var length = colorMatrix.length;
var num = i % length;
//var color = '#939598';
var color = '#FFFFFF';
if (num !== 0) {
color = colorMatrix[num][0];
}
return color;
};
Matrix.prototype.createCanvas = function () {
var conf = this.defaults;
this.canvas = new Raphael(this.node, conf.width, conf.height);
this.DOMNode = $(this.canvas.canvas);
var that = this;
this.DOMNode.click(function (event) {
that.trigger("click", event);
that.update();
});
this.DOMNode.dblclick(function (event) {
that.trigger("dblclick", event);
});
var mousewheel = document.all ? "mousewheel" : "DOMMouseScroll";
this.DOMNode.bind(mousewheel, function (event) {
that.trigger("mousewheel", event);
});
this.DOMNode.bind("contextmenu", function (event) {
that.trigger("contextmenu", event);
});
this.DOMNode.delegate("circle", "click", function (event) {
that.trigger("circle_click", event);
});
this.DOMNode.delegate("circle", "mouseover", function (event) {
that.trigger("circle_mouseover", event);
});
this.DOMNode.delegate("circle", "mouseout", function (event) {
that.trigger("circle_mouseout", event);
});
};
Matrix.prototype.generatePaths = function () {
var canvas = this.canvas;
var source = this.source;
var conf = this.defaults;
var width = conf.width;
var height = conf.height;
var startX = this.startX;
var startY = this.startY;
var cellWidth = this.cellWidth;
var tableWidth = this.tableWidth;
var tableHeight = this.tableHeight;
var bRectWidth = this.bRectWidth;
var matrixWidth = this.matrixWidth;
//canvas.clear();
// var color = this.getColor();
// var font = this.getFont();
var font_family = '微软雅黑';
var font_size = 8;
var title = this.title;
var row = [];
var columnLine = [];
var columnText = [];
var backgroundRect = canvas.rect(startX, startY, bRectWidth, bRectWidth);
//backgroundRect.attr({fill: "#939598", stroke: "none", "fill-opacity": 0.8});
backgroundRect.attr({fill: "#ffffff", stroke: "none", "fill-opacity": 0.8});
backgroundRect.toBack();
var sort;
if (this.hasSort) {
sort = this.sort;
}
var i, j, a, b, color, rect;
var rects = []; //for column change move rect
for (i = 0; i < tableHeight; i++) {
if (!this.hasSort){
a = i;
} else {
for (j = 0; j < sort.length; j++) {
if (sort[j] === i) {
a = j;
}
}
}
var rowRect = canvas.set();
canvas.path("M" + startX + " " + (startY + cellWidth * i) + "L" + (startX + matrixWidth + 10 + cellWidth) + " "
+ (startY + cellWidth * i)).attr({stroke: "#D1D1D1", "stroke-width": 1});
rowRect.push(canvas.text(-20, cellWidth / 2, title[i])
.attr({"fill": "#000000",
"fill-opacity": 0.7,
"font-family": "Verdana",
//"font-weight": "bold",
"font-size": 12}));
for (j = 0; j < tableWidth; j++) {
if (!this.hasSort) {
color = this.getColor(source[i][j]);
} else {
color = this.getColor(source[i][sort[j]]);
}
rect = canvas.rect(cellWidth * j, 0, cellWidth, cellWidth)
.attr({stroke: "none", fill: color, "fill-opacity": 0.8});
rowRect.push(rect);
rects.push(rect);
}
rowRect.transform("t" + startX + ", " + (startY + cellWidth * a));
row.push(rowRect);
}
canvas.path("M" + startX + " " + (startY + cellWidth * tableHeight) + "L" + (startX + matrixWidth + 10 + cellWidth) + " "
+ (startY + cellWidth * tableHeight)).attr({stroke: "#D1D1D1", "stroke-width": 1});
for (i = 0; i < tableWidth; i++) {
// var columnLine = canvas.set();
// var columnText = canvas.set();
if (!this.hasSort){
a = i;
} else {
for (j = 0; j < sort.length; j++) {
if (sort[j] === i) {
a = j;
}
}
}
columnLine.push(canvas.path("M0 0L0 " + matrixWidth + 10 + cellWidth)
.attr({stroke: "#D1D1D1", "stroke-width": 1})
.transform("t" + (startX + cellWidth * a) + ", " + startY));
columnText.push(canvas.text(cellWidth / 2, -20, title[i])
.attr({"fill": "#000000",
"fill-opacity": 0.7,
"font-family": "Verdana",
//"font-weight": "bold",
"font-size": 12})
.transform("t" + (startX + cellWidth * a) + ", " + startY + "r90"));
}
columnLine.push(canvas.path("M0 0L0 " + matrixWidth + 10 + cellWidth)
.attr({stroke: "#D1D1D1", "stroke-width": 1})
.transform("t" + (startX + cellWidth * tableWidth) + ", " + startY));
this.row = row;
this.columnText = columnText;
this.columnLine = columnLine;
this.rects = rects;
};
Matrix.prototype.getSort = function (source) {
var sumQueue = [];
var sort = [];
var rowData;
var rowLength;
var sum;
var means;
var matrixD = [];
var quareSum;
var rowquareSum = [];
var i, j, k;
for (i = 0 ; i < source.length ; i++) {
rowData = source[i];
rowLength = rowData.length;
sum = 0;
quareSum = 0;
for (j = 0 ; j < rowLength ; j++) {
sum = sum + rowData[j];
}
means = sum / rowLength;
for (j = 0 ; j < rowLength ; j++) {
rowData[j] = rowData[j] - means;
quareSum = quareSum + Math.pow(rowData[j], 2);
}
quareSum = Math.sqrt(quareSum);
rowquareSum.push(quareSum);
matrixD.push(rowData);
}
var rowI;
var rowJ;
var matrixR = [];
for (i = 0 ; i < source.length ; i++) {
matrixR[i] = [];
for (j = 0 ; j < source.length ; j++) {
matrixR[i][j] = 0;
}
}
for (i = 0 ; i < source.length ; i++) {
rowI = matrixD[i];
matrixR[i][i] = source[i][i];
for (j = i + 1 ; j < source.length ; j++) {
sum = 0;
rowJ = matrixD[j];
for (k = 0; k < rowLength; k++) {
sum = sum + rowI[k] * rowJ[k];
}
sum = sum / (rowquareSum[i] * rowquareSum[j]);
matrixR[i][j] = sum;
matrixR[j][i] = sum;
}
}
return matrixR;
};
Matrix.prototype.update = function () {
var i, j;
var source = [];
for(i = 0; i < this.source.length ; i++){
source[i] = this.source[i].concat();
}
var sort = [];
for (i = 0; i < source[0].length; i++) {
sort.push(i);
}
if (this.hasSort) {
this.sort = sort;
this.hasSort = false;
} else {
var getSort = this.getSort;
var i, j;
var pt;
var nowSort = [];
var iterations = 12;
for (i = 0; i < iterations; i++) {
source = getSort(source);
}
nowSort = source[0];
var a, b;
for (i = 1; i < sort.length; i++) {
a = sort[i];
for (j = i + 1; j < sort.length; j++) {
b = sort[j];
if (nowSort[a] < nowSort[b]) {
pt = sort[i];
sort[i] = sort[j];
sort[j] = pt;
}
}
}
sort = [0,7,5,2,8,3,1,9,6,14,15,4,13,10,16,11,12];
this.sort = sort;
this.hasSort = true;
}
if (!this.move) {
this.move = true;
var rects = this.rects;
var num;
var startX = this.startX;
var startY = this.startY;
var cellWidth = this.cellWidth;
var rowAnim;
var columnLineAnim;
var columnTextAnim;
var anim;
for (i = 0; i < sort.length; i++) {
num = sort[i];
// if (num != i) {
rowAnim = Raphael.animation({transform: ["t", startX, (startY + cellWidth * i)]}, 200, "<>");
this.row[num].animate(rowAnim.delay(100 * i));
// }
}
var that = this;
var moveEnd = function () {
that.move = false;
};
for (i = 0; i < sort.length; i++) {
num = sort[i];
// if (num != i) {
//columnLineAnim = Raphael.animation({transform: ["t", (startX + cellWidth * i), startY]}, 1000, "<>");
columnTextAnim = Raphael.animation({transform: ["t", (startX + cellWidth * i), startY, "r", 90]},
200, "<>");
//this.columnLine[num].animate(columnLineAnim.delay(500 * (i + sort.length + 1)));
this.columnText[num].animate(columnTextAnim.delay(100 * (i + sort.length + 1)));
for (j = 0; j < sort.length; j++) {
if (i === sort.length - 1 && j === sort.length - 1) {
anim = Raphael.animation({'x': cellWidth * i}, 200, "<>", moveEnd);
} else {
anim = Raphael.animation({'x': cellWidth * i}, 200, "<>");
}
rects[j * sort.length + num].animate(anim.delay(100 * (i + sort.length + 1)));
}
// }
}
}
};
Matrix.prototype.render = function (options) {
if (!this.move) {
this.canvas.clear();
this.setOptions(options);
this.layout();
this.generatePaths();
}
};
return Matrix;
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff