render.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.destroy = exports.renderToMountedElement = exports.render = void 0;
  7. const g_1 = require("@antv/g");
  8. const g_canvas_1 = require("@antv/g-canvas");
  9. const g_plugin_dragndrop_1 = require("@antv/g-plugin-dragndrop");
  10. const util_1 = require("@antv/util");
  11. const event_emitter_1 = __importDefault(require("@antv/event-emitter"));
  12. const stdlib_1 = require("../stdlib");
  13. const selection_1 = require("../utils/selection");
  14. const event_1 = require("../utils/event");
  15. const helper_1 = require("../utils/helper");
  16. const plot_1 = require("./plot");
  17. const constant_1 = require("./constant");
  18. /**
  19. * Infer key for each node of view tree.
  20. * Each key should be unique in the entire view tree.
  21. * The key is for incremental render when view tree is changed.
  22. * @todo Fix custom key equals to inferred key.
  23. */
  24. function inferKeys(options) {
  25. const root = (0, util_1.deepMix)({}, options);
  26. const nodeParent = new Map([[root, null]]);
  27. const nodeIndex = new Map([[null, -1]]);
  28. const discovered = [root];
  29. while (discovered.length) {
  30. const node = discovered.shift();
  31. // If key of node is not specified, using parentKey and the index for it
  32. // in parent.children as its key.
  33. // e.g. The key of node named 'a' will be 'a', and the key of node named
  34. // 'b' will be 'parent-1' in the following view tree specification.
  35. // { key: 'parent', children: [{ name: 'a', key: 'a' }, { name: 'b' }] }
  36. if (node.key === undefined) {
  37. const parent = nodeParent.get(node);
  38. const index = nodeIndex.get(node);
  39. const key = parent === null ? `${0}` : `${parent.key}-${index}`;
  40. node.key = key;
  41. }
  42. const { children = [] } = node;
  43. if (Array.isArray(children)) {
  44. for (let i = 0; i < children.length; i++) {
  45. // Clone node as well.
  46. const child = (0, util_1.deepMix)({}, children[i]);
  47. children[i] = child;
  48. nodeParent.set(child, node);
  49. nodeIndex.set(child, i);
  50. discovered.push(child);
  51. }
  52. }
  53. }
  54. return root;
  55. }
  56. function Canvas(width, height) {
  57. const renderer = new g_canvas_1.Renderer();
  58. // DragAndDropPlugin is for interaction.
  59. renderer.registerPlugin(new g_plugin_dragndrop_1.Plugin());
  60. return new g_1.Canvas({
  61. width,
  62. height,
  63. container: document.createElement('div'),
  64. renderer: renderer,
  65. });
  66. }
  67. function render(options, context = {}, resolve = () => { }, reject = (e) => {
  68. throw e;
  69. }) {
  70. // Initialize the context if it is not provided.
  71. const { width = 640, height = 480, theme } = options;
  72. if (!theme) {
  73. (0, helper_1.error)('ChartOptions.theme is required, such as `const chart = new Chart({ theme: "classic"})`.');
  74. }
  75. const keyed = inferKeys(options);
  76. const { canvas = Canvas(width, height), library = (0, stdlib_1.createLibrary)(), emitter = new event_emitter_1.default(), } = context;
  77. context.canvas = canvas;
  78. context.library = library;
  79. context.emitter = emitter;
  80. canvas.resize(width, height);
  81. emitter.emit(event_1.ChartEvent.BEFORE_RENDER);
  82. // Plot the chart and mutate context.
  83. // Make sure that plot chart after container is ready for every time.
  84. const selection = (0, selection_1.select)(canvas.document.documentElement);
  85. canvas.ready
  86. .then(() => (0, plot_1.plot)(Object.assign(Object.assign({}, keyed), { width, height }), selection, library, context))
  87. .then(() => {
  88. // Wait for the next tick.
  89. canvas.requestAnimationFrame(() => {
  90. emitter.emit(event_1.ChartEvent.AFTER_RENDER);
  91. resolve === null || resolve === void 0 ? void 0 : resolve();
  92. });
  93. })
  94. .catch((e) => {
  95. reject === null || reject === void 0 ? void 0 : reject(e);
  96. });
  97. // Return the container HTML element wraps the canvas or svg element.
  98. return normalizeContainer(canvas.getConfig().container);
  99. }
  100. exports.render = render;
  101. function renderToMountedElement(options, context = {}, resolve = () => { }, reject = (e) => {
  102. throw e;
  103. }) {
  104. // Initialize the context if it is not provided.
  105. const { width = 640, height = 480, on } = options;
  106. const keyed = inferKeys(options);
  107. const { library = (0, stdlib_1.createLibrary)(), group = new g_1.Group(), emitter = new event_emitter_1.default(), } = context;
  108. if (!(group === null || group === void 0 ? void 0 : group.parentElement)) {
  109. (0, helper_1.error)(`renderToMountedElement can't render chart to unmounted group.`);
  110. }
  111. const selection = (0, selection_1.select)(group);
  112. context.group = group;
  113. context.library = library;
  114. context.emitter = emitter;
  115. emitter.emit(event_1.ChartEvent.BEFORE_RENDER);
  116. // Plot the chart and mutate context.
  117. // Make sure that plot chart after container is ready for every time.
  118. (0, plot_1.plot)(Object.assign(Object.assign({}, keyed), { width, height }), selection, library, context)
  119. .then(() => {
  120. const canvas = group.ownerDocument.defaultView;
  121. canvas.requestAnimationFrame(() => {
  122. emitter.emit(event_1.ChartEvent.AFTER_RENDER);
  123. resolve === null || resolve === void 0 ? void 0 : resolve();
  124. });
  125. })
  126. .catch((e) => {
  127. reject === null || reject === void 0 ? void 0 : reject(e);
  128. });
  129. // Return the Group wraps the canvas or svg element.
  130. return group;
  131. }
  132. exports.renderToMountedElement = renderToMountedElement;
  133. function destroy(options, context = {}, isDestroyCanvas = false) {
  134. const { canvas, emitter } = context;
  135. if (canvas) {
  136. destroyAllInteractions(canvas);
  137. isDestroyCanvas ? canvas.destroy() : canvas.destroyChildren();
  138. }
  139. emitter.off();
  140. }
  141. exports.destroy = destroy;
  142. /**
  143. * Destroy all interactions mounted on the canvas.
  144. */
  145. function destroyAllInteractions(canvas) {
  146. const viewGroups = canvas.getRoot().querySelectorAll(`.${constant_1.VIEW_CLASS_NAME}`);
  147. viewGroups === null || viewGroups === void 0 ? void 0 : viewGroups.forEach((group) => {
  148. const { nameInteraction = new Map() } = group;
  149. if ((nameInteraction === null || nameInteraction === void 0 ? void 0 : nameInteraction.size) > 0) {
  150. Array.from(nameInteraction === null || nameInteraction === void 0 ? void 0 : nameInteraction.values()).forEach((value) => {
  151. value === null || value === void 0 ? void 0 : value.destroy();
  152. });
  153. }
  154. });
  155. }
  156. function normalizeContainer(container) {
  157. return typeof container === 'string'
  158. ? document.getElementById(container)
  159. : container;
  160. }
  161. //# sourceMappingURL=render.js.map