@antv/g2
Version:
the Grammar of Graphics in Javascript
312 lines • 11.9 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Runtime = exports.G2_CHART_KEY = void 0;
const g_1 = require("@antv/g");
const g_canvas_1 = require("@antv/g-canvas");
const g_plugin_dragndrop_1 = require("@antv/g-plugin-dragndrop");
const util_1 = require("@antv/util");
const event_emitter_1 = __importDefault(require("@antv/event-emitter"));
const runtime_1 = require("../runtime");
const event_1 = require("../utils/event");
const utils_1 = require("./utils");
const composition_1 = require("./composition");
const define_1 = require("./define");
const mark_1 = require("./mark");
const library_1 = require("./library");
exports.G2_CHART_KEY = 'G2_CHART_KEY';
class Runtime extends composition_1.CompositionNode {
constructor(options) {
const { container, canvas, renderer, plugins, lib, createCanvas } = options, rest = __rest(options, ["container", "canvas", "renderer", "plugins", "lib", "createCanvas"]);
super(rest, 'view');
// Identifies whether bindAutoFit.
this._hasBindAutoFit = false;
this._rendering = false;
this._trailing = false;
this._trailingResolve = null;
this._trailingReject = null;
this._previousDefinedType = null;
this._onResize = (0, util_1.debounce)(() => {
this.forceFit();
}, 300);
this._renderer = renderer || new g_canvas_1.Renderer();
this._plugins = plugins || [];
this._container = (0, utils_1.normalizeContainer)(container);
this._emitter = new event_emitter_1.default();
this._context = {
library: Object.assign(Object.assign({}, lib), library_1.library),
emitter: this._emitter,
canvas,
createCanvas,
};
this._create();
}
render() {
if (this._rendering)
return this._addToTrailing();
if (!this._context.canvas)
this._createCanvas();
this._context.canvas.getConfig().supportsCSSTransform = true;
this._bindAutoFit();
this._rendering = true;
const finished = new Promise((resolve, reject) => (0, runtime_1.render)(this._computedOptions(), this._context, this._createResolve(resolve), this._createReject(reject)));
const [finished1, resolve, reject] = (0, utils_1.createEmptyPromise)();
finished
.then(resolve)
.catch(reject)
.then(() => this._renderTrailing());
return finished1;
}
/**
* @overload
* @param {G2ViewTree} [options]
* @returns {Runtime|Spec}
*/
options(options) {
if (arguments.length === 0)
return (0, utils_1.optionsOf)(this);
const { type } = options;
if (type)
this._previousDefinedType = type;
(0, utils_1.updateRoot)(this, options, this._previousDefinedType, this._marks, this._compositions);
return this;
}
getContainer() {
return this._container;
}
getContext() {
return this._context;
}
on(event, callback, once) {
this._emitter.on(event, callback, once);
return this;
}
once(event, callback) {
this._emitter.once(event, callback);
return this;
}
emit(event, ...args) {
this._emitter.emit(event, ...args);
return this;
}
off(event, callback) {
this._emitter.off(event, callback);
return this;
}
clear() {
const options = this.options();
this.emit(event_1.ChartEvent.BEFORE_CLEAR);
this._reset();
(0, runtime_1.destroy)(options, this._context, false);
this.emit(event_1.ChartEvent.AFTER_CLEAR);
}
destroy() {
const options = this.options();
this.emit(event_1.ChartEvent.BEFORE_DESTROY);
this._unbindAutoFit();
this._reset();
(0, runtime_1.destroy)(options, this._context, true);
if (this._container[utils_1.REMOVE_FLAG])
(0, utils_1.removeContainer)(this._container);
this.emit(event_1.ChartEvent.AFTER_DESTROY);
}
forceFit() {
// Don't fit if size do not change.
this.options['autoFit'] = true;
const { width, height } = (0, utils_1.sizeOf)(this.options(), this._container);
if (width === this._width && height === this._height) {
return Promise.resolve(this);
}
// Don't call changeSize to prevent update width and height of options.
this.emit(event_1.ChartEvent.BEFORE_CHANGE_SIZE);
const finished = this.render();
finished.then(() => {
this.emit(event_1.ChartEvent.AFTER_CHANGE_SIZE);
});
return finished;
}
changeSize(width, height) {
if (width === this._width && height === this._height) {
return Promise.resolve(this);
}
this.emit(event_1.ChartEvent.BEFORE_CHANGE_SIZE);
this.attr('width', width);
this.attr('height', height);
const finished = this.render();
finished.then(() => {
this.emit(event_1.ChartEvent.AFTER_CHANGE_SIZE);
});
return finished;
}
_create() {
const { library } = this._context;
// @todo After refactor component as mark, remove this.
const isMark = (key) => key.startsWith('mark.') ||
key === 'component.axisX' ||
key === 'component.axisY' ||
key === 'component.legends';
const marks = [
'mark.mark',
...Object.keys(library).filter(isMark),
];
// Create mark generators.
this._marks = {};
for (const key of marks) {
const name = key.split('.').pop();
class Mark extends mark_1.MarkNode {
constructor() {
super({}, name);
}
}
this._marks[name] = Mark;
this[name] = function (composite) {
const node = this.append(Mark);
if (name === 'mark')
node.type = composite;
return node;
};
}
// Create composition generators.
const compositions = [
'composition.view',
...Object.keys(library).filter((key) => key.startsWith('composition.') && key !== 'composition.mark'),
];
this._compositions = Object.fromEntries(compositions.map((key) => {
const name = key.split('.').pop();
let Composition = class Composition extends composition_1.CompositionNode {
constructor() {
super({}, name);
}
};
Composition = __decorate([
(0, define_1.defineProps)((0, define_1.nodeProps)(this._marks))
], Composition);
return [name, Composition];
}));
for (const Ctor of Object.values(this._compositions)) {
(0, define_1.defineProps)((0, define_1.nodeProps)(this._compositions))(Ctor);
}
for (const key of compositions) {
const name = key.split('.').pop();
this[name] = function () {
const Composition = this._compositions[name];
this.type = null;
return this.append(Composition);
};
}
}
_reset() {
const KEYS = ['theme', 'type', 'width', 'height', 'autoFit'];
this.type = 'view';
this.value = Object.fromEntries(Object.entries(this.value).filter(([key]) => key.startsWith('margin') ||
key.startsWith('padding') ||
key.startsWith('inset') ||
KEYS.includes(key)));
this.children = [];
}
_renderTrailing() {
if (!this._trailing)
return;
this._trailing = false;
this.render()
.then(() => {
const trailingResolve = this._trailingResolve.bind(this);
this._trailingResolve = null;
trailingResolve(this);
})
.catch((error) => {
const trailingReject = this._trailingReject.bind(this);
this._trailingReject = null;
trailingReject(error);
});
}
_createResolve(resolve) {
return () => {
this._rendering = false;
resolve(this);
};
}
_createReject(reject) {
return (error) => {
this._rendering = false;
reject(error);
};
}
// Update actual size and key.
_computedOptions() {
const options = this.options();
const { key = exports.G2_CHART_KEY } = options;
const { width, height, depth } = (0, utils_1.sizeOf)(options, this._container);
this._width = width;
this._height = height;
this._key = key;
return Object.assign(Object.assign({ key: this._key }, options), { width, height, depth });
}
// Create canvas if it does not exist.
// DragAndDropPlugin is for interaction.
// It is OK to register more than one time, G will handle this.
_createCanvas() {
const { width, height } = (0, utils_1.sizeOf)(this.options(), this._container);
this._plugins.push(new g_plugin_dragndrop_1.Plugin());
this._plugins.forEach((d) => this._renderer.registerPlugin(d));
this._context.canvas = new g_1.Canvas({
container: this._container,
width,
height,
renderer: this._renderer,
});
}
_addToTrailing() {
var _a;
// Resolve previous promise, and give up this task.
(_a = this._trailingResolve) === null || _a === void 0 ? void 0 : _a.call(this, this);
// Create new task.
this._trailing = true;
const promise = new Promise((resolve, reject) => {
this._trailingResolve = resolve;
this._trailingReject = reject;
});
return promise;
}
_bindAutoFit() {
const options = this.options();
const { autoFit } = options;
if (this._hasBindAutoFit) {
// If it was bind before, unbind it now.
if (!autoFit)
this._unbindAutoFit();
return;
}
if (autoFit) {
this._hasBindAutoFit = true;
window.addEventListener('resize', this._onResize);
}
}
_unbindAutoFit() {
if (this._hasBindAutoFit) {
this._hasBindAutoFit = false;
window.removeEventListener('resize', this._onResize);
}
}
}
exports.Runtime = Runtime;
//# sourceMappingURL=runtime.js.map