You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
489 lines
14 KiB
JavaScript
489 lines
14 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports["default"] = void 0;
|
|
|
|
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
|
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
|
|
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
|
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
|
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
|
|
var _style = _interopRequireDefault(require("./style.class"));
|
|
|
|
var _transition = _interopRequireDefault(require("@jiaminghi/transition"));
|
|
|
|
var _util = require("../plugin/util");
|
|
|
|
/**
|
|
* @description Class Graph
|
|
* @param {Object} graph Graph default configuration
|
|
* @param {Object} config Graph config
|
|
* @return {Graph} Instance of Graph
|
|
*/
|
|
var Graph = function Graph(graph, config) {
|
|
(0, _classCallCheck2["default"])(this, Graph);
|
|
config = (0, _util.deepClone)(config, true);
|
|
var defaultConfig = {
|
|
/**
|
|
* @description Weather to render graph
|
|
* @type {Boolean}
|
|
* @default visible = true
|
|
*/
|
|
visible: true,
|
|
|
|
/**
|
|
* @description Whether to enable drag
|
|
* @type {Boolean}
|
|
* @default drag = false
|
|
*/
|
|
drag: false,
|
|
|
|
/**
|
|
* @description Whether to enable hover
|
|
* @type {Boolean}
|
|
* @default hover = false
|
|
*/
|
|
hover: false,
|
|
|
|
/**
|
|
* @description Graph rendering index
|
|
* Give priority to index high graph in rendering
|
|
* @type {Number}
|
|
* @example index = 1
|
|
*/
|
|
index: 1,
|
|
|
|
/**
|
|
* @description Animation delay time(ms)
|
|
* @type {Number}
|
|
* @default animationDelay = 0
|
|
*/
|
|
animationDelay: 0,
|
|
|
|
/**
|
|
* @description Number of animation frames
|
|
* @type {Number}
|
|
* @default animationFrame = 30
|
|
*/
|
|
animationFrame: 30,
|
|
|
|
/**
|
|
* @description Animation dynamic curve (Supported by transition)
|
|
* @type {String}
|
|
* @default animationCurve = 'linear'
|
|
* @link https://github.com/jiaming743/Transition
|
|
*/
|
|
animationCurve: 'linear',
|
|
|
|
/**
|
|
* @description Weather to pause graph animation
|
|
* @type {Boolean}
|
|
* @default animationPause = false
|
|
*/
|
|
animationPause: false,
|
|
|
|
/**
|
|
* @description Rectangular hover detection zone
|
|
* Use this method for hover detection first
|
|
* @type {Null|Array}
|
|
* @default hoverRect = null
|
|
* @example hoverRect = [0, 0, 100, 100] // [Rect start x, y, Rect width, height]
|
|
*/
|
|
hoverRect: null,
|
|
|
|
/**
|
|
* @description Mouse enter event handler
|
|
* @type {Function|Null}
|
|
* @default mouseEnter = null
|
|
*/
|
|
mouseEnter: null,
|
|
|
|
/**
|
|
* @description Mouse outer event handler
|
|
* @type {Function|Null}
|
|
* @default mouseOuter = null
|
|
*/
|
|
mouseOuter: null,
|
|
|
|
/**
|
|
* @description Mouse click event handler
|
|
* @type {Function|Null}
|
|
* @default click = null
|
|
*/
|
|
click: null
|
|
};
|
|
var configAbleNot = {
|
|
status: 'static',
|
|
animationRoot: [],
|
|
animationKeys: [],
|
|
animationFrameState: [],
|
|
cache: {}
|
|
};
|
|
if (!config.shape) config.shape = {};
|
|
if (!config.style) config.style = {};
|
|
var shape = Object.assign({}, graph.shape, config.shape);
|
|
Object.assign(defaultConfig, config, configAbleNot);
|
|
Object.assign(this, graph, defaultConfig);
|
|
this.shape = shape;
|
|
this.style = new _style["default"](config.style);
|
|
this.addedProcessor();
|
|
};
|
|
/**
|
|
* @description Processor of added
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
exports["default"] = Graph;
|
|
|
|
Graph.prototype.addedProcessor = function () {
|
|
if (typeof this.setGraphCenter === 'function') this.setGraphCenter(null, this); // The life cycle 'added"
|
|
|
|
if (typeof this.added === 'function') this.added(this);
|
|
};
|
|
/**
|
|
* @description Processor of draw
|
|
* @param {CRender} render Instance of CRender
|
|
* @param {Graph} graph Instance of Graph
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.drawProcessor = function (render, graph) {
|
|
var ctx = render.ctx;
|
|
graph.style.initStyle(ctx);
|
|
if (typeof this.beforeDraw === 'function') this.beforeDraw(this, render);
|
|
graph.draw(render, graph);
|
|
if (typeof this.drawed === 'function') this.drawed(this, render);
|
|
graph.style.restoreTransform(ctx);
|
|
};
|
|
/**
|
|
* @description Processor of hover check
|
|
* @param {Array} position Mouse Position
|
|
* @param {Graph} graph Instance of Graph
|
|
* @return {Boolean} Result of hover check
|
|
*/
|
|
|
|
|
|
Graph.prototype.hoverCheckProcessor = function (position, _ref) {
|
|
var hoverRect = _ref.hoverRect,
|
|
style = _ref.style,
|
|
hoverCheck = _ref.hoverCheck;
|
|
var graphCenter = style.graphCenter,
|
|
rotate = style.rotate,
|
|
scale = style.scale,
|
|
translate = style.translate;
|
|
|
|
if (graphCenter) {
|
|
if (rotate) position = (0, _util.getRotatePointPos)(-rotate, position, graphCenter);
|
|
if (scale) position = (0, _util.getScalePointPos)(scale.map(function (s) {
|
|
return 1 / s;
|
|
}), position, graphCenter);
|
|
if (translate) position = (0, _util.getTranslatePointPos)(translate.map(function (v) {
|
|
return v * -1;
|
|
}), position);
|
|
}
|
|
|
|
if (hoverRect) return _util.checkPointIsInRect.apply(void 0, [position].concat((0, _toConsumableArray2["default"])(hoverRect)));
|
|
return hoverCheck(position, this);
|
|
};
|
|
/**
|
|
* @description Processor of move
|
|
* @param {Event} e Mouse movement event
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.moveProcessor = function (e) {
|
|
this.move(e, this);
|
|
if (typeof this.beforeMove === 'function') this.beforeMove(e, this);
|
|
if (typeof this.setGraphCenter === 'function') this.setGraphCenter(e, this);
|
|
if (typeof this.moved === 'function') this.moved(e, this);
|
|
};
|
|
/**
|
|
* @description Update graph state
|
|
* @param {String} attrName Updated attribute name
|
|
* @param {Any} change Updated value
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.attr = function (attrName) {
|
|
var change = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : undefined;
|
|
if (!attrName || change === undefined) return false;
|
|
var isObject = (0, _typeof2["default"])(this[attrName]) === 'object';
|
|
if (isObject) change = (0, _util.deepClone)(change, true);
|
|
var render = this.render;
|
|
|
|
if (attrName === 'style') {
|
|
this.style.update(change);
|
|
} else if (isObject) {
|
|
Object.assign(this[attrName], change);
|
|
} else {
|
|
this[attrName] = change;
|
|
}
|
|
|
|
if (attrName === 'index') render.sortGraphsByIndex();
|
|
render.drawAllGraph();
|
|
};
|
|
/**
|
|
* @description Update graphics state (with animation)
|
|
* Only shape and style attributes are supported
|
|
* @param {String} attrName Updated attribute name
|
|
* @param {Any} change Updated value
|
|
* @param {Boolean} wait Whether to store the animation waiting
|
|
* for the next animation request
|
|
* @return {Promise} Animation Promise
|
|
*/
|
|
|
|
|
|
Graph.prototype.animation =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref2 = (0, _asyncToGenerator2["default"])(
|
|
/*#__PURE__*/
|
|
_regenerator["default"].mark(function _callee2(attrName, change) {
|
|
var wait,
|
|
changeRoot,
|
|
changeKeys,
|
|
beforeState,
|
|
animationFrame,
|
|
animationCurve,
|
|
animationDelay,
|
|
animationFrameState,
|
|
render,
|
|
_args2 = arguments;
|
|
return _regenerator["default"].wrap(function _callee2$(_context2) {
|
|
while (1) {
|
|
switch (_context2.prev = _context2.next) {
|
|
case 0:
|
|
wait = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : false;
|
|
|
|
if (!(attrName !== 'shape' && attrName !== 'style')) {
|
|
_context2.next = 4;
|
|
break;
|
|
}
|
|
|
|
console.error('Only supported shape and style animation!');
|
|
return _context2.abrupt("return");
|
|
|
|
case 4:
|
|
change = (0, _util.deepClone)(change, true);
|
|
if (attrName === 'style') this.style.colorProcessor(change);
|
|
changeRoot = this[attrName];
|
|
changeKeys = Object.keys(change);
|
|
beforeState = {};
|
|
changeKeys.forEach(function (key) {
|
|
return beforeState[key] = changeRoot[key];
|
|
});
|
|
animationFrame = this.animationFrame, animationCurve = this.animationCurve, animationDelay = this.animationDelay;
|
|
animationFrameState = (0, _transition["default"])(animationCurve, beforeState, change, animationFrame, true);
|
|
this.animationRoot.push(changeRoot);
|
|
this.animationKeys.push(changeKeys);
|
|
this.animationFrameState.push(animationFrameState);
|
|
|
|
if (!wait) {
|
|
_context2.next = 17;
|
|
break;
|
|
}
|
|
|
|
return _context2.abrupt("return");
|
|
|
|
case 17:
|
|
if (!(animationDelay > 0)) {
|
|
_context2.next = 20;
|
|
break;
|
|
}
|
|
|
|
_context2.next = 20;
|
|
return delay(animationDelay);
|
|
|
|
case 20:
|
|
render = this.render;
|
|
return _context2.abrupt("return", new Promise(
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref3 = (0, _asyncToGenerator2["default"])(
|
|
/*#__PURE__*/
|
|
_regenerator["default"].mark(function _callee(resolve) {
|
|
return _regenerator["default"].wrap(function _callee$(_context) {
|
|
while (1) {
|
|
switch (_context.prev = _context.next) {
|
|
case 0:
|
|
_context.next = 2;
|
|
return render.launchAnimation();
|
|
|
|
case 2:
|
|
resolve();
|
|
|
|
case 3:
|
|
case "end":
|
|
return _context.stop();
|
|
}
|
|
}
|
|
}, _callee);
|
|
}));
|
|
|
|
return function (_x3) {
|
|
return _ref3.apply(this, arguments);
|
|
};
|
|
}()));
|
|
|
|
case 22:
|
|
case "end":
|
|
return _context2.stop();
|
|
}
|
|
}
|
|
}, _callee2, this);
|
|
}));
|
|
|
|
return function (_x, _x2) {
|
|
return _ref2.apply(this, arguments);
|
|
};
|
|
}();
|
|
/**
|
|
* @description Extract the next frame of data from the animation queue
|
|
* and update the graph state
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.turnNextAnimationFrame = function (timeStamp) {
|
|
var animationDelay = this.animationDelay,
|
|
animationRoot = this.animationRoot,
|
|
animationKeys = this.animationKeys,
|
|
animationFrameState = this.animationFrameState,
|
|
animationPause = this.animationPause;
|
|
if (animationPause) return;
|
|
if (Date.now() - timeStamp < animationDelay) return;
|
|
animationRoot.forEach(function (root, i) {
|
|
animationKeys[i].forEach(function (key) {
|
|
root[key] = animationFrameState[i][0][key];
|
|
});
|
|
});
|
|
animationFrameState.forEach(function (stateItem, i) {
|
|
stateItem.shift();
|
|
var noFrame = stateItem.length === 0;
|
|
if (noFrame) animationRoot[i] = null;
|
|
if (noFrame) animationKeys[i] = null;
|
|
});
|
|
this.animationFrameState = animationFrameState.filter(function (state) {
|
|
return state.length;
|
|
});
|
|
this.animationRoot = animationRoot.filter(function (root) {
|
|
return root;
|
|
});
|
|
this.animationKeys = animationKeys.filter(function (keys) {
|
|
return keys;
|
|
});
|
|
};
|
|
/**
|
|
* @description Skip to the last frame of animation
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.animationEnd = function () {
|
|
var animationFrameState = this.animationFrameState,
|
|
animationKeys = this.animationKeys,
|
|
animationRoot = this.animationRoot,
|
|
render = this.render;
|
|
animationRoot.forEach(function (root, i) {
|
|
var currentKeys = animationKeys[i];
|
|
var lastState = animationFrameState[i].pop();
|
|
currentKeys.forEach(function (key) {
|
|
return root[key] = lastState[key];
|
|
});
|
|
});
|
|
this.animationFrameState = [];
|
|
this.animationKeys = [];
|
|
this.animationRoot = [];
|
|
return render.drawAllGraph();
|
|
};
|
|
/**
|
|
* @description Pause animation behavior
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.pauseAnimation = function () {
|
|
this.attr('animationPause', true);
|
|
};
|
|
/**
|
|
* @description Try animation behavior
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.playAnimation = function () {
|
|
var render = this.render;
|
|
this.attr('animationPause', false);
|
|
return new Promise(
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _ref4 = (0, _asyncToGenerator2["default"])(
|
|
/*#__PURE__*/
|
|
_regenerator["default"].mark(function _callee3(resolve) {
|
|
return _regenerator["default"].wrap(function _callee3$(_context3) {
|
|
while (1) {
|
|
switch (_context3.prev = _context3.next) {
|
|
case 0:
|
|
_context3.next = 2;
|
|
return render.launchAnimation();
|
|
|
|
case 2:
|
|
resolve();
|
|
|
|
case 3:
|
|
case "end":
|
|
return _context3.stop();
|
|
}
|
|
}
|
|
}, _callee3);
|
|
}));
|
|
|
|
return function (_x4) {
|
|
return _ref4.apply(this, arguments);
|
|
};
|
|
}());
|
|
};
|
|
/**
|
|
* @description Processor of delete
|
|
* @param {CRender} render Instance of CRender
|
|
* @return {Undefined} Void
|
|
*/
|
|
|
|
|
|
Graph.prototype.delProcessor = function (render) {
|
|
var _this = this;
|
|
|
|
var graphs = render.graphs;
|
|
var index = graphs.findIndex(function (graph) {
|
|
return graph === _this;
|
|
});
|
|
if (index === -1) return;
|
|
if (typeof this.beforeDelete === 'function') this.beforeDelete(this);
|
|
graphs.splice(index, 1, null);
|
|
if (typeof this.deleted === 'function') this.deleted(this);
|
|
};
|
|
/**
|
|
* @description Return a timed release Promise
|
|
* @param {Number} time Release time
|
|
* @return {Promise} A timed release Promise
|
|
*/
|
|
|
|
|
|
function delay(time) {
|
|
return new Promise(function (resolve) {
|
|
setTimeout(resolve, time);
|
|
});
|
|
} |