123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- /**
- * 力导向布局
- * @module echarts/layout/Force
- * @author pissang(http://github.com/pissang)
- */
- define(function(require) {
- var ForceLayoutWorker = require('./forceLayoutWorker');
- var vec2 = require('zrender/tool/vector');
- var requestAnimationFrame = window.requestAnimationFrame
- || window.msRequestAnimationFrame
- || window.mozRequestAnimationFrame
- || window.webkitRequestAnimationFrame
- || function (func) {setTimeout(func, 16);};
- var ArrayCtor = typeof(Float32Array) == 'undefined' ? Array : Float32Array;
- var workerUrl;
- // function getToken() {
- // return Math.round((allGetServerTime()).getTime() / 100) % 10000000;
- // }
- function createWorkerUrl() {
- if (
- typeof(Worker) !== 'undefined' &&
- typeof(Blob) !== 'undefined'
- ) {
- try {
- var blob = new Blob([ForceLayoutWorker.getWorkerCode()]);
- workerUrl = window.URL.createObjectURL(blob);
- }
- catch (e) {
- workerUrl = '';
- }
- }
- return workerUrl;
- }
- var ForceLayout = function(opts) {
- if (typeof(workerUrl) === 'undefined') {
- createWorkerUrl();
- }
- opts = opts || {};
- // 配置项
- this.width = opts.width || 500;
- this.height = opts.height || 500;
- this.center = opts.center || [this.width / 2, this.height / 2];
- this.ratioScaling = opts.ratioScaling || false;
- this.scaling = opts.scaling || 1;
- this.gravity = typeof(opts.gravity) !== 'undefined'
- ? opts.gravity : 1;
- this.large = opts.large || false;
- this.preventNodeOverlap = opts.preventNodeOverlap || false;
- this.preventNodeEdgeOverlap = opts.preventNodeEdgeOverlap || false;
- this.maxSpeedIncrease = opts.maxSpeedIncrease || 1;
- this.onupdate = opts.onupdate || function () {};
- this.temperature = opts.temperature || 1;
- this.coolDown = opts.coolDown || 0.99;
- this._layout = null;
- this._layoutWorker = null;
- var self = this;
- var _$onupdate = this._$onupdate;
- this._$onupdate = function(e) {
- _$onupdate.call(self, e);
- };
- };
- ForceLayout.prototype.updateConfig = function () {
- var width = this.width;
- var height = this.height;
- var size = Math.min(width, height);
- var config = {
- center: this.center,
- width: this.ratioScaling ? width : size,
- height: this.ratioScaling ? height : size,
- scaling: this.scaling || 1.0,
- gravity: this.gravity || 1.0,
- barnesHutOptimize: this.large,
- preventNodeOverlap: this.preventNodeOverlap,
- preventNodeEdgeOverlap: this.preventNodeEdgeOverlap,
-
- maxSpeedIncrease: this.maxSpeedIncrease
- };
- if (this._layoutWorker) {
- this._layoutWorker.postMessage({
- cmd: 'updateConfig',
- config: config
- });
- }
- else {
- for (var name in config) {
- this._layout[name] = config[name];
- }
- }
- };
- ForceLayout.prototype.init = function (graph, useWorker) {
- if (this._layoutWorker) {
- this._layoutWorker.terminate();
- this._layoutWorker = null;
- }
- if (workerUrl && useWorker) {
- try {
- if (!this._layoutWorker) {
- this._layoutWorker = new Worker(workerUrl);
- this._layoutWorker.onmessage = this._$onupdate;
- }
- this._layout = null;
- }
- catch (e) { // IE10-11 will throw security error when using blog url
- this._layoutWorker = null;
- if (!this._layout) {
- this._layout = new ForceLayoutWorker();
- }
- }
- }
- else {
- if (!this._layout) {
- this._layout = new ForceLayoutWorker();
- }
- }
- this.temperature = 1;
- this.graph = graph;
- // 节点数据
- var len = graph.nodes.length;
- var positionArr = new ArrayCtor(len * 2);
- var massArr = new ArrayCtor(len);
- var sizeArr = new ArrayCtor(len);
- for (var i = 0; i < len; i++) {
- var n = graph.nodes[i];
- positionArr[i * 2] = n.layout.position[0];
- positionArr[i * 2 + 1] = n.layout.position[1];
- massArr[i] = typeof(n.layout.mass) === 'undefined'
- ? 1 : n.layout.mass;
- sizeArr[i] = typeof(n.layout.size) === 'undefined'
- ? 1 : n.layout.size;
- n.layout.__index = i;
- }
- // 边数据
- len = graph.edges.length;
- var edgeArr = new ArrayCtor(len * 2);
- var edgeWeightArr = new ArrayCtor(len);
- for (var i = 0; i < len; i++) {
- var edge = graph.edges[i];
- edgeArr[i * 2] = edge.node1.layout.__index;
- edgeArr[i * 2 + 1] = edge.node2.layout.__index;
- edgeWeightArr[i] = edge.layout.weight || 1;
- }
- if (this._layoutWorker) {
- this._layoutWorker.postMessage({
- cmd: 'init',
- nodesPosition: positionArr,
- nodesMass: massArr,
- nodesSize: sizeArr,
- edges: edgeArr,
- edgesWeight: edgeWeightArr
- });
- }
- else {
- this._layout.initNodes(positionArr, massArr, sizeArr);
- this._layout.initEdges(edgeArr, edgeWeightArr);
- }
- this.updateConfig();
- };
- ForceLayout.prototype.step = function (steps) {
- var nodes = this.graph.nodes;
- if (this._layoutWorker) {
- // Sync back
- var positionArr = new ArrayCtor(nodes.length * 2);
- for (var i = 0; i < nodes.length; i++) {
- var n = nodes[i];
- positionArr[i * 2] = n.layout.position[0];
- positionArr[i * 2 + 1] = n.layout.position[1];
- }
- this._layoutWorker.postMessage(positionArr.buffer, [positionArr.buffer]);
- this._layoutWorker.postMessage({
- cmd: 'update',
- steps: steps,
- temperature: this.temperature,
- coolDown: this.coolDown
- });
- for (var i = 0; i < steps; i++) {
- this.temperature *= this.coolDown;
- }
- }
- else {
-
- requestAnimationFrame(this._$onupdate);
- for (var i = 0; i < nodes.length; i++) {
- var n = nodes[i];
- vec2.copy(this._layout.nodes[i].position, n.layout.position);
- }
- for (var i = 0; i < steps; i++) {
- this._layout.temperature = this.temperature;
- this._layout.update();
- this.temperature *= this.coolDown;
- }
- }
- };
- ForceLayout.prototype._$onupdate = function (e) {
- if (this._layoutWorker) {
- var positionArr = new Float32Array(e.data);
- for (var i = 0; i < this.graph.nodes.length; i++) {
- var n = this.graph.nodes[i];
- n.layout.position[0] = positionArr[i * 2];
- n.layout.position[1] = positionArr[i * 2 + 1];
- }
- this.onupdate && this.onupdate();
- }
- else if (this._layout) {
- for (var i = 0; i < this.graph.nodes.length; i++) {
- var n = this.graph.nodes[i];
- vec2.copy(n.layout.position, this._layout.nodes[i].position);
- }
- this.onupdate && this.onupdate();
- }
- };
- ForceLayout.prototype.dispose = function() {
- if (this._layoutWorker) {
- this._layoutWorker.terminate();
- }
- this._layoutWorker = null;
- this._layout = null;
- };
- return ForceLayout;
- });
|