提交 5c41f814 编写于 作者: K kener

force拖拽事件~

上级 342c1a26
/** /**
* echarts图表类:力导向图 * echarts图表类:力导向图
* Copyright 2013 Baidu Inc. All rights reserved. * Copyright 2013 Baidu Inc. All rights reserved.
* *
* @author pissang (shenyi01@baidu.com) * @author pissang (shenyi01@baidu.com)
* *
*/ */
define(function(require) { define(function(require) {
/** /**
* 构造函数 * 构造函数
* @param {Object} messageCenter echart消息中心 * @param {Object} messageCenter echart消息中心
* @param {ZRender} zr zrender实例 * @param {ZRender} zr zrender实例
* @param {Object} series 数据 * @param {Object} series 数据
* @param {Object} component 组件 * @param {Object} component 组件
*/ */
function Force(messageCenter, zr, option, component) { function Force(messageCenter, zr, option, component) {
// 基类装饰
var ComponentBase = require('../component/base'); var ComponentBase = require('../component/base');
ComponentBase.call(this, zr); ComponentBase.call(this, zr);
// 可计算特性装饰
var ecConfig = require('../config'); var CalculableBase = require('./calculableBase');
var ecData = require('../util/ecData'); CalculableBase.call(this, zr, option);
var zrColor = require('zrender/tool/color'); var ecConfig = require('../config');
var zrUtil = require('zrender/tool/util'); var ecData = require('../util/ecData');
var vec2 = require('zrender/tool/vector');
var zrConfig = require('zrender/config');
var self = this; var zrEvent = require('zrender/tool/event');
self.type = ecConfig.CHART_TYPE_FORCE; var zrColor = require('zrender/tool/color');
var zrUtil = require('zrender/tool/util');
var series; var vec2 = require('zrender/tool/vector');
var nodeShapes = []; var self = this;
var linkShapes = []; self.type = ecConfig.CHART_TYPE_FORCE;
// 节点分类 var series;
var categories = [];
// 默认节点样式 var nodeShapes = [];
var nodeStyle; var linkShapes = [];
// 默认边样式
var linkStyle; // 节点分类
// nodes和links的原始数据 var categories = [];
var nodesRawData = []; // 默认节点样式
var linksRawData = []; var nodeStyle;
// 默认边样式
// nodes和links的权重, 用来计算引力和斥力 var linkStyle;
var nodeWeights = []; // nodes和links的原始数据
var linkWeights = []; var nodesRawData = [];
var linksRawData = [];
// 节点的受力
var nodeForces = []; // nodes和links的权重, 用来计算引力和斥力
// 节点的加速度 var nodeWeights = [];
var nodeAccelerations = []; var linkWeights = [];
// 节点的位置
var nodePositions = []; // 节点的受力
var nodePrePositions = []; var nodeForces = [];
// 节点的质量 // 节点的加速度
var nodeMasses = []; var nodeAccelerations = [];
// 节点的位置
var temperature; var nodePositions = [];
var k; var nodePrePositions = [];
var density; // 节点的质量
var nodeMasses = [];
var stepTime = 1/20;
var temperature;
var viewportWidth; var k;
var viewportHeight; var density;
var centroid = [];
var stepTime = 1/20;
function _buildShape() {
var viewportWidth;
temperature = 1.0; var viewportHeight;
viewportWidth = zr.getWidth(); var centroid = [];
viewportHeight = zr.getHeight();
centroid = [viewportWidth/2, viewportHeight/2] function _buildShape() {
for (var i = 0, l = series.length; i < l; i++) { temperature = 1.0;
var serie = series[i]; viewportWidth = zr.getWidth();
if (serie.type === ecConfig.CHART_TYPE_FORCE) { viewportHeight = zr.getHeight();
centroid = [viewportWidth/2, viewportHeight/2]
series[i] = self.reformOption(series[i]);
for (var i = 0, l = series.length; i < l; i++) {
var minRadius = self.deepQuery([serie], 'minRadius'); var serie = series[i];
var maxRadius = self.deepQuery([serie], 'maxRadius'); if (serie.type === ecConfig.CHART_TYPE_FORCE) {
density = self.deepQuery([serie], 'density'); series[i] = self.reformOption(series[i]);
categories = self.deepQuery([serie], 'categories'); var minRadius = self.deepQuery([serie], 'minRadius');
var maxRadius = self.deepQuery([serie], 'maxRadius');
linkStyle = self.deepQuery([serie], 'linkStyle');
nodeStyle = self.deepQuery([serie], 'nodeStyle'); density = self.deepQuery([serie], 'density');
nodesRawData = self.deepQuery([serie], 'nodes'); categories = self.deepQuery([serie], 'categories');
linksRawData = self.deepQuery([serie], 'links');
linkStyle = self.deepQuery([serie], 'linkStyle');
var area = viewportWidth * viewportHeight; nodeStyle = self.deepQuery([serie], 'nodeStyle');
// Formula in 'Graph Drawing by Force-directed Placement'
k = 0.5 * Math.sqrt( area / nodesRawData.length ); nodesRawData = self.deepQuery([serie], 'nodes');
linksRawData = self.deepQuery([serie], 'links');
_buildLinkShapes(nodesRawData, linksRawData);
_buildNodeShapes(nodesRawData, minRadius, maxRadius); var area = viewportWidth * viewportHeight;
} // Formula in 'Graph Drawing by Force-directed Placement'
} k = 0.5 * Math.sqrt( area / nodesRawData.length );
}
_buildLinkShapes(nodesRawData, linksRawData);
function _buildNodeShapes(nodes, minRadius, maxRadius) { _buildNodeShapes(nodesRawData, minRadius, maxRadius);
// 将值映射到minRadius-maxRadius的范围上 }
var radius = []; }
var l = nodes.length; }
for (var i = 0; i < l; i++) {
var node = nodes[i]; function _buildNodeShapes(nodes, minRadius, maxRadius) {
radius.push(node.value); // 将值映射到minRadius-maxRadius的范围上
} var radius = [];
_map(radius, radius, minRadius, maxRadius); var l = nodes.length;
_normalize(nodeWeights, radius); for (var i = 0; i < l; i++) {
var node = nodes[i];
radius.push(node.value);
for (var i = 0; i < l; i++) { }
var node = nodes[i]; _map(radius, radius, minRadius, maxRadius);
var x, y; _normalize(nodeWeights, radius);
var r = radius[i];
var random = _randomInSquare(viewportWidth/2, for (var i = 0; i < l; i++) {
viewportHeight/2, var node = nodes[i];
300); var x, y;
x = typeof(node.initial) === "undefined" var r = radius[i];
? random.x
: node.initial.x; var random = _randomInSquare(viewportWidth/2,
y = typeof(node.initial) === "undefined" viewportHeight/2,
? random.y 300);
: node.initial.y; x = typeof(node.initial) === "undefined"
// 初始化位置 ? random.x
nodePositions[i] = [x, y]; : node.initial.x;
nodePrePositions[i] = [x, y]; y = typeof(node.initial) === "undefined"
// 初始化受力 ? random.y
nodeForces[i] = [0, 0]; : node.initial.y;
// 初始化加速度 // 初始化位置
nodeAccelerations[i] = [0, 0]; nodePositions[i] = [x, y];
// 初始化质量 nodePrePositions[i] = [x, y];
nodeMasses[i] = r * r * density; // 初始化受力
nodeForces[i] = [0, 0];
var shape = { // 初始化加速度
id : zr.newShapeId(self.type), nodeAccelerations[i] = [0, 0];
shape : 'circle', // 初始化质量
style : { nodeMasses[i] = r * r * density;
r : r,
x : x, var shape = {
y : y id : zr.newShapeId(self.type),
} shape : 'circle',
}; style : {
r : r,
// 优先级 node.style > category.style > defaultStyle x : x,
zrUtil.merge(shape.style, nodeStyle); y : y
if (typeof(node.category) !== 'undefined') { }
var category = categories[node.category]; };
if (category){
var style = category.style; // 优先级 node.style > category.style > defaultStyle
if(style){ zrUtil.merge(shape.style, nodeStyle);
zrUtil.merge(shape.style, style, { if (typeof(node.category) !== 'undefined') {
overwrite : true var category = categories[node.category];
}); if (category){
} var style = category.style;
} if(style){
} zrUtil.merge(shape.style, style, {
if (typeof(node.style) !== 'undefined') { overwrite : true
zrUtil.merge(shape.style, node.style, { });
overwrite : true }
}); }
} }
if (typeof(node.style) !== 'undefined') {
nodeShapes.push(shape); zrUtil.merge(shape.style, node.style, {
self.shapeList.push(shape); overwrite : true
});
zr.addShape(shape); }
}
// 拖拽特性
// _normalize(nodeMasses, nodeMasses); self.setCalculable(shape);
} shape.ondragstart = self.shapeHandler.ondragstart;
shape.draggable = true;
function _buildLinkShapes(nodes, links) {
var l = links.length; nodeShapes.push(shape);
self.shapeList.push(shape);
for (var i = 0; i < l; i++) {
var link = links[i]; zr.addShape(shape);
var source = nodes[link.source]; }
var target = nodes[link.target];
var weight = link.weight || 1; // _normalize(nodeMasses, nodeMasses);
linkWeights.push(weight); }
var shape = { function _buildLinkShapes(nodes, links) {
id : zr.newShapeId(self.type), var l = links.length;
shape : 'line',
style : { for (var i = 0; i < l; i++) {
xStart : 0, var link = links[i];
yStart : 0, var source = nodes[link.source];
xEnd : 0, var target = nodes[link.target];
yEnd : 0 var weight = link.weight || 1;
} linkWeights.push(weight);
};
var shape = {
zrUtil.merge(shape.style, linkStyle); id : zr.newShapeId(self.type),
if (typeof(link.style) !== 'undefined') { shape : 'line',
zrUtil.merge(shape.style, link.style, { style : {
overwrite : true xStart : 0,
}) yStart : 0,
} xEnd : 0,
yEnd : 0
linkShapes.push(shape); }
self.shapeList.push(shape); };
zr.addShape(shape); zrUtil.merge(shape.style, linkStyle);
} if (typeof(link.style) !== 'undefined') {
_normalize(linkWeights, linkWeights); zrUtil.merge(shape.style, link.style, {
} overwrite : true
})
function _updateLinkShapes(){ }
for (var i = 0, l = linksRawData.length; i < l; i++) {
var link = linksRawData[i]; linkShapes.push(shape);
var linkShape = linkShapes[i]; self.shapeList.push(shape);
var sourceShape = nodeShapes[link.source];
var targetShape = nodeShapes[link.target]; zr.addShape(shape);
}
linkShape.style.xStart = sourceShape.style.x; _normalize(linkWeights, linkWeights);
linkShape.style.yStart = sourceShape.style.y; }
linkShape.style.xEnd = targetShape.style.x;
linkShape.style.yEnd = targetShape.style.y; function _updateLinkShapes(){
} for (var i = 0, l = linksRawData.length; i < l; i++) {
} var link = linksRawData[i];
var linkShape = linkShapes[i];
function _update(stepTime) { var sourceShape = nodeShapes[link.source];
var len = nodePositions.length; var targetShape = nodeShapes[link.target];
var v12 = [];
// 计算节点之间斥力 linkShape.style.xStart = sourceShape.style.x;
var k2 = k*k; linkShape.style.yStart = sourceShape.style.y;
// Reset force linkShape.style.xEnd = targetShape.style.x;
for (var i = 0; i < len; i++) { linkShape.style.yEnd = targetShape.style.y;
nodeForces[i][0] = 0; }
nodeForces[i][1] = 0; }
}
for (var i = 0; i < len; i++) { function _update(stepTime) {
for (var j = i+1; j < len; j++){ var len = nodePositions.length;
var w1 = nodeWeights[i]; var v12 = [];
var w2 = nodeWeights[j]; // 计算节点之间斥力
var p1 = nodePositions[i]; var k2 = k*k;
var p2 = nodePositions[j]; // Reset force
for (var i = 0; i < len; i++) {
// 节点1到2的向量 nodeForces[i][0] = 0;
vec2.sub(v12, p2, p1); nodeForces[i][1] = 0;
var d = vec2.length(v12); }
// 距离大于500忽略斥力 for (var i = 0; i < len; i++) {
if(d > 500){ for (var j = i+1; j < len; j++){
continue; var w1 = nodeWeights[i];
} var w2 = nodeWeights[j];
vec2.scale(v12, v12, 1/d); var p1 = nodePositions[i];
var forceFactor = 1 * (w1 + w2) * k2 / d; var p2 = nodePositions[j];
vec2.scale(v12, v12, forceFactor); // 节点1到2的向量
//节点1受到的力 vec2.sub(v12, p2, p1);
vec2.sub(nodeForces[i], nodeForces[i], v12); var d = vec2.length(v12);
//节点2受到的力 // 距离大于500忽略斥力
vec2.add(nodeForces[j], nodeForces[j], v12); if(d > 500){
} continue;
} }
// 计算节点之间引力 vec2.scale(v12, v12, 1/d);
for (var i = 0, l = linksRawData.length; i < l; i++) { var forceFactor = 1 * (w1 + w2) * k2 / d;
var link = linksRawData[i];
var w = linkWeights[i]; vec2.scale(v12, v12, forceFactor);
var s = link.source; //节点1受到的力
var t = link.target; vec2.sub(nodeForces[i], nodeForces[i], v12);
var p1 = nodePositions[s]; //节点2受到的力
var p2 = nodePositions[t]; vec2.add(nodeForces[j], nodeForces[j], v12);
}
vec2.sub(v12, p2, p1); }
var d2 = vec2.lengthSquare(v12); // 计算节点之间引力
vec2.normalize(v12, v12); for (var i = 0, l = linksRawData.length; i < l; i++) {
var link = linksRawData[i];
var forceFactor = w * d2 / k; var w = linkWeights[i];
// 节点1受到的力 var s = link.source;
vec2.scale(v12, v12, forceFactor); var t = link.target;
vec2.add(nodeForces[s], nodeForces[s], v12); var p1 = nodePositions[s];
//节点2受到的力 var p2 = nodePositions[t];
vec2.sub(nodeForces[t], nodeForces[t], v12);
} vec2.sub(v12, p2, p1);
// 到质心的向心力 var d2 = vec2.lengthSquare(v12);
for (var i = 0, l = nodesRawData.length; i < l; i++){ vec2.normalize(v12, v12);
var p = nodePositions[i];
vec2.sub(v12, centroid, p); var forceFactor = w * d2 / k;
var d2 = vec2.lengthSquare(v12); // 节点1受到的力
vec2.normalize(v12, v12); vec2.scale(v12, v12, forceFactor);
// 100是可调参数 vec2.add(nodeForces[s], nodeForces[s], v12);
var forceFactor = d2 / 100; //节点2受到的力
vec2.scale(v12, v12, forceFactor); vec2.sub(nodeForces[t], nodeForces[t], v12);
vec2.add(nodeForces[i], nodeForces[i], v12); }
// 到质心的向心力
} for (var i = 0, l = nodesRawData.length; i < l; i++){
// 计算加速度 var p = nodePositions[i];
for (var i = 0, l = nodeAccelerations.length; i < l; i++) { vec2.sub(v12, centroid, p);
vec2.scale(nodeAccelerations[i], nodeForces[i], 1 / nodeMasses[i]); var d2 = vec2.lengthSquare(v12);
} vec2.normalize(v12, v12);
var velocity = []; // 100是可调参数
var tmp = []; var forceFactor = d2 / 100;
// 计算位置(verlet积分) vec2.scale(v12, v12, forceFactor);
for (var i = 0, l = nodePositions.length; i < l; i++) { vec2.add(nodeForces[i], nodeForces[i], v12);
var p = nodePositions[i];
var p_ = nodePrePositions[i]; }
vec2.sub(velocity, p, p_); // 计算加速度
p_[0] = p[0]; for (var i = 0, l = nodeAccelerations.length; i < l; i++) {
p_[1] = p[1]; vec2.scale(nodeAccelerations[i], nodeForces[i], 1 / nodeMasses[i]);
vec2.add(velocity, velocity, vec2.scale(tmp, nodeAccelerations[i], stepTime)); }
// Damping var velocity = [];
vec2.scale(velocity, velocity, temperature); var tmp = [];
vec2.add(p, p, velocity); // 计算位置(verlet积分)
nodeShapes[i].style.x = p[0]; for (var i = 0, l = nodePositions.length; i < l; i++) {
nodeShapes[i].style.y = p[1]; var p = nodePositions[i];
} var p_ = nodePrePositions[i];
} vec2.sub(velocity, p, p_);
p_[0] = p[0];
function _step(){ p_[1] = p[1];
if (temperature < 0.005) { vec2.add(velocity, velocity, vec2.scale(tmp, nodeAccelerations[i], stepTime));
return; // Damping
} vec2.scale(velocity, velocity, temperature);
vec2.add(p, p, velocity);
_update(stepTime); nodeShapes[i].style.x = p[0];
_updateLinkShapes(); nodeShapes[i].style.y = p[1];
}
for (var i = 0; i < nodeShapes.length; i++) { }
var shape = nodeShapes[i];
zr.modShape(shape.id, shape); function _step(){
} if (temperature < 0.005) {
for (var i = 0; i < linkShapes.length; i++) { return;
var shape = linkShapes[i]; }
zr.modShape(shape.id, shape);
} _update(stepTime);
_updateLinkShapes();
zr.refresh();
for (var i = 0; i < nodeShapes.length; i++) {
// Cool Down var shape = nodeShapes[i];
temperature *= 0.999; zr.modShape(shape.id, shape);
} }
for (var i = 0; i < linkShapes.length; i++) {
function init(newOption, newComponent) { var shape = linkShapes[i];
option = newOption; zr.modShape(shape.id, shape);
component = newComponent; }
series = option.series; zr.refresh();
self.clear(); // Cool Down
_buildShape(); temperature *= 0.999;
}
setInterval(function(){
_step(); function init(newOption, newComponent) {
}, stepTime); option = newOption;
} component = newComponent;
function refresh() { series = option.series;
self.clear();
_buildShape(); self.clear();
} _buildShape();
setInterval(function(){
self.init = init; _step();
self.refresh = refresh; }, stepTime);
}
init(option, component);
} function refresh() {
self.clear();
_buildShape();
function _map(output, input, mappedMin, mappedMax) { }
var min = input[0];
var max = input[0]; /**
var l = input.length; * 输出动态视觉引导线
for (var i = 1; i < l; i++) { */
var val = input[i]; self.shapeHandler.ondragstart = function() {
if (val < min) { self.isDragstart = true;
min = val; }
}
if (val > max) { /**
max = val; * 拖拽开始
} */
} function ondragstart(param, status) {
var range = max - min; if (!self.isDragstart || !param.target) {
var mappedRange = mappedMax - mappedMin; // 没有在当前实例上发生拖拽行为则直接返回
for (var i = 0; i < l; i++) { return;
if (range === 0) { }
output[i] = mappedMin; console.log('dragstart', param.target);
} else { // 处理完拖拽事件后复位
var val = input[i]; self.isDragstart = false;
var percent = (val - min) / range;
output[i] = mappedRange * percent + mappedMin; // 我想你需要这个
} zr.on(zrConfig.EVENT.MOUSEMOVE, _onmousemove);
} }
}
/**
function _normalize(output, input) { * 数据项被拖拽出去,重载基类方法
var l = input.length; */
var max = input[0]; function ondragend(param, status) {
for (var i = 1; i < l; i++) { if (!self.isDragend || !param.target) {
if (input[i] > max) { // 没有在当前实例上发生拖拽行为则直接返回
max = input[i]; return;
} }
}
for (var i = 0; i < l; i++) { console.log('dragend', param.target);
output[i] = input[i] / max;
} // 别status = {}赋值啊!!
} status.dragIn = true;
//你自己refresh的话把他设为false,设true就会重新掉refresh接口
function _randomInCircle(x, y, radius) { status.needRefresh = false;
var theta = Math.random() * Math.PI * 2;
var r = radius * Math.random(); // 处理完拖拽事件后复位
return { self.isDragend = false;
x : Math.cos(theta) * r + x,
y : Math.sin(theta) * r + y zr.un(zrConfig.EVENT.MOUSEMOVE, _onmousemove);
} }
}
// 拖拽中位移信息
function _randomInSquare(x, y, size) { function _onmousemove(param) {
return { console.log(
x : (Math.random() - 0.5) * size + x, param,
y : (Math.random() - 0.5) * size + y zrEvent.getX(param.event),
} zrEvent.getY(param.event)
} )
}
// 图表注册
require('../chart').define('force', Force); self.init = init;
self.refresh = refresh;
return Force; self.ondragstart = ondragstart;
self.ondragend = ondragend;
init(option, component);
}
function _map(output, input, mappedMin, mappedMax) {
var min = input[0];
var max = input[0];
var l = input.length;
for (var i = 1; i < l; i++) {
var val = input[i];
if (val < min) {
min = val;
}
if (val > max) {
max = val;
}
}
var range = max - min;
var mappedRange = mappedMax - mappedMin;
for (var i = 0; i < l; i++) {
if (range === 0) {
output[i] = mappedMin;
} else {
var val = input[i];
var percent = (val - min) / range;
output[i] = mappedRange * percent + mappedMin;
}
}
}
function _normalize(output, input) {
var l = input.length;
var max = input[0];
for (var i = 1; i < l; i++) {
if (input[i] > max) {
max = input[i];
}
}
for (var i = 0; i < l; i++) {
output[i] = input[i] / max;
}
}
function _randomInCircle(x, y, radius) {
var theta = Math.random() * Math.PI * 2;
var r = radius * Math.random();
return {
x : Math.cos(theta) * r + x,
y : Math.sin(theta) * r + y
}
}
function _randomInSquare(x, y, size) {
return {
x : (Math.random() - 0.5) * size + x,
y : (Math.random() - 0.5) * size + y
}
}
// 图表注册
require('../chart').define('force', Force);
return Force;
}) })
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册