@jiaminghi/c-render
Version:
Canvas-based vector graphics rendering plugin
1,741 lines (1,511 loc) • 418 kB
JavaScript
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
var CRender = require('../lib/index')
window.CRender = CRender
},{"../lib/index":6}],2:[function(require,module,exports){
"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 _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _color = _interopRequireDefault(require("@jiaminghi/color"));
var _bezierCurve = _interopRequireDefault(require("@jiaminghi/bezier-curve"));
var _util = require("../plugin/util");
var _graphs = _interopRequireDefault(require("../config/graphs"));
var _graph = _interopRequireDefault(require("./graph.class"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
/**
* @description Class of CRender
* @param {Object} canvas Canvas DOM
* @return {CRender} Instance of CRender
*/
var CRender = function CRender(canvas) {
(0, _classCallCheck2["default"])(this, CRender);
if (!canvas) {
console.error('CRender Missing parameters!');
return;
}
var ctx = canvas.getContext('2d');
var clientWidth = canvas.clientWidth,
clientHeight = canvas.clientHeight;
var area = [clientWidth, clientHeight];
canvas.setAttribute('width', clientWidth);
canvas.setAttribute('height', clientHeight);
/**
* @description Context of the canvas
* @type {Object}
* @example ctx = canvas.getContext('2d')
*/
this.ctx = ctx;
/**
* @description Width and height of the canvas
* @type {Array}
* @example area = [300,100]
*/
this.area = area;
/**
* @description Whether render is in animation rendering
* @type {Boolean}
* @example animationStatus = true|false
*/
this.animationStatus = false;
/**
* @description Added graph
* @type {[Graph]}
* @example graphs = [Graph, Graph, ...]
*/
this.graphs = [];
/**
* @description Color plugin
* @type {Object}
* @link https://github.com/jiaming743/color
*/
this.color = _color["default"];
/**
* @description Bezier Curve plugin
* @type {Object}
* @link https://github.com/jiaming743/BezierCurve
*/
this.bezierCurve = _bezierCurve["default"]; // bind event handler
canvas.addEventListener('mousedown', mouseDown.bind(this));
canvas.addEventListener('mousemove', mouseMove.bind(this));
canvas.addEventListener('mouseup', mouseUp.bind(this));
};
/**
* @description Clear canvas drawing area
* @return {Undefined} Void
*/
exports["default"] = CRender;
CRender.prototype.clearArea = function () {
var _this$ctx;
var area = this.area;
(_this$ctx = this.ctx).clearRect.apply(_this$ctx, [0, 0].concat((0, _toConsumableArray2["default"])(area)));
};
/**
* @description Add graph to render
* @param {Object} config Graph configuration
* @return {Graph} Graph instance
*/
CRender.prototype.add = function () {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var name = config.name;
if (!name) {
console.error('add Missing parameters!');
return;
}
var graphConfig = _graphs["default"].get(name);
if (!graphConfig) {
console.warn('No corresponding graph configuration found!');
return;
}
var graph = new _graph["default"](graphConfig, config);
if (!graph.validator(graph)) return;
graph.render = this;
this.graphs.push(graph);
this.sortGraphsByIndex();
this.drawAllGraph();
return graph;
};
/**
* @description Sort the graph by index
* @return {Undefined} Void
*/
CRender.prototype.sortGraphsByIndex = function () {
var graphs = this.graphs;
graphs.sort(function (a, b) {
if (a.index > b.index) return 1;
if (a.index === b.index) return 0;
if (a.index < b.index) return -1;
});
};
/**
* @description Delete graph in render
* @param {Graph} graph The graph to be deleted
* @return {Undefined} Void
*/
CRender.prototype.delGraph = function (graph) {
if (typeof graph.delProcessor !== 'function') return;
graph.delProcessor(this);
this.graphs = this.graphs.filter(function (graph) {
return graph;
});
this.drawAllGraph();
};
/**
* @description Delete all graph in render
* @return {Undefined} Void
*/
CRender.prototype.delAllGraph = function () {
var _this = this;
this.graphs.forEach(function (graph) {
return graph.delProcessor(_this);
});
this.graphs = this.graphs.filter(function (graph) {
return graph;
});
this.drawAllGraph();
};
/**
* @description Draw all the graphs in the render
* @return {Undefined} Void
*/
CRender.prototype.drawAllGraph = function () {
var _this2 = this;
this.clearArea();
this.graphs.filter(function (graph) {
return graph && graph.visible;
}).forEach(function (graph) {
return graph.drawProcessor(_this2, graph);
});
};
/**
* @description Animate the graph whose animation queue is not empty
* and the animationPause is equal to false
* @return {Promise} Animation Promise
*/
CRender.prototype.launchAnimation = function () {
var _this3 = this;
var animationStatus = this.animationStatus;
if (animationStatus) return;
this.animationStatus = true;
return new Promise(function (resolve) {
animation.call(_this3, function () {
_this3.animationStatus = false;
resolve();
}, Date.now());
});
};
/**
* @description Try to animate every graph
* @param {Function} callback Callback in animation end
* @param {Number} timeStamp Time stamp of animation start
* @return {Undefined} Void
*/
function animation(callback, timeStamp) {
var graphs = this.graphs;
if (!animationAble(graphs)) {
callback();
return;
}
graphs.forEach(function (graph) {
return graph.turnNextAnimationFrame(timeStamp);
});
this.drawAllGraph();
requestAnimationFrame(animation.bind(this, callback, timeStamp));
}
/**
* @description Find if there are graph that can be animated
* @param {[Graph]} graphs
* @return {Boolean}
*/
function animationAble(graphs) {
return graphs.find(function (graph) {
return !graph.animationPause && graph.animationFrameState.length;
});
}
/**
* @description Handler of CRender mousedown event
* @return {Undefined} Void
*/
function mouseDown(e) {
var graphs = this.graphs;
var hoverGraph = graphs.find(function (graph) {
return graph.status === 'hover';
});
if (!hoverGraph) return;
hoverGraph.status = 'active';
}
/**
* @description Handler of CRender mousemove event
* @return {Undefined} Void
*/
function mouseMove(e) {
var offsetX = e.offsetX,
offsetY = e.offsetY;
var position = [offsetX, offsetY];
var graphs = this.graphs;
var activeGraph = graphs.find(function (graph) {
return graph.status === 'active' || graph.status === 'drag';
});
if (activeGraph) {
if (!activeGraph.drag) return;
if (typeof activeGraph.move !== 'function') {
console.error('No move method is provided, cannot be dragged!');
return;
}
activeGraph.moveProcessor(e);
activeGraph.status = 'drag';
return;
}
var hoverGraph = graphs.find(function (graph) {
return graph.status === 'hover';
});
var hoverAbleGraphs = graphs.filter(function (graph) {
return graph.hover && (typeof graph.hoverCheck === 'function' || graph.hoverRect);
});
var hoveredGraph = hoverAbleGraphs.find(function (graph) {
return graph.hoverCheckProcessor(position, graph);
});
if (hoveredGraph) {
document.body.style.cursor = hoveredGraph.style.hoverCursor;
} else {
document.body.style.cursor = 'default';
}
var hoverGraphMouseOuterIsFun = false,
hoveredGraphMouseEnterIsFun = false;
if (hoverGraph) hoverGraphMouseOuterIsFun = typeof hoverGraph.mouseOuter === 'function';
if (hoveredGraph) hoveredGraphMouseEnterIsFun = typeof hoveredGraph.mouseEnter === 'function';
if (!hoveredGraph && !hoverGraph) return;
if (!hoveredGraph && hoverGraph) {
if (hoverGraphMouseOuterIsFun) hoverGraph.mouseOuter(e, hoverGraph);
hoverGraph.status = 'static';
return;
}
if (hoveredGraph && hoveredGraph === hoverGraph) return;
if (hoveredGraph && !hoverGraph) {
if (hoveredGraphMouseEnterIsFun) hoveredGraph.mouseEnter(e, hoveredGraph);
hoveredGraph.status = 'hover';
return;
}
if (hoveredGraph && hoverGraph && hoveredGraph !== hoverGraph) {
if (hoverGraphMouseOuterIsFun) hoverGraph.mouseOuter(e, hoverGraph);
hoverGraph.status = 'static';
if (hoveredGraphMouseEnterIsFun) hoveredGraph.mouseEnter(e, hoveredGraph);
hoveredGraph.status = 'hover';
}
}
/**
* @description Handler of CRender mouseup event
* @return {Undefined} Void
*/
function mouseUp(e) {
var graphs = this.graphs;
var activeGraph = graphs.find(function (graph) {
return graph.status === 'active';
});
var dragGraph = graphs.find(function (graph) {
return graph.status === 'drag';
});
if (activeGraph && typeof activeGraph.click === 'function') activeGraph.click(e, activeGraph);
graphs.forEach(function (graph) {
return graph && (graph.status = 'static');
});
if (activeGraph) activeGraph.status = 'hover';
if (dragGraph) dragGraph.status = 'hover';
}
/**
* @description Clone Graph
* @param {Graph} graph The target to be cloned
* @return {Graph} Cloned graph
*/
CRender.prototype.clone = function (graph) {
var style = graph.style.getStyle();
var clonedGraph = _objectSpread({}, graph, {
style: style
});
delete clonedGraph.render;
clonedGraph = (0, _util.deepClone)(clonedGraph, true);
return this.add(clonedGraph);
};
},{"../config/graphs":5,"../plugin/util":8,"./graph.class":3,"@babel/runtime/helpers/classCallCheck":12,"@babel/runtime/helpers/defineProperty":13,"@babel/runtime/helpers/interopRequireDefault":14,"@babel/runtime/helpers/toConsumableArray":20,"@jiaminghi/bezier-curve":25,"@jiaminghi/color":27}],3:[function(require,module,exports){
"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);
});
}
},{"../plugin/util":8,"./style.class":4,"@babel/runtime/helpers/asyncToGenerator":11,"@babel/runtime/helpers/classCallCheck":12,"@babel/runtime/helpers/interopRequireDefault":14,"@babel/runtime/helpers/toConsumableArray":20,"@babel/runtime/helpers/typeof":21,"@babel/runtime/regenerator":22,"@jiaminghi/transition":29}],4:[function(require,module,exports){
"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 _color = require("@jiaminghi/color");
var _util = require("../plugin/util");
/**
* @description Class Style
* @param {Object} style Style configuration
* @return {Style} Instance of Style
*/
var Style = function Style(style) {
(0, _classCallCheck2["default"])(this, Style);
this.colorProcessor(style);
var defaultStyle = {
/**
* @description Rgba value of graph fill color
* @type {Array}
* @default fill = [0, 0, 0, 1]
*/
fill: [0, 0, 0, 1],
/**
* @description Rgba value of graph stroke color
* @type {Array}
* @default stroke = [0, 0, 0, 1]
*/
stroke: [0, 0, 0, 0],
/**
* @description Opacity of graph
* @type {Number}
* @default opacity = 1
*/
opacity: 1,
/**
* @description LineCap of Ctx
* @type {String}
* @default lineCap = null
* @example lineCap = 'butt'|'round'|'square'
*/
lineCap: null,
/**
* @description Linejoin of Ctx
* @type {String}
* @default lineJoin = null
* @example lineJoin = 'round'|'bevel'|'miter'
*/
lineJoin: null,
/**
* @description LineDash of Ctx
* @type {Array}
* @default lineDash = null
* @example lineDash = [10, 10]
*/
lineDash: null,
/**
* @description LineDashOffset of Ctx
* @type {Number}
* @default lineDashOffset = null
* @example lineDashOffset = 10
*/
lineDashOffset: null,
/**
* @description ShadowBlur of Ctx
* @type {Number}
* @default shadowBlur = 0
*/
shadowBlur: 0,
/**
* @description Rgba value of graph shadow color
* @type {Array}
* @default shadowColor = [0, 0, 0, 0]
*/
shadowColor: [0, 0, 0, 0],
/**
* @description ShadowOffsetX of Ctx
* @type {Number}
* @default shadowOffsetX = 0
*/
shadowOffsetX: 0,
/**
* @description ShadowOffsetY of Ctx
* @type {Number}
* @default shadowOffsetY = 0
*/
shadowOffsetY: 0,
/**
* @description LineWidth of Ctx
* @type {Number}
* @default lineWidth = 0
*/
lineWidth: 0,
/**
* @description Center point of the graph
* @type {Array}
* @default graphCenter = null
* @example graphCenter = [10, 10]
*/
graphCenter: null,
/**
* @description Graph scale
* @type {Array}
* @default scale = null
* @example scale = [1.5, 1.5]
*/
scale: null,
/**
* @description Graph rotation degree
* @type {Number}
* @default rotate = null
* @example rotate = 10
*/
rotate: null,
/**
* @description Graph translate distance
* @type {Array}
* @default translate = null
* @example translate = [10, 10]
*/
translate: null,
/**
* @description Cursor status when hover
* @type {String}
* @default hoverCursor = 'pointer'
* @example hoverCursor = 'default'|'pointer'|'auto'|'crosshair'|'move'|'wait'|...
*/
hoverCursor: 'pointer',
/**
* @description Font style of Ctx
* @type {String}
* @default fontStyle = 'normal'
* @example fontStyle = 'normal'|'italic'|'oblique'
*/
fontStyle: 'normal',
/**
* @description Font varient of Ctx
* @type {String}
* @default fontVarient = 'normal'
* @example fontVarient = 'normal'|'small-caps'
*/
fontVarient: 'normal',
/**
* @description Font weight of Ctx
* @type {String|Number}
* @default fontWeight = 'normal'
* @example fontWeight = 'normal'|'bold'|'bolder'|'lighter'|Number
*/
fontWeight: 'normal',
/**
* @description Font size of Ctx
* @type {Number}
* @default fontSize = 10
*/
fontSize: 10,
/**
* @description Font family of Ctx
* @type {String}
* @default fontFamily = 'Arial'
*/
fontFamily: 'Arial',
/**
* @description TextAlign of Ctx
* @type {String}
* @default textAlign = 'center'
* @example textAlign = 'start'|'end'|'left'|'right'|'center'
*/
textAlign: 'center',
/**
* @description TextBaseline of Ctx
* @type {String}
* @default textBaseline = 'middle'
* @example textBaseline = 'top'|'bottom'|'middle'|'alphabetic'|'hanging'
*/
textBaseline: 'middle',
/**
* @description The color used to create the gradient
* @type {Array}
* @default gradientColor = null
* @example gradientColor = ['#000', '#111', '#222']
*/
gradientColor: null,
/**
* @description Gradient type
* @type {String}
* @default gradientType = 'linear'
* @example gradientType = 'linear' | 'radial'
*/
gradientType: 'linear',
/**
* @description Gradient params
* @type {Array}
* @default gradientParams = null
* @example gradientParams = [x0, y0, x1, y1] (Linear Gradient)
* @example gradientParams = [x0, y0, r0, x1, y1, r1] (Radial Gradient)
*/
gradientParams: null,
/**
* @description When to use gradients
* @type {String}
* @default gradientWith = 'stroke'
* @example gradientWith = 'stroke' | 'fill'
*/
gradientWith: 'stroke',
/**
* @description Gradient color stops
* @type {String}
* @default gradientStops = 'auto'
* @example gradientStops = 'auto' | [0, .2, .3, 1]
*/
gradientStops: 'auto',
/**
* @description Extended color that supports animation transition
* @type {Array|Object}
* @default colors = null
* @example colors = ['#000', '#111', '#222', 'red' ]
* @example colors = { a: '#000', b: '#111' }
*/
colors: null
};
Object.assign(this, defaultStyle, style);
};
/**
* @description Set colors to rgba value
* @param {Object} style style config
* @param {Boolean} reverse Whether to perform reverse operation
* @return {Undefined} Void
*/
exports["default"] = Style;
Style.prototype.colorProcessor = function (style) {
var reverse = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var processor = reverse ? _color.getColorFromRgbValue : _color.getRgbaValue;
var colorProcessorKeys = ['fill', 'stroke', 'shadowColor'];
var allKeys = Object.keys(style);
var colorKeys = allKeys.filter(function (key) {
return colorProcessorKeys.find(function (k) {
return k === key;
});
});
colorKeys.forEach(function (key) {
return style[key] = processor(style[key]);
});
var gradientColor = style.gradientColor,
colors = style.colors;
if (gradientColor) style.gradientColor = gradientColor.map(function (c) {
return processor(c);
});
if (colors) {
var colorsKeys = Object.keys(colors);
colorsKeys.forEach(function (key) {
return colors[key] = processor(colors[key]);
});
}
};
/**
* @description Init graph style
* @param {Object} ctx Context of canvas
* @return {Undefined} Void
*/
Style.prototype.initStyle = function (ctx) {
initTransform(ctx, this);
initGraphStyle(ctx, this);
initGradient(ctx, this);
};
/**
* @description Init canvas transform
* @param {Object} ctx Context of canvas
* @param {Style} style Instance of Style
* @return {Undefined} Void
*/
function initTransform(ctx, style) {
ctx.save();
var graphCenter = style.graphCenter,
rotate = style.rotate,
scale = style.scale,
translate = style.translate;
if (!(graphCenter instanceof Array)) return;
ctx.translate.apply(ctx, (0, _toConsumableArray2["default"])(graphCenter));
if (rotate) ctx.rotate(rotate * Math.PI / 180);
if (scale instanceof Array) ctx.scale.apply(ctx, (0, _toConsumableArray2["default"])(scale));
if (translate) ctx.translate.apply(ctx, (0, _toConsumableArray2["default"])(translate));
ctx.translate(-graphCenter[0], -graphCenter[1]);
}
var autoSetStyleKeys = ['lineCap', 'lineJoin', 'lineDashOffset', 'shadowOffsetX', 'shadowOffsetY', 'lineWidth', 'textAlign', 'textBaseline'];
/**
* @description Set the style of canvas ctx
* @param {Object} ctx Context of canvas
* @param {Style} style Instance of Style
* @return {Undefined} Void
*/
function initGraphStyle(ctx, style) {
var fill = style.fill,
stroke = style.stroke,
shadowColor = style.shadowColor,
opacity = style.opacity;
autoSetStyleKeys.forEach(function (key) {
if (key || typeof key === 'number') ctx[key] = style[key];
});
fill = (0, _toConsumableArray2["default"])(fill);
stroke = (0, _toConsumableArray2["default"])(stroke);
shadowColor = (0, _toConsumableArray2["default"])(shadowColor);
fill[3] *= opacity;
stroke[3] *= opacity;
shadowColor[3] *= opacity;
ctx.fillStyle = (0, _color.getColorFromRgbValue)(fill);
ctx.strokeStyle = (0, _color.getColorFromRgbValue)(stroke);
ctx.shadowColor = (0, _color.getColorFromRgbValue)(shadowColor);
var lineDash = style.lineDash,
shadowBlur = style.shadowBlur;
if (lineDash) {
lineDash = lineDash.map(function (v) {
return v >= 0 ? v : 0;
});
ctx.setLineDash(lineDash);
}
if (typeof shadowBlur === 'number') ctx.shadowBlur = shadowBlur > 0 ? shadowBlur : 0.001;
var fontStyle = style.fontStyle,
fontVarient = style.fontVarient,
fontWeight = style.fontWeight,
fontSize = style.fontSize,
fontFamily = style.fontFamily;
ctx.font = fontStyle + ' ' + fontVarient + ' ' + fontWeight + ' ' + fontSize + 'px' + ' ' + fontFamily;
}
/**
* @description Set the gradient color of canvas ctx
* @param {Object} ctx Context of canvas
* @param {Style} style Instance of Style
* @return {Undefined} Void
*/
function initGradient(ctx, style) {
if (!gradientValidator(style)) return;
var gradientColor = style.gradientColor,
gradientParams = style.gradientParams,
gradientType = style.gradientType,
gradientWith = style.gradientWith,
gradientStops = style.gradientStops,
opacity = style.opacity;
gradientColor = gradientColor.map(function (color) {
var colorOpacity = color[3] * opacity;
var clonedColor = (0, _toConsumableArray2["default"])(color);
clonedColor[3] = colorOpacity;
return clonedColor;
});
gradientColor = gradientColor.map(function (c) {
return (0, _color.getColorFromRgbValue)(c);
});
if (gradientStops === 'auto') gradientStops = getAutoColorStops(gradientColor);
var gradient = ctx["create".concat(gradientType.slice(0, 1).toUpperCase() + gradientType.slice(1), "Gradient")].apply(ctx, (0, _toConsumableArray2["default"])(gradientParams));
gradientStops.forEach(function (stop, i) {
return gradient.addColorStop(stop, gradientColor[i]);
});
ctx["".concat(gradientWith, "Style")] = gradient;
}
/**
* @description Check if the gradient configuration is legal
* @param {Style} style Instance of Style
* @return {Boolean} Check Result
*/
function gradientValidator(style) {
var gradientColor = style.gradientColor,
gradientParams = style.gradientParams,
gradientType = style.gradientType,
gradientWith = style.gradientWith,
gradientStops = style.gradientStops;
if (!gradientColor || !gradientParams) return false;
if (gradientColor.length === 1) {
console.warn('The gradient needs to provide at least two colors');
return false;
}
if (gradientType !== 'linear' && gradientType !== 'radial') {
console.warn('GradientType only supports linear or radial, current value is ' + gradientType);
return false;
}
var gradientParamsLength = gradientParams.length;
if (gradientType === 'linear' && gradientParamsLength !== 4 || gradientType === 'radial' && gradientParamsLength !== 6) {
console.warn('The expected length of gradientParams is ' + (gradientType === 'linear' ? '4' : '6'));
return false;
}
if (gradientWith !== 'fill' && gradientWith !== 'stroke') {
console.warn('GradientWith only supports fill or stroke, current value is ' + gradientWith);
return false;
}
if (gradientStops !== 'auto' && !(gradientStops instanceof Array)) {
console.warn("gradientStops only supports 'auto' or Number Array ([0, .5, 1]), current value is " + gradientStops);
return false;
}
return true;
}
/**
* @description Get a uniform gradient color stop
* @param {Array} color Gradient color
* @return {Array} Gradient color stop
*/
function getAutoColorStops(color) {
var stopGap = 1 / (color.length - 1);
return color.map(function (foo, i) {
return stopGap * i;
});
}
/**
* @description Restore canvas ctx transform
* @param {Object} ctx Context of canvas
* @return {Undefined} Void
*/
Style.prototype.restoreTransform = function (ctx) {
ctx.restore();
};
/**
* @description Update style data
* @param {Object} change Changed data
* @return {Undefined} Void
*/
Style.prototype.update = function (change) {
this.colorProcessor(change);
Object.assign(this, change);
};
/**
* @description Get the current style configuration
* @return {Object} Style configuration
*/
Style.prototype.getStyle = function () {
var clonedStyle = (0, _util.deepClone)(this, true);
this.colorProcessor(clonedStyle, true);
return clonedStyle;
};
},{"../plugin/util":8,"@babel/runtime/helpers/classCallCheck":12,"@babel/runtime/helpers/interopRequireDefault":14,"@babel/runtime/helpers/toConsumableArray":20,"@jiaminghi/color":27}],5:[function(require,module,exports){
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.extendNewGraph = extendNewGraph;
exports["default"] = exports.text = exports.bezierCurve = exports.smoothline = exports.polyline = exports.regPolygon = exports.sector = exports.arc = exports.ring = exports.rect = exports.ellipse = exports.circle = void 0;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _bezierCurve2 = _interopRequireDefault(require("@jiaminghi/bezier-curve"));
var _util = require("../plugin/util");
var _canvas = require("../plugin/canvas");
var polylineToBezierCurve = _bezierCurve2["default"].polylineToBezierCurve,
bezierCurveToPolyline = _bezierCurve2["default"].bezierCurveToPolyline;
var circle = {
shape: {
rx: 0,
ry: 0,
r: 0
},
validator: function validator(_ref) {
var shape = _ref.shape;
var rx = shape.rx,
ry = shape.ry,
r = shape.r;
if (typeof rx !== 'number' || typeof ry !== 'number' || typeof r !== 'number') {
console.error('Circle shape configuration is abnormal!');
return false;
}
return true;
},
draw: function draw(_ref2, _ref3) {
var ctx = _ref2.ctx;
var shape = _ref3.shape;
ctx.beginPath();
var rx = shape.rx,
ry = shape.ry,
r = shape.r;
ctx.arc(rx, ry, r > 0 ? r : 0.01, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
},
hoverCheck: function hoverCheck(position, _ref4) {
var shape = _ref4.shape;
var rx = shape.rx,
ry = shape.ry,
r = shape.r;
return (0, _util.checkPointIsInCircle)(position, rx, ry, r);
},
setGraphCenter: function setGraphCenter(e, _ref5) {
var shape = _ref5.shape,
style = _ref5.style;
var rx = shape.rx,
ry = shape.ry;
style.graphCenter = [rx, ry];
},
move: function move(_ref6, _ref7) {
var movementX = _ref6.movementX,
movementY = _ref6.movementY;
var shape = _ref7.shape;
this.attr('shape', {
rx: shape.rx + movementX,
ry: shape.ry + movementY
});
}
};
exports.circle = circle;
var ellipse = {
shape: {
rx: 0,
ry: 0,
hr: 0,
vr: 0
},
validator: function validator(_ref8) {
var shape = _ref8.shape;
var rx = shape.rx,
ry = shape.ry,
hr = shape.hr,
vr = shape.vr;
if (typeof rx !== 'number' || typeof ry !== 'number' || typeof hr !== 'number' || typeof vr !== 'number') {
console.error('Ellipse shape configuration is abnormal!');
return false;
}
return true;
},
draw: function draw(_ref9, _ref10) {
var ctx = _ref9.ctx;
var shape = _ref10.shape;
ctx.beginPath();
var rx = shape.rx,
ry = shape.ry,
hr = shape.hr,
vr = shape.vr;
ctx.ellipse(rx, ry, hr > 0 ? hr : 0.01, vr > 0 ? vr : 0.01, 0, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
},
hoverCheck: function hoverCheck(position, _ref11) {
var shape = _ref11.shape;
var rx = shape.rx,
ry = shape.ry,
hr = shape.hr,
vr = shape.vr;
var a = Math.max(hr, vr);
var b = Math.min(hr, vr);
var c = Math.sqrt(a * a - b * b);
var leftFocusPoint = [rx - c, ry];
var rightFocusPoint = [rx + c, ry];
var distance = (0, _util.getTwoPointDistance)(position, leftFocusPoint) + (0, _util.getTwoPointDistance)(position, rightFocusPoint);
return distance <= 2 * a;
},
setGraphCenter: function setGraphCenter(e, _ref12) {
var shape = _ref12.shape,
style = _ref12.style;
var rx = shape.rx,
ry = shape.ry;
style.graphCenter = [rx, ry];
},
move: function move(_ref13, _ref14) {
var movementX = _ref13.movementX,
movementY = _ref13.movementY;
var shape = _ref14.shape;
this.attr('shape', {
rx: shape.rx + movementX,
ry: shape.ry + movementY
});
}
};
exports.ellipse = ellipse;
var rect = {
shape: {
x: 0,
y: 0,
w: 0,
h: 0
},
validator: function validator(_ref15) {
var shape = _ref15.shape;
var x = shape.x,
y = shape.y,
w = shape.w,
h = shape.h;
if (typeof x !== 'number' || typeof y !== 'number' || typeof w !== 'number' || typeof h !== 'number') {
console.error('Rect shape configuration is abnormal!');
return false;
}
return true;
},
draw: function draw(_ref16, _ref17) {
var ctx = _ref16.ctx;
var shape = _ref17.shape;
ctx.beginPath();
var x = shape.x,
y = shape.y,
w = shape.w,
h = shape.h;
ctx.rect(x, y, w, h);
ctx.fill();
ctx.stroke();
ctx.closePath();
},
hoverCheck: function hoverCheck(position, _ref18) {
var shape = _ref18.shape;
var x = shape.x,
y = shape.y,
w = shape.w,
h = shape.h;
return (0, _util.checkPointIsInRect)(position, x, y, w, h);
},
setGraphCenter: function setGraphCenter(e, _ref19) {
var shape = _ref19.shape,
style = _ref19.style;
var x = shape.x,
y = shape.y,
w = shape.w,
h = shape.h;
style.graphCenter = [x + w / 2, y + h / 2];
},
move: function move(_ref20, _ref21) {
var movementX = _ref20.movementX,
movementY = _ref20.movementY;
var shape = _ref21.shape;
this.attr('shape', {
x: shape.x + movementX,
y: shape.y + movementY
});
}
};
exports.rect = rect;
var ring = {
shape: {
rx: 0,
ry: 0,
r: 0
},
validator: function validator(_ref22) {
var shape = _ref22.shape;
var rx = shape.rx,
ry = shape.ry,
r = shape.r;
if (typeof rx !== 'number' || typeof ry !== 'number' || typeof r !== 'number') {
console.error('Ring shape configuration is abnormal!');
return false;
}
return true;
},
draw: function draw(_ref23, _ref24) {
var ctx = _ref23.ctx;
var shape = _ref24.shape;
ctx.beginPath();
var rx = shape.rx,
ry = shape.ry,
r = shape.r;
ctx.arc(rx, ry, r > 0 ? r : 0.01, 0, Math.PI * 2);
ctx.stroke();
ctx.closePath();
},
hoverCheck: function hoverCheck(position, _ref25) {
var shape = _ref25.shape,
style = _ref25.style;
var rx = shape.rx,
ry = shape.ry,
r = shape.r;
var lineWidth = style.lineWidth;
var halfLineWidth = lineWidth / 2;
var minDistance = r - halfLineWidth;
var maxDistance = r + halfLineWidth;
var distance = (0, _util.getTwoPointDistance)(position, [rx, ry]);
return distance >= minDistance && distance <= maxDistance;
},
setGraphCenter: function setGraphCenter(e, _ref26) {
var shape = _ref26.shape,
style = _ref26.style;
var rx = shape.rx,
ry = shape.ry;
style.graphCenter = [rx, ry];
},
move: function move(_ref27, _ref28) {
var movementX = _ref27.movementX,
movementY = _ref27.movementY;
var shape = _ref28.shape;
this.attr('shape', {
rx: shape.rx + movementX,
ry: shape.ry + movementY
});
}
};
exports.ring = ring;
var arc = {
shape: {
rx: 0,
ry: 0,
r: 0,
startAngle: 0,
endAngle: 0,
clockWise: true
},
validator: function validator(_ref29) {
var shape = _ref29.shape;
var keys = ['rx', 'ry', 'r', 'startAngle', 'endAngle'];
if (keys.find(function (key) {
return typeof shape[key] !== 'number';
})) {
console.error('Arc shape configuration is abnormal!');
return false;
}
return true;
},
draw: function draw(_ref30, _ref31) {
var ctx = _ref30.ctx;
var shape = _ref31.shape;
ctx.beginPath();
var rx = shape.rx,
ry = shape.ry,
r = shape.r,
startAngle = shape.startAngle,
endAngle = shape.endAngle,
clockWise = shape.clockWise;
ctx.arc(rx, ry, r > 0 ? r : 0.001, startAngle, endAngle, !clockWise);
ctx.stroke();
ctx.closePath();
},
hoverCheck: function hoverCheck(position, _ref32) {
var shape = _ref32.shape,
style = _ref32.style;
var rx = shape.rx,
ry = shape.ry,
r = shape.r,
startAngle = shape.startAngle,
endAngle = shape.endAngle,
clockWise = shape.clockWise;
var lineWidth = style.lineWidth;
var halfLineWidth = lineWidth / 2;
var insideRadius = r - halfLineWidth;
var outsideRadius = r + halfLineWidth;
return !(0, _util.checkPointIsInSector)(position, rx, ry, insideRadius, startAngle, endAngle, clockWise) && (0, _util.checkPointIsInSector)(position, rx, ry, outsideRadius, startAngle, endAngle, clockWise);
},
setGraphCenter: function setGraphCenter(e, _ref33) {
var shape = _ref33.shape,
style = _ref33.style;
var rx = shape.rx,
ry = shape.ry;
style.graphCenter = [rx, ry];
},
move: function move(_ref34, _ref35) {
var movementX = _ref34.movementX,
movementY = _ref34.movementY;
var shape = _ref35.shape;
this.attr('shape', {
rx: shape.rx + movementX,
ry: shape.ry + movementY
});
}
};
exports.arc = arc;
var sector = {
shape: {
rx: 0,
ry: 0,
r: 0,
startAngle: 0,
endAngle: 0,
clockWise: true
},
validator: function validator(_ref36) {
var shape = _ref36.shape;
var keys = ['rx', 'ry', 'r', 'startAngle', 'endAngle'];
if (keys.find(function (key) {
return typeof shape[key] !== 'number';
})) {
console.error('Sector shape configuration is abnormal!');
return false;
}
return true;
},
draw: function draw(_ref37, _ref38) {
var ctx = _ref37.ctx;
var shape = _ref38.shape;
ctx.beginPath();
var rx = shape.rx,
ry = shape.ry,
r = shape.r,
startAngle = shape.startAngle,
endAngle = shape.endAngle,
clockWise = shape.clockWise;