chartx
Version:
Data Visualization Chart Library
1,429 lines (1,398 loc) • 67.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _canvax = _interopRequireDefault(require("canvax"));
var _index = _interopRequireDefault(require("../index"));
var _global = _interopRequireDefault(require("../../../global"));
var _dataFrame = _interopRequireDefault(require("../../../core/dataFrame"));
var _tools = require("../../../utils/tools");
var _data2 = require("./data");
var _zoom = _interopRequireDefault(require("../../../utils/zoom"));
var _dagre = _interopRequireDefault(require("dagre"));
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } //import Dagre from "../../../layout/dagre/index"
var _ = _canvax.default._,
event = _canvax.default.event;
var Rect = _canvax.default.Shapes.Rect;
var Diamond = _canvax.default.Shapes.Diamond;
var Path = _canvax.default.Shapes.Path;
var BrokenLine = _canvax.default.Shapes.BrokenLine;
var Circle = _canvax.default.Shapes.Circle;
var Arrow = _canvax.default.Shapes.Arrow;
/**
* 关系图中 包括了 配置,数据,和布局数据,
* 默认用配置和数据可以完成绘图, 但是如果有布局数据,就绘图玩额外调用一次绘图,把布局数据传入修正布局效果
*/
var Relation = /*#__PURE__*/function (_GraphsBase) {
function Relation(opt, app) {
var _this;
(0, _classCallCheck2.default)(this, Relation);
_this = _callSuper(this, Relation, [opt, app]);
_this.type = "relation";
_.extend(true, _this, (0, _tools.getDefaultProps)(Relation.defaultProps()), opt);
if (_this.layout === 'dagre') {
var dagreOpts = {
graph: {
rankdir: 'TB',
nodesep: 10,
ranksep: 10,
edgesep: 10,
acyclicer: "greedy"
},
node: {},
edge: {
labelpos: 'c'
//labeloffset: 0
}
};
_.extend(true, dagreOpts, _this.layoutOpts);
_.extend(true, _this.layoutOpts, dagreOpts);
if (!_this.rankdir) {
_this.rankdir = _this.layoutOpts.graph.rankdir;
} else {
//如果有设置this.randdir 则已经 ta 为准
_this.layoutOpts.graph.rankdir = _this.rankdir;
}
;
}
;
_this.domContainer = app.canvax.domView;
_this.induce = null;
_this.init();
return _this;
}
(0, _inherits2.default)(Relation, _GraphsBase);
return (0, _createClass2.default)(Relation, [{
key: "init",
value: function init() {
this._initInduce();
this.nodesSp = new _canvax.default.Display.Sprite({
id: "nodesSp"
});
this.nodesContentSp = new _canvax.default.Display.Sprite({
id: "nodesContentSp"
});
this.edgesSp = new _canvax.default.Display.Sprite({
id: "edgesSp"
});
this.arrowsSp = new _canvax.default.Display.Sprite({
id: "arrowsSp"
});
this.labelsSp = new _canvax.default.Display.Sprite({
id: "labelsSp"
});
this.graphsSp = new _canvax.default.Display.Sprite({
id: "graphsSp"
});
//这个view和induce是一一对应的,在induce上面执行拖拽和滚轮缩放,操作的目标元素就是graphsView
this.graphsView = new _canvax.default.Display.Sprite({
id: "graphsView"
});
this.graphsSp.addChild(this.edgesSp);
this.graphsSp.addChild(this.nodesSp);
this.graphsSp.addChild(this.nodesContentSp);
this.graphsSp.addChild(this.arrowsSp);
this.graphsSp.addChild(this.labelsSp);
this.graphsView.addChild(this.graphsSp);
this.sprite.addChild(this.graphsView);
}
}, {
key: "_initInduce",
value: function _initInduce() {
var me = this;
this.induce = new Rect({
id: "induce",
context: {
width: 0,
height: 0,
fillStyle: "#000000",
globalAlpha: 0
}
});
this.sprite.addChild(this.induce);
var _mosedownIng = false;
var _preCursor = me.app.canvax.domView ? "default" : me.app.canvax.domView.style.cursor;
//滚轮缩放相关
var _wheelHandleTimeLen = 32; //16*2
var _wheelHandleTimeer = null;
var _deltaY = 0;
this.zoom = new _zoom.default({
scale: this.status.transform.scale,
scaleMin: this.status.transform.scaleMin,
scaleMax: this.status.transform.scaleMax
});
this.induce.on(event.types.get(), function (e) {
if (me.status.transform.enabled) {
e.preventDefault();
var point = e.target.localToGlobal(e.point, me.sprite);
//鼠标拖拽移动
if (e.type == "mousedown") {
me.induce.toFront();
_mosedownIng = true;
me.app.canvax.domView && (me.app.canvax.domView.style.cursor = "move");
me.zoom.mouseMoveTo(point);
}
;
if (e.type == "mouseup" || e.type == "mouseout") {
me.induce.toBack();
_mosedownIng = false;
me.app.canvax.domView && (me.app.canvax.domView.style.cursor = _preCursor);
}
;
if (e.type == "mousemove") {
if (_mosedownIng) {
var _me$zoom$move = me.zoom.move(point),
x = _me$zoom$move.x,
y = _me$zoom$move.y;
me.graphsView.context.x = parseInt(x);
me.graphsView.context.y = parseInt(y);
}
}
;
//滚轮缩放
if (e.type == "wheel") {
if (Math.abs(e.deltaY) > Math.abs(_deltaY)) {
_deltaY = e.deltaY;
}
;
if (!_wheelHandleTimeer) {
_wheelHandleTimeer = setTimeout(function () {
if (me.status.transform.wheelAction == 'offset') {
//移动的话用offset,偏移多少像素
var _me$zoom$offset = me.zoom.offset({
x: -e.deltaX,
y: -e.deltaY
}),
_x = _me$zoom$offset.x,
_y = _me$zoom$offset.y; //me.zoom.move( {x:zx, y:zy} );
me.graphsView.context.x = _x;
me.graphsView.context.y = _y;
}
if (me.status.transform.wheelAction == 'scale') {
// 缩放
var _me$zoom$wheel = me.zoom.wheel(e, point),
scale = _me$zoom$wheel.scale,
_x2 = _me$zoom$wheel.x,
_y2 = _me$zoom$wheel.y;
me.graphsView.context.x = _x2;
me.graphsView.context.y = _y2;
me.graphsView.context.scaleX = scale;
me.graphsView.context.scaleY = scale;
me.status.transform.scale = scale;
}
_wheelHandleTimeer = null;
_deltaY = 0;
}, _wheelHandleTimeLen);
}
;
}
;
}
;
});
}
}, {
key: "_initZoom",
value: function _initZoom() {
this.zoom = new _zoom.default({
scale: this.status.transform.scale,
scaleMin: this.status.transform.statusMin,
scaleMax: this.status.transform.statusMax
});
var me = this;
var _mosedownIng = false;
var _preCursor = me.app.canvax.domView ? me.app.canvax.domView.style.cursor : 'default';
//滚轮缩放相关
var _wheelHandleTimeLen = 32; //16 * 2
var _wheelHandleTimeer = null;
var _deltaY = 0;
this.sprite.on(event.types.get(), function (e) {
if (me.status.transform.enabled) {
e.preventDefault();
var point = e.target.localToGlobal(e.point, me.sprite);
if (e.type == "mousedown") {
_mosedownIng = true;
me.app.canvax.domView && (me.app.canvax.domView.style.cursor = "move");
me.zoom.mouseMoveTo(point);
}
;
if (e.type == "mouseup" || e.type == "mouseout") {
_mosedownIng = false;
me.app.canvax.domView && (me.app.canvax.domView.style.cursor = _preCursor);
}
;
if (e.type == "mousemove") {
if (_mosedownIng) {
var _me$zoom$move2 = me.zoom.move(point),
x = _me$zoom$move2.x,
y = _me$zoom$move2.y;
me.mapGraphs.context.x = x;
me.mapGraphs.context.y = y;
}
}
;
if (e.type == "wheel") {
if (Math.abs(e.deltaY) > Math.abs(_deltaY)) {
_deltaY = e.deltaY;
}
;
if (!_wheelHandleTimeer) {
_wheelHandleTimeer = setTimeout(function () {
var _me$zoom$wheel2 = me.zoom.wheel(e, point),
scale = _me$zoom$wheel2.scale,
x = _me$zoom$wheel2.x,
y = _me$zoom$wheel2.y;
me.mapGraphs.context.x = x;
me.mapGraphs.context.y = y;
me.mapGraphs.context.scaleX = scale;
me.mapGraphs.context.scaleY = scale;
me.status.transform.scale = scale;
_wheelHandleTimeer = null;
_deltaY = 0;
}, _wheelHandleTimeLen);
}
;
}
;
}
;
});
}
}, {
key: "draw",
value: function draw(opt) {
var _this2 = this;
!opt && (opt = {});
_.extend(true, this, opt);
this._initData(opt.data).then(function (data) {
_this2.data = data;
_this2._layoutData();
_this2.widget();
_this2.induce.context.width = _this2.width;
_this2.induce.context.height = _this2.height;
_this2.sprite.context.x = parseInt(_this2.origin.x);
_this2.sprite.context.y = parseInt(_this2.origin.y);
var _offsetLeft = (_this2.width - _this2.data.size.width) / 2;
if (_offsetLeft < 0) {
_offsetLeft = 0;
}
;
var _offsetTop = (_this2.height - _this2.data.size.height) / 2;
if (_offsetTop < 0) {
_offsetTop = 0;
}
;
_this2.graphsSp.context.x = parseInt(_offsetLeft);
_this2.graphsSp.context.y = parseInt(_offsetTop);
_this2.fire("complete");
});
}
//如果dataTrigger.origin 有传入, 则已经这个origin为参考点做重新布局
//TODO, 如果这个图的options中有配置 一个 符合 关系图的数据{nodes, edges, size}
//那么这个时候的resetData还不能满足,因为resetData的第一个个参数是dataFrame, 而options.data其实已经算是配置了,
//后面遇到这个情况再调整吧
}, {
key: "resetData",
value: function resetData(dataFrame, dataTrigger) {
var _this3 = this;
this._resetData(dataFrame, dataTrigger).then(function () {
_this3.fire("complete");
});
}
}, {
key: "_resetData",
value: function _resetData(data, dataTrigger) {
var _this4 = this;
var me = this;
this._preData = this.data;
return new Promise(function (resolve) {
_this4._initData(data).then(function (_data) {
_this4.data = _data;
_this4._layoutData();
_.each(_this4._preData.nodes, function (preNode) {
var nodeData = _.find(me.data.nodes, function (node) {
return preNode.key == node.key;
});
if (!nodeData) {
me._destroy(preNode);
} else {
//如果找到了,要从前面
nodeData.focused = preNode.focused;
nodeData.selected = preNode.selected;
}
});
_.each(_this4._preData.edges, function (preEdge) {
if (!_.find(me.data.edges, function (edge) {
return preEdge.key.join('_') == edge.key.join('_');
})) {
me._destroy(preEdge);
}
});
_this4.widget();
if (dataTrigger) {
var origin = dataTrigger.origin || (dataTrigger.params || {}).origin; //兼容老的配置里面没有params,直接传origin的情况
//钉住某个node为参考点(不移动)
if (origin != undefined) {
var preOriginNode = _.find(_this4._preData.nodes, function (node) {
return node.key == origin;
});
var originNode = _.find(_this4.data.nodes, function (node) {
return node.key == origin;
});
if (preOriginNode && originNode) {
var offsetPos = {
x: parseInt(preOriginNode.x) - parseInt(originNode.x),
y: parseInt(preOriginNode.y) - parseInt(originNode.y)
};
var _this4$zoom$offset = _this4.zoom.offset(offsetPos),
x = _this4$zoom$offset.x,
y = _this4$zoom$offset.y;
me.graphsView.context.x = parseInt(x);
me.graphsView.context.y = parseInt(y);
}
;
}
;
}
;
resolve();
});
});
}
}, {
key: "_destroy",
value: function _destroy(item) {
item.shapeElement && item.shapeElement.destroy();
if (item.contentElement.destroy) {
item.contentElement.destroy();
} else {
//否则就可定是个dom
this.domContainer.removeChild(item.contentElement);
}
;
//下面的几个是销毁edge上面的元素
item.pathElement && item.pathElement.destroy();
item.labelElement && item.labelElement.destroy();
item.arrowElement && item.arrowElement.destroy();
item.edgeIconElement && item.edgeIconElement.destroy();
item.edgeIconBack && item.edgeIconBack.destroy();
}
}, {
key: "_getDefNode",
value: function _getDefNode() {
var node = {
type: "relation",
iNode: 0,
rowData: null,
key: "",
content: '',
_contentInited: false,
ctype: 'canvas',
//下面三个属性在_setElementAndSize中设置
contentElement: null,
//外面传的layout数据可能没有element,widget的时候要检测下
width: null,
height: null,
//这个在layout的时候设置
x: null,
y: null,
shapeType: null,
//如果是edge,要填写这两节点
source: null,
target: null,
focused: false,
selected: false
};
return node;
}
//$data如果用户设置了符合data的数据格式数据{nodes, edges, size},那就直接返回
}, {
key: "_initData",
value: function _initData($data) {
var _this5 = this;
return new Promise(function (resolve) {
if ($data && $data.nodes && $data.edges) {
resolve($data);
return;
}
;
var data = {
//{ type,key,content,ctype,width,height,x,y }
nodes: [],
//{ type,key[],content,ctype,width,height,x,y }
edges: [],
size: {
width: 0,
height: 0
}
};
var originData = _this5.app._data;
if ((0, _data2.checkDataIsJson)(originData, _this5.field, _this5.childrenField)) {
_this5.jsonData = (0, _data2.jsonToArrayForRelation)(originData, _this5, _this5.childrenField);
_this5.dataFrame = _this5.app.dataFrame = (0, _dataFrame.default)(_this5.jsonData, _this5);
} else {
if (_this5.layout == "tree") {
//源数据就是图表标准数据,只需要转换成json的Children格式
//app.dataFrame.jsonOrg ==> [{name: key:} ...] 不是children的树结构
_this5.jsonData = (0, _data2.arrayToTreeJsonForRelation)(JSON.parse(JSON.stringify(_this5.app.dataFrame.jsonOrg)), _this5);
}
;
}
;
for (var i = 0; i < _this5.dataFrame.length; i++) {
var rowData = _this5.dataFrame.getRowDataAt(i);
var fields = _.flatten([(rowData[_this5.field] + "").split(",")]);
var content = _this5._getContent(rowData);
var node = _this5._getDefNode();
Object.assign(node, {
iNode: i,
rowData: rowData,
key: fields.length == 1 ? fields[0] : fields,
content: content,
ctype: _this5._checkHtml(content) ? 'html' : 'canvas'
});
if (fields.length == 1) {
//isNode
node.shapeType = _this5.getProp(_this5.node.shapeType, node);
Object.assign(node, _this5.layoutOpts.node);
data.nodes.push(node);
} else {
// isEdge
node.shapeType = _this5.getProp(_this5.line.shapeType, node);
Object.assign(node, _this5.layoutOpts.edge);
data.edges.push(node);
}
;
}
;
_this5._initAllDataSize(data).then(function (data) {
resolve(data);
});
});
}
}, {
key: "_initAllDataSize",
value: function _initAllDataSize(data) {
var _this6 = this;
return new Promise(function (resolve) {
var _nodeMap = {};
var initNum = 0;
data.nodes.concat(data.edges).forEach(function (node) {
_nodeMap[node.key] = node;
//计算和设置node的尺寸
_this6._initContentAndGetSize(node).then(function (opt) {
_.extend(node, opt);
//如果是菱形,还需要重新调整新的尺寸
if (node.shapeType == 'diamond') {
//因为node的尺寸前面计算出来的是矩形的尺寸,如果是菱形的话,这里就是指内接矩形的尺寸,
//需要换算成外接矩形的尺寸
var innerRect = {
//内接矩形
width: node.width,
height: node.height
};
var includedAngle = _this6.node.includedAngle / 2;
var includeRad = includedAngle * Math.PI / 180;
var newWidthDiff = innerRect.height / Math.tan(includeRad);
var newHeightDiff = innerRect.width * Math.tan(includeRad);
//在内接矩形基础上扩展出来的外界矩形
var newWidth = innerRect.width + newWidthDiff;
var newHeight = innerRect.height + newHeightDiff;
//把新的菱形的外界边界回写
node._innerRect = {
width: node.width,
height: node.height
};
node.width = newWidth;
node.height = newHeight;
}
;
node._contentInited = true;
initNum++;
//如果所有的node的size都初始化完毕
if (initNum == data.nodes.length + data.edges.length) {
//all is inited
//然后给edge填写source 和 target
_.each(data.edges, function (edge) {
var keys = edge.key;
edge.source = _nodeMap[keys[0]];
edge.target = _nodeMap[keys[1]];
});
resolve(data);
}
;
});
});
});
}
}, {
key: "_layoutData",
value: function _layoutData() {
if (this.layout == "dagre") {
this._dagreLayout(this.data);
} else if (this.layout == "tree") {
this._treeLayout(this.data);
} else if (_.isFunction(this.layout)) {
//layout需要设置好data中nodes的xy, 以及edges的points,和 size的width,height
this.layout(this.data);
}
;
}
}, {
key: "_dagreLayout",
value: function _dagreLayout(data) {
//https://github.com/dagrejs/dagre/wiki
var layout = _global.default.layout.dagre || _dagre.default;
var g = new layout.graphlib.Graph();
g.setGraph(this.layoutOpts.graph);
g.setDefaultEdgeLabel(function () {
//其实我到现在都还没搞明白setDefaultEdgeLabel的作用
return {};
});
_.each(data.nodes, function (node) {
g.setNode(node.key, node);
});
_.each(data.edges, function (edge) {
//后面的参数直接把edge对象传入进去的话,setEdge会吧point 和 x y 等信息写回edge
g.setEdge.apply(g, (0, _toConsumableArray2.default)(edge.key).concat([edge]));
//g.setEdge(edge.key[0],edge.key[1]);
});
layout.layout(g);
data.size.width = g.graph().width;
data.size.height = g.graph().height;
//this.g = g;
return data;
}
//TODO: 待实现,目前其实用dagre可以直接实现tree,但是如果可以用更加轻便的tree也可以尝试下
}, {
key: "_treeLayout",
value: function _treeLayout() {
// let tree = global.layout.tree().separation(function(a, b) {
// //设置横向节点之间的间距
// let totalWidth = a.width + b.width;
// return (totalWidth/2) + 10;
// });
// let nodes = tree.nodes( this.jsonData[0] ).reverse();
// let links = tree.links(nodes);
}
}, {
key: "widget",
value: function widget() {
/*
me.g.edges().forEach( e => {
let edge = me.g.edge(e);
console.log( edge )
} );
*/
this._drawEdges();
this._drawNodes();
}
//画布偏移量
}, {
key: "offset",
value: function offset() {
var _offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
x: 0,
y: 0
};
var _this$zoom$offset = this.zoom.offset(_offset),
x = _this$zoom$offset.x,
y = _this$zoom$offset.y;
this.graphsView.context.x = parseInt(x);
this.graphsView.context.y = parseInt(y);
}
//把某个节点移动到居中位置
}, {
key: "setNodeToCenter",
value: function setNodeToCenter(key) {
var nodeData = this.getNodeDataAt(key);
if (nodeData) {
var globalPos = nodeData.shapeElement.localToGlobal();
var toGlobalPos = {
x: this.app.width / 2 - nodeData.width / 2,
y: this.app.height / 2 - nodeData.height / 2
};
var toCenterOffset = {
x: parseInt(toGlobalPos.x - globalPos.x),
y: parseInt(toGlobalPos.y - globalPos.y)
};
this.offset(toCenterOffset);
}
}
}, {
key: "_drawEdges",
value: function _drawEdges() {
var me = this;
_.each(this.data.edges, function (edge) {
var key = edge.key.join('_');
if (me.line.isTree && edge.points.length == 3) {
//严格树状图的话(三个点),就转化成4个点的,有两个拐点
me._setTreePoints(edge);
}
;
var lineShapeOpt = me._getLineShape(edge, me.line.inflectionRadius);
var type = lineShapeOpt.type;
var path = lineShapeOpt.path;
var pointList = lineShapeOpt.pointList;
var shape = type == 'path' ? Path : BrokenLine;
var lineWidth = me.getProp(me.line.lineWidth, edge);
var strokeStyle = me.getProp(me.line.strokeStyle, edge);
var lineType = me.getProp(me.line.lineType, edge);
var cursor = me.getProp(me.line.cursor, edge);
var edgeId = 'edge_' + key;
var _path = me.edgesSp.getChildById(edgeId);
if (_path) {
if (type == 'path') {
_path.context.path = path;
}
if (type == 'brokenLine') {
_path.context.pointList = pointList;
}
_path.context.lineWidth = lineWidth;
_path.context.strokeStyle = strokeStyle;
_path.context.lineType = lineType;
} else {
var _ctx = {
lineWidth: lineWidth,
strokeStyle: strokeStyle,
lineType: lineType,
cursor: cursor
};
if (type == 'path') {
_ctx.path = path;
}
if (type == 'brokenLine') {
//_ctx.smooth = true;
//_ctx.curvature = 0.25;
_ctx.pointList = pointList;
}
_path = new shape({
id: edgeId,
context: _ctx
});
_path.on(event.types.get(), function (e) {
var node = this.nodeData;
node.__no_value = true;
e.eventInfo = {
trigger: me.line,
nodes: [node]
};
me.app.fire(e.type, e);
});
me.edgesSp.addChild(_path);
}
;
edge.pathElement = _path;
_path.nodeData = edge; //edge也是一个node数据
var arrowControl = edge.points.slice(-2, -1)[0];
if (me.line.shapeType == "bezier") {
if (me.rankdir == "TB" || me.rankdir == "BT") {
arrowControl.x += (edge.source.x - edge.target.x) / 20;
}
if (me.rankdir == "LR" || me.rankdir == "RL") {
arrowControl.y += (edge.source.y - edge.target.y) / 20;
}
}
;
var edgeLabelId = 'label_' + key;
var enabled = me.getProp(me.line.edgeLabel.enabled, edge);
if (enabled) {
var textAlign = me.getProp(me.node.content.textAlign, edge);
var textBaseline = me.getProp(me.node.content.textBaseline, edge);
var fontSize = me.getProp(me.line.edgeLabel.fontSize, edge);
var fontColor = me.getProp(me.line.edgeLabel.fontColor, edge);
// let offsetX = me.getProp( me.line.edgeLabel.offsetX , edge );
// let offsetY = me.getProp( me.line.edgeLabel.offsetY , edge );
var offset = me.getProp(me.line.icon.offset, edge);
if (!offset) {
//default 使用edge.x edge.y 也就是edge label的位置
offset = {
x: edge.x,
y: edge.y
};
}
;
var _edgeLabel = me.labelsSp.getChildById(edgeLabelId);
if (_edgeLabel) {
_edgeLabel.resetText(edge.content);
_edgeLabel.context.x = offset.x;
_edgeLabel.context.y = offset.y;
_edgeLabel.context.fontSize = fontSize;
_edgeLabel.context.fillStyle = fontColor;
_edgeLabel.context.textAlign = textAlign;
_edgeLabel.context.textBaseline = textBaseline;
} else {
_edgeLabel = new _canvax.default.Display.Text(edge.content, {
id: edgeLabelId,
context: {
x: offset.x,
y: offset.y,
fontSize: fontSize,
fillStyle: fontColor,
textAlign: textAlign,
textBaseline: textBaseline
}
});
_edgeLabel.on(event.types.get(), function (e) {
var node = this.nodeData;
node.__no_value = true;
e.eventInfo = {
trigger: me.line,
nodes: [node]
};
me.app.fire(e.type, e);
});
me.labelsSp.addChild(_edgeLabel);
}
edge.labelElement = _edgeLabel;
_edgeLabel.nodeData = edge;
}
;
var edgeIconEnabled = me.getProp(me.line.icon.enabled, edge);
if (edgeIconEnabled) {
var _chartCode = me.getProp(me.line.icon.charCode, edge);
var charCode = String.fromCharCode(parseInt(_chartCode, 16));
if (_chartCode != '') {
var _lineWidth = me.getProp(me.line.icon.lineWidth, edge);
var _strokeStyle = me.getProp(me.line.icon.strokeStyle, edge);
var fontFamily = me.getProp(me.line.icon.fontFamily, edge);
var _fontSize = me.getProp(me.line.icon.fontSize, edge);
var _fontColor = me.getProp(me.line.icon.fontColor, edge);
var background = me.getProp(me.line.icon.background, edge);
var _textAlign = 'center';
var _textBaseline = 'middle';
var _offset2 = me.getProp(me.line.icon.offset, edge);
var offsetX = me.getProp(me.line.icon.offsetX, edge);
var offsetY = me.getProp(me.line.icon.offsetY, edge);
if (!_offset2) {
//default 使用edge.x edge.y 也就是edge label的位置
_offset2 = {
x: parseInt(edge.x) + offsetX,
y: parseInt(edge.y) + offsetY
};
}
;
var _iconBackCtx = {
x: _offset2.x,
y: _offset2.y - 1,
r: parseInt(_fontSize * 0.5) + 2,
fillStyle: background,
strokeStyle: _strokeStyle,
lineWidth: _lineWidth
};
var edgeIconBackId = 'edge_item_icon_back_' + key;
var _iconBack = me.labelsSp.getChildById(edgeIconBackId);
if (_iconBack) {
//_.extend( true, _iconBack.context, _iconBackCtx )
Object.assign(_iconBack.context, _iconBackCtx);
} else {
_iconBack = new Circle({
id: edgeIconBackId,
context: _iconBackCtx
});
me.labelsSp.addChild(_iconBack);
}
;
edge.edgeIconBack = _iconBack;
_iconBack.nodeData = edge;
var edgeIconId = 'edge_item_icon_' + key;
var _edgeIcon = me.labelsSp.getChildById(edgeIconId);
if (_edgeIcon) {
_edgeIcon.resetText(charCode);
_edgeIcon.context.x = _offset2.x;
_edgeIcon.context.y = _offset2.y;
_edgeIcon.context.fontSize = _fontSize;
_edgeIcon.context.fillStyle = _fontColor;
_edgeIcon.context.textAlign = _textAlign;
_edgeIcon.context.textBaseline = _textBaseline;
_edgeIcon.context.fontFamily = fontFamily;
//_edgeIcon.context.lineWidth = lineWidth;
//_edgeIcon.context.strokeStyle = strokeStyle;
} else {
_edgeIcon = new _canvax.default.Display.Text(charCode, {
id: edgeIconId,
context: {
x: _offset2.x,
y: _offset2.y,
fillStyle: _fontColor,
cursor: 'pointer',
fontSize: _fontSize,
textAlign: _textAlign,
textBaseline: _textBaseline,
fontFamily: fontFamily
}
});
_edgeIcon.on(event.types.get(), function (e) {
var node = this.nodeData;
node.__no_value = true;
var trigger = me.line;
if (me.line.icon['on' + e.type]) {
trigger = me.line.icon;
}
;
e.eventInfo = {
trigger: trigger,
nodes: [node]
};
me.app.fire(e.type, e);
});
me.labelsSp.addChild(_edgeIcon);
}
edge.edgeIconElement = _edgeIcon;
_edgeIcon.nodeData = edge;
}
}
;
if (me.line.arrow.enabled) {
var arrowId = "arrow_" + key;
var _arrow = me.arrowsSp.getChildById(arrowId);
if (_arrow) {
//arrow 只监听了x y 才会重绘,,,暂时只能这样处理,手动的赋值control.x control.y
//而不是直接把 arrowControl 赋值给 control
_arrow.context.x = me.line.arrow.offsetX;
_arrow.context.y = me.line.arrow.offsetY;
_arrow.context.fillStyle = strokeStyle;
_arrow.context.control.x = arrowControl.x;
_arrow.context.control.y = arrowControl.y;
_arrow.context.point = edge.points.slice(-1)[0];
_arrow.context.strokeStyle = strokeStyle;
_arrow.context.fillStyle = strokeStyle;
// _.extend(true, _arrow, {
// control: arrowControl,
// point: edge.points.slice(-1)[0],
// strokeStyle: strokeStyle
// } );
} else {
_arrow = new Arrow({
id: arrowId,
context: {
x: me.line.arrow.offsetX,
y: me.line.arrow.offsetY,
control: arrowControl,
point: edge.points.slice(-1)[0],
strokeStyle: strokeStyle,
fillStyle: strokeStyle
}
});
me.arrowsSp.addChild(_arrow);
}
;
edge.arrowElement = _arrow;
}
;
});
}
}, {
key: "_drawNodes",
value: function _drawNodes() {
var me = this;
_.each(this.data.nodes, function (node) {
me._drawNode(node);
});
}
}, {
key: "_drawNode",
value: function _drawNode(node) {
var me = this;
var shape = Rect;
var nodeId = "node_" + node.key;
var cursor = me.node.cursor;
var _me$_getNodeStyle = me._getNodeStyle(node),
lineWidth = _me$_getNodeStyle.lineWidth,
fillStyle = _me$_getNodeStyle.fillStyle,
strokeStyle = _me$_getNodeStyle.strokeStyle,
radius = _me$_getNodeStyle.radius,
shadowOffsetX = _me$_getNodeStyle.shadowOffsetX,
shadowOffsetY = _me$_getNodeStyle.shadowOffsetY,
shadowBlur = _me$_getNodeStyle.shadowBlur,
shadowColor = _me$_getNodeStyle.shadowColor;
var context = {
x: parseInt(node.x) - parseInt(node.width / 2),
y: parseInt(node.y) - parseInt(node.height / 2),
width: node.width,
height: node.height,
cursor: cursor,
lineWidth: lineWidth,
fillStyle: fillStyle,
strokeStyle: strokeStyle,
radius: radius,
shadowOffsetX: shadowOffsetX,
shadowOffsetY: shadowOffsetY,
shadowBlur: shadowBlur,
shadowColor: shadowColor
};
if (node.shapeType == 'diamond') {
shape = Diamond;
context = {
x: parseInt(node.x),
y: parseInt(node.y),
cursor: cursor,
innerRect: node._innerRect,
lineWidth: lineWidth,
fillStyle: fillStyle,
strokeStyle: strokeStyle,
shadowOffsetX: shadowOffsetX,
shadowOffsetY: shadowOffsetY,
shadowBlur: shadowBlur,
shadowColor: shadowColor
};
}
;
var _boxShape = me.nodesSp.getChildById(nodeId);
if (_boxShape) {
_.extend(_boxShape.context, context);
} else {
_boxShape = new shape({
id: nodeId,
hoverClone: false,
context: context
});
me.nodesSp.addChild(_boxShape);
_boxShape.on(event.types.get(), function (e) {
var node = this.nodeData;
node.__no_value = true;
e.eventInfo = {
trigger: me.node,
nodes: [node]
};
if (me.node.focus.enabled) {
if (e.type == "mouseover") {
me.focusAt(this.nodeData);
}
if (e.type == "mouseout") {
me.unfocusAt(this.nodeData);
}
}
;
if (me.node.select.enabled && me.node.select.triggerEventType.indexOf(e.type) > -1) {
//如果开启了图表的选中交互
//TODO:这里不能
var onbefore = me.node.select.onbefore;
var onend = me.node.select.onend;
if (!onbefore || typeof onbefore == 'function' && onbefore.apply(me, [this.nodeData]) !== false) {
if (this.nodeData.selected) {
//说明已经选中了
me.unselectAt(this.nodeData);
} else {
me.selectAt(this.nodeData);
}
onend && typeof onend == 'function' && onend.apply(me, [this.nodeData]);
}
}
;
me.app.fire(e.type, e);
});
}
;
_boxShape.nodeData = node;
node.shapeElement = _boxShape;
if (me.node.select.list.indexOf(node.key) > -1) {
me.selectAt(node);
}
;
if (node.ctype == "canvas") {
node.contentElement.context.visible = true;
}
;
_boxShape.on("transform", function () {
if (node.ctype == "canvas") {
node.contentElement.context.x = parseInt(node.x);
node.contentElement.context.y = parseInt(node.y);
} else if (node.ctype == "html") {
var devicePixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio : 1;
var contentMatrix = _boxShape.worldTransform.clone();
contentMatrix = contentMatrix.scale(1 / devicePixelRatio, 1 / devicePixelRatio);
node.contentElement.style.transform = "matrix(" + contentMatrix.toArray().join() + ")";
node.contentElement.style.transformOrigin = "left top"; //修改为左上角为旋转中心点来和canvas同步
if (node.shapeType == 'diamond') {
node.contentElement.style.left = -parseInt(node._innerRect.width / 2 * me.status.transform.scale) + "px";
node.contentElement.style.top = -parseInt(node._innerRect.height / 2 * me.status.transform.scale) + "px";
}
;
node.contentElement.style.visibility = "visible";
}
;
});
}
}, {
key: "_getNodeStyle",
value: function _getNodeStyle(nodeData, targetPath) {
var me = this;
var radius = _.flatten([me.getProp(me.node.radius, nodeData)]);
var target = me.node;
if (targetPath == 'select') {
target = me.node.select;
}
if (targetPath == 'focus') {
target = me.node.focus;
}
var lineWidth = me.getProp(target.lineWidth, nodeData);
var fillStyle = me.getProp(target.fillStyle, nodeData);
var strokeStyle = me.getProp(target.strokeStyle, nodeData);
var shadowOffsetX = me.getProp(target.shadow.shadowOffsetX, nodeData);
var shadowOffsetY = me.getProp(target.shadow.shadowOffsetY, nodeData);
var shadowBlur = me.getProp(target.shadow.shadowBlur, nodeData);
var shadowColor = me.getProp(target.shadow.shadowColor, nodeData);
return {
lineWidth: lineWidth,
fillStyle: fillStyle,
strokeStyle: strokeStyle,
radius: radius,
shadowOffsetX: shadowOffsetX,
shadowOffsetY: shadowOffsetY,
shadowBlur: shadowBlur,
shadowColor: shadowColor
};
}
}, {
key: "_setNodeStyle",
value: function _setNodeStyle(nodeData, targetPath) {
var _this$_getNodeStyle = this._getNodeStyle(nodeData, targetPath),
lineWidth = _this$_getNodeStyle.lineWidth,
fillStyle = _this$_getNodeStyle.fillStyle,
strokeStyle = _this$_getNodeStyle.strokeStyle,
shadowOffsetX = _this$_getNodeStyle.shadowOffsetX,
shadowOffsetY = _this$_getNodeStyle.shadowOffsetY,
shadowBlur = _this$_getNodeStyle.shadowBlur,
shadowColor = _this$_getNodeStyle.shadowColor;
if (nodeData.shapeElement && nodeData.shapeElement.context) {
var ctx = nodeData.shapeElement.context;
ctx.lineWidth = lineWidth;
ctx.fillStyle = fillStyle;
ctx.strokeStyle = strokeStyle;
ctx.shadowOffsetX = shadowOffsetX;
ctx.shadowOffsetY = shadowOffsetY;
ctx.shadowBlur = shadowBlur;
ctx.shadowColor = shadowColor;
}
}
}, {
key: "focusAt",
value: function focusAt(key) {
var nodeData = this.getNodeDataAt(key);
if (nodeData) {
!nodeData.selected && this._setNodeStyle(nodeData, 'focus');
nodeData.focused = true;
}
}
}, {
key: "unfocusAt",
value: function unfocusAt(key) {
var nodeData = this.getNodeDataAt(key);
if (nodeData) {
!nodeData.selected && this._setNodeStyle(nodeData);
nodeData.focused = false;
}
}
}, {
key: "selectAt",
value: function selectAt(key) {
var nodeData = this.getNodeDataAt(key);
if (nodeData) {
this._setNodeStyle(nodeData, 'select');
nodeData.selected = true;
if (this.node.select.list.indexOf(nodeData.key) == -1) {
this.node.select.list.push(nodeData.key);
}
}
}
}, {
key: "selectAll",
value: function selectAll() {
var _this7 = this;
this.data.nodes.forEach(function (nodeData) {
_this7.selectAt(nodeData);
});
}
}, {
key: "unselectAt",
value: function unselectAt(key) {
var nodeData = this.getNodeDataAt(key);
if (nodeData) {
nodeData.focused ? this._setNodeStyle(nodeData, 'focus') : this._setNodeStyle(nodeData);
nodeData.selected = false;
var selectedKeyInd = this.node.select.list.indexOf(nodeData.key);
if (selectedKeyInd > -1) {
this.node.select.list.splice(selectedKeyInd, 1);
}
}
}
}, {
key: "unselectAll",
value: function unselectAll() {
var _this8 = this;
this.data.nodes.forEach(function (nodeData) {
_this8.unselectAt(nodeData);
});
}
}, {
key: "getNodeDataAt",
value: function getNodeDataAt(key) {
if (key.type && (key.type == "relation" || key.type == "tree")) {
return key;
}
;
if (typeof key == 'string') {
var keys = key.split(',');
if (keys.length == 1) {
return this.data.nodes.find(function (item) {
return item.key == key;
});
}
if (keys.length == 2) {
return this.data.edges.find(function (item) {
return item.key.join() == keys.join();
});
}
}
;
}
}, {
key: "_setTreePoints",
value: function _setTreePoints(edge) {
var points = edge.points;
if (this.rankdir == "TB" || this.rankdir == "BT") {
points[0] = {
x: edge.source.x,
y: edge.source.y + (this.rankdir == "BT" ? -1 : 1) * edge.source.height / 2
};
points.splice(1, 0, {
x: edge.source.x,
y: points.slice(-2, -1)[0].y
});
}
if (this.rankdir == "LR" || this.rankdir == "RL") {
points[0] = {
x: edge.source.x + (this.rankdir == "RL" ? -1 : 1) * edge.source.width / 2,
y: edge.source.y
};
points.splice(1, 0, {
x: points.slice(-2, -1)[0].x,
y: edge.source.y
});
}
edge.points = points;
}
/**
*
* @param {shapeType,points} edge
* @param {number} inflectionRadius 拐点的圆角半径
*/
}, {
key: "_getLineShape",
value: function _getLineShape(edge, inflectionRadius) {
var points = edge.points;
var line = {
type: 'path',
// pah or brokenLine
pointList: null,
path: str
};
var head = points[0];
var tail = points.slice(-1)[0];
var str = "M" + head.x + " " + head.y;
if (edge.shapeType == "bezier") {
if (points.length == 3) {
str += ",Q" + points[1].x + " " + points[1].y + " " + tail.x + " " + tail.y;
}
if (points.length == 4) {
str += ",C" + points[1].x + " " + points[1].y + " " + points[2].x + " " + points[2].y + " " + tail.x + " " + tail.y;
}
if (points.length >= 5) {
line.type = 'brokenLine';
line.pointList = points.map(function (item) {
return [item.x, item.y];
});
return line;
}
}
;
if (edge.shapeType == "brokenLine") {
_.each(points, function (point, i) {
if (i) {
if (inflectionRadius && i < points.length - 1) {
//圆角连线
var prePoint = points[i - 1];
var nextPoint = points[i + 1];
//要从这个点到上个点的半径距离,已point为控制点,绘制nextPoint的半径距离
var radius = inflectionRadius;
//radius要做次二次校验,取radius 以及 point 和prePoint距离以及和 nextPoint 的最小值
//let _disPre = Math.abs(Math.sqrt( (prePoint.x - point.x)*(prePoint.x - point.x) + (prePoint.y - point.y)*(prePoint.y - point.y) ));
//let _disNext = Math.abs(Math.sqrt( (nextPoint.x - point.x)*(nextPoint.x - point.x) + (nextPoint.y - point.y)*(nextPoint.y - point.y) ));
var _disPre = Math.max(Math.abs(prePoint.x - point.x) / 2, Math.abs(prePoint.y - point.y) / 2);
var _disNext = Math.max(Math.abs(nextPoint.x - point.x) / 2, Math.abs(nextPoint.y - point.y) / 2);
radius = _.min([radius, _disPre, _disNext]);
//console.log(Math.atan2( point.y - prePoint.y , point.x - prePoint.x ),Math.atan2( nextPoint.y - point.y , nextPoint.x - point.x ))
if (point.x == prePoint.x && point.y == prePoint.y || point.x == nextPoint.x && point.y == nextPoint.y || Math.atan2(point.y - prePoint.y, point.x - prePoint.x) == Math.atan2(nextPoint.y - point.y, nextPoint.x - point.x)) {
//如果中间的这个点 , 和前后的点在一个直线上面,就略过
return;
} else {
var getPointOf = function getPointOf(p) {
var _atan2 = Math.atan2(p.y - point.y, p.x - point.x);
return {
x: point.x + radius * Math.cos(_atan2),
y: point.y + radius * Math.sin(_atan2)
};
};
;
var bezierBegin = getPointOf(prePoint);
var bezierEnd = getPointOf(nextPoint);
str += ",L" + bezierBegin.x + " " + bezierBegin.y + ",Q" + point.x + " " + point.y + " " + bezierEnd.x + " " + bezierEnd.y;
}
} else {
//直角连线
str += ",L" + point.x + " " + point.y;
}
;
}
});
}
;
line.path = str;
//str += "z"
return line;
}
/**
* 字符串是否含有html标签的检测
*/
}, {
key: "_checkHtml",
value: function _checkHtml(str) {
var reg = /<[^>]+>/g;
return reg.test(str);
}
}, {
key: "_getContent",
value: function _getContent(rowData) {
var me = this;
var _c; //this.node.content;
var field = this.node.content.field;
if (this._isField(field)) {
_c = rowData[field];
}
;
if (me.node.content.format && _.isFunction(me.node.content.format)) {
_c = me.node.content.format.apply(this, [_c, rowData]);
} else {
//否则用fieldConfig上面的
var _coord = me.app.getComponent({
name: 'coord'
});
var fieldConfig = _coord.getFieldConfig(field);
if (fieldConfig) {
_c = fieldConfig.getFormatValue(_c);
}
;
}
return _c;
}
}, {
key: "_isField",
value: function _isField(str) {
return ~this.dataFrame.fields.indexOf(str);
}
}, {
key: "_initContentAndGetSize",
value: function _initContentAndGetSize(node) {
var me = this;
var contentType = node.ctype;
if (me._isField(contentType)) {
contentType = node.rowData[contentType];
}
;
!contentType && (contentType = 'canvas');
if (contentType == 'canvas') {
return me._getEleAndsetCanvasSize(node);
}
;
if (contentType == 'html') {
return me._getEleAndsetHtmlSize(node);
}
;
}
}, {
key: "_getEleAndsetCanvasSize",
value: function _getEleAndsetCanvasSize(node) {
var _this9 = this;
var me = this;
return new Promise(function (resolve) {
var content = node.content;
var width = node.rowData.width,
height = node.rowData.height;
//let sprite = new Canvax.Display.Sprite({});
var context = {
fillStyle: me.getProp(me.node.content.fontColor, node),
textAlign: me.getProp(me.node.content.textAlign, node),
textBaseline: me.getProp(me.node.content.textBaseline, node)
};
//console.log(node.key);
var contentLabelId = "content_label_" + node.key;
var _contentLabel = me.nodesContentSp.getChildById(contentLabelId);
if (_contentLabel) {
//已经存在的label
_contentLabel.resetText(content);
_.extend(_contentLabel.context, context);
} else {
//新创建text,根据 text 来计算node需要的width和height
_contentLabel = new _canvax.default.Display.Text(content, {
id: contentLabelId,
context: context
});
_contentLabel.context.visible = false;
if (!_.isArray(node.key)) {
me.nodesContentSp.addChild(_contentLabel);
}
;
}
;
var inited;
if (_this9.node.content.init && typeof _this9.node.content.init === 'function') {
inited = _this9.node.content.init(node, _contentLabel);
}
;
if (inited && typeof inited.then == 'function') {
inited.then(function () {
if (!width) {
width = _contentLabel.getTextWidth() + me.getProp(me.node.padding, node) * me.status.transform.scale * 2;
}
;
if (!height) {
height = _contentLabel.getTextHeight() + me.getProp(me.node.padding, node) * me.status.transform.scale * 2;
}
;
resolve({
contentElement: _contentLabel,
width: width,
height: height
});
});
} else {
if (!width) {
width = _contentLabel.getTextWidth() + me.getProp(me.node.padding, node) * me.status.transform.scale * 2;
}
;
if (!height) {
height = _contentLabel.getTextHeight() + me.getProp(me.node.padding, node) * me.status.transform.scale * 2;
}
;
resolve({
contentElement: _contentLabel,
width: width,
height: height
});
}
});
}
}, {
key: "_getEleAndsetHtmlSize",
value: function _getEleAndsetHtmlSize(node) {
var _this10 = this;