light-chart
Version:
Charts for mobile visualization.
190 lines (161 loc) • 4.26 kB
JavaScript
const Util = require('../util/common');
const Container = require('./container');
const Group = require('./group');
const { requestAnimationFrame } = require('./util/requestAnimationFrame');
class Canvas {
get(name) {
return this._attrs[name];
}
set(name, value) {
this._attrs[name] = value;
}
constructor(cfg) {
this._attrs = Util.mix({
type: 'canvas',
children: []
}, cfg);
this._initPixelRatio();
this._initCanvas();
}
_initPixelRatio() {
const pixelRatio = this.get('pixelRatio');
if (!pixelRatio) {
this.set('pixelRatio', Util.getPixelRatio());
}
}
beforeDraw() {
const context = this._attrs.context;
const el = this._attrs.el;
!Util.isWx && !Util.isMy && context && context.clearRect(0, 0, el.width, el.height);
}
_initCanvas() {
const self = this;
const el = self.get('el');
const context = self.get('context');
let canvas;
if (context) { // CanvasRenderingContext2D
canvas = context.canvas;
} else if (Util.isString(el)) { // HTMLElement's id
canvas = Util.getDomById(el);
} else { // HTMLElement
canvas = el;
}
if (!canvas) {
throw new Error('Please specify the id or el of the chart!');
}
if (context && canvas && !canvas.getContext) {
canvas.getContext = function() {
return context;
};
}
let width = self.get('width');
if (!width) {
width = Util.getWidth(canvas);
}
let height = self.get('height');
if (!height) {
height = Util.getHeight(canvas);
}
self.set('canvas', this);
self.set('el', canvas);
self.set('context', context || canvas.getContext('2d'));
self.changeSize(width, height);
}
changeSize(width, height) {
const pixelRatio = this.get('pixelRatio');
const canvasDOM = this.get('el');
if (Util.isBrowser) {
canvasDOM.style.width = width + 'px';
canvasDOM.style.height = height + 'px';
}
if (!Util.isWx && !Util.isMy) {
canvasDOM.width = width * pixelRatio;
canvasDOM.height = height * pixelRatio;
if (pixelRatio !== 1) {
const ctx = this.get('context');
ctx.scale(pixelRatio, pixelRatio);
}
}
this.set('width', width);
this.set('height', height);
}
getWidth() {
const pixelRatio = this.get('pixelRatio');
const width = this.get('width');
return width * pixelRatio;
}
getHeight() {
const pixelRatio = this.get('pixelRatio');
const height = this.get('height');
return height * pixelRatio;
}
getPointByClient(clientX, clientY) {
const el = this.get('el');
const bbox = el.getBoundingClientRect();
const width = bbox.right - bbox.left;
const height = bbox.bottom - bbox.top;
return {
x: (clientX - bbox.left) * (el.width / width),
y: (clientY - bbox.top) * (el.height / height)
};
}
_beginDraw() {
this._attrs.toDraw = true;
}
_endDraw() {
this._attrs.toDraw = false;
}
draw() {
const self = this;
function drawInner() {
self.set('animateHandler', requestAnimationFrame(() => {
self.set('animateHandler', undefined);
if (self.get('toDraw')) {
drawInner();
}
}));
self.beforeDraw();
try {
const context = self._attrs.context;
const children = self._attrs.children;
for (let i = 0, len = children.length; i < len; i++) {
const child = children[i];
child.draw(context);
}
if (Util.isWx || Util.isMy) {
context.draw();
}
} catch (ev) {
console.warn('error in draw canvas, detail as:');
console.warn(ev);
self._endDraw();
}
self._endDraw();
}
if (self.get('destroyed')) {
return;
}
if (self.get('animateHandler')) {
this._beginDraw();
} else {
drawInner();
}
}
destroy() {
if (this.get('destroyed')) {
return;
}
this.clear();
this._attrs = {};
this.set('destroyed', true);
}
isDestroyed() {
return this.get('destroyed');
}
}
Util.mix(Canvas.prototype, Container, {
getGroupClass() {
return Group;
}
});
module.exports = Canvas;