chartx
Version:
Data Visualization Chart Library
1,389 lines (1,362 loc) • 60.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
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 _tools = require("../../../utils/tools");
var _zoom = _interopRequireDefault(require("../../../utils/zoom"));
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
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; })(); }
var _ = _canvax.default._,
event = _canvax.default.event;
var Rect = _canvax.default.Shapes.Rect;
var Diamond = _canvax.default.Shapes.Diamond;
var Line = _canvax.default.Shapes.Line;
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 iconWidth = 20;
/**
* 关系图中 包括了 配置,数据,和布局数据,
* 默认用配置和数据可以完成绘图, 但是如果有布局数据,就绘图玩额外调用一次绘图,把布局数据传入修正布局效果
*
* relation 也好, tree也好, 最后都要转换成 nodes edges
*
*/
var RelationBase = /*#__PURE__*/function (_GraphsBase) {
function RelationBase(opt, app, preComp) {
var _this;
(0, _classCallCheck2.default)(this, RelationBase);
_this = _callSuper(this, RelationBase, [opt, app]);
_this.type = "relation";
_.extend(true, _this, (0, _tools.getDefaultProps)(RelationBase.defaultProps()), opt);
_this.domContainer = app.canvax.domView;
_this.induce = null;
_this.init(preComp);
return _this;
}
(0, _inherits2.default)(RelationBase, _GraphsBase);
return (0, _createClass2.default)(RelationBase, [{
key: "init",
value: function init(preComp) {
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);
if (preComp.zoom) {
this.preGraphsSpPosition = preComp.graphsSpPosition;
this.zoom = preComp.zoom;
this.offset();
} else {
this.zoom = new _zoom.default();
}
}
//这个node是放在 nodes 和 edges 中的数据结构
}, {
key: "getDefNode",
value: function getDefNode() {
var opt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var node = _objectSpread({
type: "relation",
//tree中会覆盖为tree
iNode: 0,
rowData: null,
key: "",
content: '',
ctype: 'canvas',
//下面三个属性在_setElementAndSize中设置
contentElement: null,
//外面传的layout数据可能没有element,widget的时候要检测下
width: null,
height: null,
boundingClientWidth: 0,
//通过width,然后看有多少icon,计算出来用于layout计算的width
//这个在layout的时候设置
x: null,
y: null,
shapeType: null,
focused: false,
selected: false
}, opt);
return node;
}
}, {
key: "checkNodeSizeForShapeType",
value: function checkNodeSizeForShapeType(node) {
//如果是菱形,还需要重新调整新的尺寸
if (node.shapeType == 'diamond') {
//因为node的尺寸前面计算出来的是矩形的尺寸,如果是菱形的话,这里就是指内接矩形的尺寸,
//需要换算成外接矩形的尺寸
var includedAngle = this.node.includedAngle / 2;
var includeRad = includedAngle * Math.PI / 180;
var boundingClientWidth = node.boundingClientWidth,
height = node.height;
node._innerBound = {
width: boundingClientWidth,
height: height
};
var newWidthDiff = height / Math.tan(includeRad);
var newHeightDiff = boundingClientWidth * Math.tan(includeRad);
//在内接矩形基础上扩展出来的外界矩形
var newWidth = boundingClientWidth + newWidthDiff;
var newHeight = height + newHeightDiff;
//node上面记录的width 和 height 永远是内容的 高宽, 但是像 diamond 等, 布局的时候的bound是要计算一个新的
//布局的时候, 布局算法要优先取 layoutWidth 和 layoutHeight
node.boundingClientWidth = newWidth;
node.height = newHeight;
}
;
}
}, {
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 _wheelHandleTimeLen = 32; //16*2
var _wheelHandleTimeer = null;
var _deltaY = 0;
this.induce.on(event.types.get(), function (e) {
if (me.status.transform.enabled) {
var _contextmenu = me.app.getComponent({
name: 'contextmenu'
});
if (!_contextmenu || !_contextmenu.isShow) {
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 = '');
}
;
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") {
//console.log( _deltaY, e.deltaY )
if (Math.abs(e.deltaY) > Math.abs(_deltaY)) {
_deltaY = e.deltaY;
}
;
if (!_wheelHandleTimeer) {
_wheelHandleTimeer = setTimeout(function () {
if (me.status.transform.wheelAction == 'offset') {
//移动的话用offset,偏移多少像素
var offsetPoint = {
x: -e.deltaX * 2,
y: -e.deltaY * 2
};
var leftDiss = parseInt(me.graphsView.context.x + me.graphsSp.context.x + me.data.viewPort.maxLeft + offsetPoint.x + me.app.padding.left);
if (leftDiss < 0) {
offsetPoint.x = parseInt(offsetPoint.x - leftDiss);
}
var rightDiss = parseInt(me.graphsView.context.x + me.graphsSp.context.x + me.data.viewPort.maxRight + offsetPoint.x + me.app.padding.right);
if (rightDiss >= me.app.width) {
offsetPoint.x = parseInt(offsetPoint.x - (rightDiss - me.app.width));
}
var topDiss = parseInt(me.graphsView.context.y + me.graphsSp.context.y + me.data.viewPort.maxTop + offsetPoint.y + me.app.padding.top);
if (topDiss < 0) {
offsetPoint.y = parseInt(offsetPoint.y - topDiss);
}
var bottomDiss = parseInt(me.graphsView.context.y + me.graphsSp.context.y + me.data.viewPort.maxBottom + offsetPoint.y + me.app.padding.bottom);
if (bottomDiss >= me.app.height) {
offsetPoint.y = parseInt(offsetPoint.y - (bottomDiss - me.app.height));
}
//console.log( offsetPoint )
var _me$zoom$offset = me.zoom.offset(offsetPoint),
_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);
}
;
}
;
}
}
;
//induce 的 事件都 在 graph 上面派发,可以用
e.eventInfo = {
trigger: me,
iNode: -1
//TODO:这里设置了的话,会导致多graphs里获取不到别的graphs的nodes信息了
//nodes : me.getNodesAt( this.iNode )
};
me.app.fire(e.type, e);
});
}
}, {
key: "_resetData",
value: function _resetData(data, dataTrigger) {
var _this2 = this;
var me = this;
this._preData = this.data;
return new Promise(function (resolve) {
_this2.initData(data, dataTrigger).then(function (_data) {
_this2.data = _data;
_this2.layoutData();
var _preNodes = _this2._preData && _this2._preData.nodes || [];
var _preEdges = _this2._preData && _this2._preData.edges || [];
_.each(_preNodes, 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;
//TODO:把原来的对象的 contentElement 搞过来, 就可以减少getChild的消耗
//还有个更加重要的原因,这段代码解决了展开收起的抖动
if (nodeData.ctype == preNode.ctype) {
//类型没变, 就可以用同一个 contentElement
nodeData.contentElement = preNode.contentElement;
}
;
}
});
_.each(_preEdges, function (preEdge) {
if (!_.find(me.data.edges, function (edge) {
return preEdge.key.join('_') == edge.key.join('_');
})) {
me._destroy(preEdge);
}
});
_this2.widget();
if (dataTrigger) {
var origin = dataTrigger.origin || (dataTrigger.params || {}).origin; //兼容老的配置里面没有params,直接传origin的情况
//钉住某个node为参考点(不移动)
if (origin != undefined) {
var preOriginNode = _.find(_preNodes, function (node) {
return node.key == origin;
});
var originNode = _.find(_this2.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 _this2$zoom$offset = _this2.zoom.offset(offsetPos),
x = _this2$zoom$offset.x,
y = _this2$zoom$offset.y;
me.graphsView.context.x = parseInt(x);
me.graphsView.context.y = parseInt(y);
}
;
}
;
}
;
resolve();
});
});
}
}, {
key: "_destroy",
value: function _destroy(item) {}
}, {
key: "_drawEdges",
value: function _drawEdges() {
var me = this;
_.each(this.data.edges, function (edge) {
//console.log(edge.points)
var lineShapeOpt = me._getLineShape(edge, me.line.inflectionRadius);
var key = edge.key.join('_');
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: "_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.boundingClientWidth / 2),
y: parseInt(node.y) - parseInt(node.height / 2),
width: node.boundingClientWidth,
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._innerBound,
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);
_boxShape.nodeData = node;
_boxShape.fire('transform');
} 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, e]) !== false) {
if (this.nodeData.selected) {
//说明已经选中了
me.unselectAt(this.nodeData);
} else {
me.selectAt(this.nodeData);
}
onend && typeof onend == 'function' && onend.apply(me, [this.nodeData, e]);
}
}
;
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 () {
var node = this.nodeData;
if (node.ctype == "canvas") {
node.contentElement.context.x = parseInt(node.x - node.boundingClientWidth / 2 + me.node.padding + (node.preIconCharCode ? iconWidth : 0));
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.boundingClientWidth - node._innerBound.width) / 2 * me.status.transform.scale) + "px";
node.contentElement.style.top = -parseInt(node.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: "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: "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 _this3 = this;
this.data.nodes.forEach(function (nodeData) {
_this3.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 _this4 = this;
this.data.nodes.forEach(function (nodeData) {
_this4.unselectAt(nodeData);
});
//有些被折叠了的selected也要清除干净的话,必须多做一步list = []
this.node.select.list = [];
}
}, {
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();
});
}
}
;
}
/**
*
* @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.splice(0, 1)[0];
var str = "M" + head.x + " " + head.y;
var start = points[0];
str += ",L" + start.x + " " + start.y;
var end = points.slice(-1)[0];
if (edge.shapeType == "bezier") {
if (points.length == 3) {
str += ",Q" + points[1].x + " " + points[1].y + " " + end.x + " " + end.y;
}
if (points.length == 4) {
str += ",C" + points[1].x + " " + points[1].y + " " + points[2].x + " " + points[2].y + " " + end.x + " " + end.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") {
if (points.length == 3) {
points.splice(1, 0, {
x: points[1].x,
y: start.y
});
}
_.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;
}
;
}
});
}
;
if (edge.target.shapeType == 'underLine') {
var w = edge.target.rowData._node.boundingClientWidth;
var x = parseInt(edge.target.x) + parseInt(w / 2);
str += ",L" + x + " " + (parseInt(edge.target.y) + parseInt(edge.target.height / 2));
}
;
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: "_getEleAndsetCanvasSize",
value: function _getEleAndsetCanvasSize(node) {
var _this5 = this;
var me = this;
return new Promise(function (resolve) {
var content = node.content;
var width = me.getProp(me.node.width, node);
if (!width && node.width) {
width = node.width;
}
var height = me.getProp(me.node.height, node);
if (!height && node.height) {
height = node.height;
}
var fontColor = me.getProp(me.node.content.fontColor, node);
if (node.rowData.fontColor) {
fontColor = node.rowData.fontColor;
}
if (node.rowData.style && node.rowData.style.fontColor) {
fontColor = node.rowData.style.fontColor;
}
var context = {
fillStyle: fontColor,
textAlign: me.getProp(me.node.content.textAlign, node),
textBaseline: me.getProp(me.node.content.textBaseline, node),
fontSize: me.getProp(me.node.content.fontSize, node)
};
var contentLabelId = "content_label_" + node.key;
var _contentLabel = node.contentElement || 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 (_this5.node.content.init && typeof _this5.node.content.init === 'function') {
inited = _this5.node.content.init(node, _contentLabel);
}
;
var _handle = function _handle() {
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: parseInt(width),
height: parseInt(height)
});
};
if (inited && typeof inited.then == 'function') {
inited.then(function () {
_handle();
});
} else {
_handle();
}
});
}
}, {
key: "_getEleAndsetHtmlSize",
value: function _getEleAndsetHtmlSize(node) {
var _this6 = this;
var me = this;
return new Promise(function (resolve) {
var content = node.content;
var width = me.getProp(me.node.width, node);
if (!width && me.node.rowData && node.rowData.width) {
width = node.rowData.width;
}
var height = me.getProp(me.node.height, node);
if (!height && me.node.rowData && node.rowData.height) {
height = node.rowData.height;
}
var contentLabelClass = "__content_label_" + node.key;
var _dom = node.contentElement || _this6.domContainer.getElementsByClassName(contentLabelClass)[0];
if (!_dom) {
_dom = document.createElement("div");
_dom.className = "chartx_relation_node " + contentLabelClass;
_dom.style.cssText += "; position:absolute;visibility:hidden;";
_this6.domContainer.appendChild(_dom);
}
// else {
// _dom = _dom[0]
// };
_dom.style.cssText += "; color:" + me.getProp(me.node.content.fontColor, node) + ";";
_dom.style.cssText += "; text-align:" + me.getProp(me.node.content.textAlign, node) + ";";
_dom.style.cssText += "; vertical-align:" + me.getProp(me.node.content.textBaseline, node) + ";";
//TODO 这里注释掉, 就让dom自己内部去控制padding吧
//_dom.style.cssText += "; padding:"+me.getProp(me.node.padding, node)+"px;";
_dom.innerHTML = content;
var inited;
if (_this6.node.content.init && typeof _this6.node.content.init === 'function') {
inited = _this6.node.content.init(node, _dom);
}
;
var _handle = function _handle() {
if (!width) {
width = _dom.offsetWidth; // + me.getProp(me.node.padding, node) * me.status.transform.scale * 2;
}
;
if (!height) {
height = _dom.offsetHeight; // + me.getProp(me.node.padding, node) * me.status.transform.scale * 2;
}
;
resolve({
contentElement: _dom,
width: parseInt(width),
height: parseInt(height)
});
};
if (inited && typeof inited.then == 'function') {
inited.then(function (opt) {
_handle();
});
} else {
_handle();
}
;
});
}
}, {
key: "getNodesAt",
value: function getNodesAt() {}
}, {
key: "getProp",
value: function getProp(prop, nodeData) {
var _prop = prop;
if (this._isField(prop)) {
_prop = nodeData.rowData[prop];
} else {
if (_.isArray(prop)) {
_prop = prop[nodeData.iNode];
}
;
if (_.isFunction(prop)) {
_prop = prop.apply(this, Array.prototype.slice.call(arguments).slice(1));
}
;
}
;
return _prop;
}
}], [{
key: "defaultProps",
value: function defaultProps() {
return {
field: {
detail: 'key字段设置',
documentation: '',
default: null
},
//rankdir: "TB",
//align: "DR",
//nodesep: 0,//同级node之间的距离
//edgesep: 0,
//ranksep: 0, //排与排之间的距离
rankdir: {
detail: '布局方向',
default: null
},
ranksep: {
detail: '排与排之间的距离',
default: 40
},
nodesep: {
detail: '同级node之间的距离',
default: 20
},
node: {
detail: '单个节点的配置',
propertys: {
shapeType: {
detail: '节点图形,支持rect,diamond,underLine(adc用)',
default: 'rect'
},
maxWidth: {
detail: '节点最大的width',
default: 200
},
cursor: {
detail: '节点的鼠标样式',
default: 'pointer'
},
width: {
detail: '节点的width,默认null(系统自动计算), 也可以是个function,用户来计算每一个节点的width',
default: null
},
height: {
detail: '节点的height,默认null(系统自动计算), 也可以是个function,用户来计算每一个节点的height',
default: null
},
radius: {
detail: '圆角角度,对rect生效',
default: 4
},
includedAngle: {
detail: 'shapeType为 diamond (菱形)的时候生效,x方向的夹角',
default: 60
},
fillStyle: {
detail: '节点背景色',
default: '#ffffff'
},
lineWidth: {
detail: '描边宽度',
default: 1
},
strokeStyle: {
detail: '描边颜色',
default: '#e5e5e5'
},
shadow: {
detail: '阴影设置',
propertys: {
shadowOffsetX: {
detail: 'x偏移量',
default: 0
},
shadowOffsetY: {
detail: 'y偏移量',
default: 0
},
shadowBlur: {
detail: '阴影模糊值',
default: 0
},
shadowColor: {
detail: '阴影颜色',
default: '#000000'
}
}
},
select: {
detail: '选中效果',
propertys: {
enabled: {
detail: '是否开启选中',
default: false
},
list: {
detail: '选中的node.key的集合,外部传入可以选中',
default: []
},
triggerEventType: {
detail: '触发事件',
default: 'click,tap'
},
shadow: {
detail: '选中效果的阴影设置',
propertys: {
shadowOffsetX: {
detail: 'x偏移量',
default: 0
},
shadowOffsetY: {
detail: 'y偏移量',
default: 0
},
shadowBlur: {
detail: '阴影模糊值',
default: 0
},
shadowColor: {
detail: '阴影颜色',
default: '#000000'
}
}
},
fillStyle: {
detail: 'hover节点背景色',
default: '#ffffff'
},
lineWidth: {
detail: 'hover描边宽度',
default: 1
},
strokeStyle: {
detail: 'hover描边颜色',
default: '#e5e5e5'
},
onbefore: {
detail: '执行select处理函数的前处理函数,返回false则取消执行select',
default: null
},
onend: {
detail: '执行select处理函数的后处理函数',
default: null
},
content: {
detail: '选中后节点内容配置',
propertys: {
fontColor: {
detail: '内容文本颜色',
default: '#666'
},
fontSize: {
detail: '内容文本大小(在canvas格式下有效)',
default: 14
},
format: {
detail: '内容格式化处理函数',
default: null
}
}
}
}
},
focus: {
detail: 'hover效果',
propertys: {
enabled: {
detail: '是否开启hover效果',
default: false
},
shadow: {
detail: '选中效果的阴影设置',
propertys: {
shadowOffse