UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering.

1,057 lines 40.8 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Renderer = void 0; var util_1 = require("../util"); var geometry_1 = require("../geometry"); var model_1 = require("../model"); var view_1 = require("../view"); var base_1 = require("./base"); var Renderer = /** @class */ (function (_super) { __extends(Renderer, _super); function Renderer() { return _super !== null && _super.apply(this, arguments) || this; } Renderer.prototype.init = function () { this.resetUpdates(); this.startListening(); // Renders existing cells in the model. this.resetViews(this.model.getCells()); // Starts rendering loop. if (!this.isFrozen() && this.isAsync()) { this.updateViewsAsync(); } }; Renderer.prototype.startListening = function () { this.model.on('sorted', this.onSortModel, this); this.model.on('reseted', this.onModelReseted, this); this.model.on('batch:stop', this.onBatchStop, this); this.model.on('cell:added', this.onCellAdded, this); this.model.on('cell:removed', this.onCellRemoved, this); this.model.on('cell:change:zIndex', this.onCellZIndexChanged, this); this.model.on('cell:change:visible', this.onCellVisibleChanged, this); }; Renderer.prototype.stopListening = function () { this.model.off('sorted', this.onSortModel, this); this.model.off('reseted', this.onModelReseted, this); this.model.off('batch:stop', this.onBatchStop, this); this.model.off('cell:added', this.onCellAdded, this); this.model.off('cell:removed', this.onCellRemoved, this); this.model.off('cell:change:zIndex', this.onCellZIndexChanged, this); this.model.off('cell:change:visible', this.onCellVisibleChanged, this); }; Renderer.prototype.resetUpdates = function () { this.updates = { priorities: [{}, {}, {}], mounted: {}, mountedCids: [], unmounted: {}, unmountedCids: [], count: 0, sort: false, frozen: false, freezeKey: null, animationId: null, }; }; Renderer.prototype.onSortModel = function () { if (this.model.hasActiveBatch(Renderer.SORT_DELAYING_BATCHES)) { return; } this.sortViews(); }; Renderer.prototype.onModelReseted = function (_a) { var options = _a.options; this.removeZPivots(); this.resetViews(this.model.getCells(), options); }; Renderer.prototype.onBatchStop = function (_a) { var name = _a.name, data = _a.data; if (this.isFrozen()) { return; } var model = this.model; if (!this.isAsync()) { var updateDelayingBatches = Renderer.UPDATE_DELAYING_BATCHES; if (updateDelayingBatches.includes(name) && !model.hasActiveBatch(updateDelayingBatches)) { this.updateViews(data); } } var sortDelayingBatches = Renderer.SORT_DELAYING_BATCHES; if (sortDelayingBatches.includes(name) && !model.hasActiveBatch(sortDelayingBatches)) { this.sortViews(); } }; Renderer.prototype.onCellAdded = function (_a) { var cell = _a.cell, options = _a.options; var position = options.position; if (this.isAsync() || typeof position !== 'number') { this.renderView(cell, options); } else { if (options.maxPosition === position) { this.freeze({ key: 'addCells' }); } this.renderView(cell, options); if (position === 0) { this.unfreeze({ key: 'addCells' }); } } }; Renderer.prototype.onCellRemoved = function (_a) { var cell = _a.cell, options = _a.options; var view = this.findViewByCell(cell); if (view) { this.requestViewUpdate(view, Renderer.FLAG_REMOVE, view.priority, options); } }; Renderer.prototype.onCellZIndexChanged = function (_a) { var cell = _a.cell, options = _a.options; if (this.options.sorting === 'approx') { var view = this.findViewByCell(cell); if (view) { this.requestViewUpdate(view, Renderer.FLAG_INSERT, view.priority, options); } } }; Renderer.prototype.onCellVisibleChanged = function (_a) { var cell = _a.cell, visible = _a.current, options = _a.options; // Hide connected edges before cell if (!visible) { this.processEdgeOnTerminalVisibleChanged(cell, false); } var view = this.findViewByCell(cell); if (!visible && view) { this.removeView(cell); } else if (visible && view == null) { this.renderView(cell, options); } // Show connected edges after cell rendered if (visible) { this.processEdgeOnTerminalVisibleChanged(cell, true); } }; Renderer.prototype.processEdgeOnTerminalVisibleChanged = function (node, visible) { var getOpposite = function (edge, currentTerminal) { var sourceId = edge.getSourceCellId(); if (sourceId !== currentTerminal.id) { return edge.getSourceCell(); } var targetId = edge.getTargetCellId(); if (targetId !== currentTerminal.id) { return edge.getTargetCell(); } return null; }; this.model.getConnectedEdges(node).forEach(function (edge) { var opposite = getOpposite(edge, node); if (opposite == null || opposite.isVisible()) { visible ? edge.show() : edge.hide(); } }); }; Renderer.prototype.isEdgeTerminalVisible = function (edge, terminal) { var cellId = terminal === 'source' ? edge.getSourceCellId() : edge.getTargetCellId(); var cell = cellId ? this.model.getCell(cellId) : null; if (cell && !cell.isVisible()) { return false; } return true; }; Renderer.prototype.requestConnectedEdgesUpdate = function (view, options) { if (options === void 0) { options = {}; } if (view_1.CellView.isCellView(view)) { var cell = view.cell; var edges = this.model.getConnectedEdges(cell); for (var j = 0, n = edges.length; j < n; j += 1) { var edge = edges[j]; var edgeView = this.findViewByCell(edge); if (!edgeView) { continue; } var flagLabels = ['update']; if (edge.getTargetCell() === cell) { flagLabels.push('target'); } if (edge.getSourceCell() === cell) { flagLabels.push('source'); } this.scheduleViewUpdate(edgeView, edgeView.getFlag(flagLabels), edgeView.priority, options); } } }; Renderer.prototype.forcePostponedViewUpdate = function (view, flag) { if (!view || !view_1.CellView.isCellView(view)) { return false; } var cell = view.cell; if (cell.isNode()) { return false; } var edgeView = view; if (cell.isEdge() && (flag & view.getFlag(['source', 'target'])) === 0) { // EdgeView is waiting for the source/target cellView to be rendered. // This can happen when the cells are not in the viewport. var sourceFlag = 0; var sourceView = this.findViewByCell(cell.getSourceCell()); if (sourceView && !this.isViewMounted(sourceView)) { sourceFlag = this.dumpView(sourceView); edgeView.updateTerminalMagnet('source'); } var targetFlag = 0; var targetView = this.findViewByCell(cell.getTargetCell()); if (targetView && !this.isViewMounted(targetView)) { targetFlag = this.dumpView(targetView); edgeView.updateTerminalMagnet('target'); } if (sourceFlag === 0 && targetFlag === 0) { // If leftover flag is 0, all view updates were done. return !this.dumpView(edgeView); } } return false; }; Renderer.prototype.scheduleViewUpdate = function (view, flag, priority, options) { if (options === void 0) { options = {}; } var cid = view.cid; var updates = this.updates; var cache = updates.priorities[priority]; if (!cache) { cache = updates.priorities[priority] = {}; } var currentFlag = cache[cid] || 0; if ((currentFlag & flag) === flag) { return; } if (!currentFlag) { updates.count += 1; } if (flag & Renderer.FLAG_REMOVE && currentFlag & Renderer.FLAG_INSERT) { // When a view is removed we need to remove the // insert flag as this is a reinsert. cache[cid] ^= Renderer.FLAG_INSERT; } else if (flag & Renderer.FLAG_INSERT && currentFlag & Renderer.FLAG_REMOVE) { // When a view is added we need to remove the remove // flag as this is view was previously removed. cache[cid] ^= Renderer.FLAG_REMOVE; } cache[cid] |= flag; this.graph.hook.onViewUpdated(view, flag, options); }; Renderer.prototype.requestViewUpdate = function (view, flag, priority, options) { if (options === void 0) { options = {}; } this.scheduleViewUpdate(view, flag, priority, options); var isAsync = this.isAsync(); if (this.isFrozen() || (isAsync && options.async !== false) || this.model.hasActiveBatch(Renderer.UPDATE_DELAYING_BATCHES)) { return; } var stats = this.updateViews(options); if (isAsync) { this.graph.trigger('render:done', { stats: stats, options: options }); } }; /** * Adds view into the DOM and update it. */ Renderer.prototype.dumpView = function (view, options) { if (options === void 0) { options = {}; } if (view == null) { return 0; } var cid = view.cid; var updates = this.updates; var cache = updates.priorities[view.priority]; var flag = this.registerMountedView(view) | cache[cid]; delete cache[cid]; if (!flag) { return 0; } return this.updateView(view, flag, options); }; /** * Adds all views into the DOM and update them. */ Renderer.prototype.dumpViews = function (options) { if (options === void 0) { options = {}; } this.checkView(options); this.updateViews(options); }; /** * Ensure the view associated with the cell is attached * to the DOM and updated. */ Renderer.prototype.requireView = function (cell, options) { if (options === void 0) { options = {}; } var view = this.findViewByCell(cell); if (view == null) { return null; } this.dumpView(view, options); return view; }; Renderer.prototype.updateView = function (view, flag, options) { if (options === void 0) { options = {}; } if (view == null) { return 0; } if (view_1.CellView.isCellView(view)) { if (flag & Renderer.FLAG_REMOVE) { this.removeView(view.cell); return 0; } if (flag & Renderer.FLAG_INSERT) { this.insertView(view); flag ^= Renderer.FLAG_INSERT; // eslint-disable-line } } if (!flag) { return 0; } return view.confirmUpdate(flag, options); }; Renderer.prototype.updateViews = function (options) { if (options === void 0) { options = {}; } var result; var batchCount = 0; var updatedCount = 0; var priority = Renderer.MIN_PRIORITY; do { result = this.updateViewsBatch(options); batchCount += 1; updatedCount += result.updatedCount; priority = Math.min(result.priority, priority); } while (!result.empty); return { priority: priority, batchCount: batchCount, updatedCount: updatedCount, }; }; Renderer.prototype.updateViewsBatch = function (options) { if (options === void 0) { options = {}; } var updates = this.updates; var priorities = updates.priorities; var batchSize = options.batchSize || Renderer.UPDATE_BATCH_SIZE; var empty = true; var priority = Renderer.MIN_PRIORITY; var mountedCount = 0; var unmountedCount = 0; var updatedCount = 0; var postponedCount = 0; var checkView = options.checkView || this.options.checkView; if (typeof checkView !== 'function') { checkView = null; } // eslint-disable-next-line main: for (var p = 0, n = priorities.length; p < n; p += 1) { var cache = priorities[p]; // eslint-disable-next-line for (var cid in cache) { if (updatedCount >= batchSize) { empty = false; // goto next batch break main; // eslint-disable-line no-labels } var view = view_1.View.views[cid]; if (!view) { delete cache[cid]; continue; } var currentFlag = cache[cid]; // Do not check a view for viewport if we are about to remove the view. if ((currentFlag & Renderer.FLAG_REMOVE) === 0) { var isUnmounted = cid in updates.unmounted; if (checkView && !util_1.FunctionExt.call(checkView, this.graph, { view: view, unmounted: isUnmounted, })) { // Unmount view if (!isUnmounted) { this.registerUnmountedView(view); view.unmount(); } updates.unmounted[cid] |= currentFlag; delete cache[cid]; unmountedCount += 1; continue; } // Mount view if (isUnmounted) { currentFlag |= Renderer.FLAG_INSERT; mountedCount += 1; } currentFlag |= this.registerMountedView(view); } var cellView = view; var leftoverFlag = this.updateView(view, currentFlag, options); if (leftoverFlag > 0) { var cell = cellView.cell; if (cell && cell.isEdge()) { // remove edge view when source cell is invisible if (cellView.hasAction(leftoverFlag, 'source') && !this.isEdgeTerminalVisible(cell, 'source')) { leftoverFlag = cellView.removeAction(leftoverFlag, 'source'); leftoverFlag |= Renderer.FLAG_REMOVE; } // remove edge view when target cell is invisible if (cellView.hasAction(leftoverFlag, 'target') && !this.isEdgeTerminalVisible(cell, 'target')) { leftoverFlag = cellView.removeAction(leftoverFlag, 'target'); leftoverFlag |= Renderer.FLAG_REMOVE; } } } if (leftoverFlag > 0) { // update has not finished cache[cid] = leftoverFlag; if (!this.graph.hook.onViewPostponed(cellView, leftoverFlag, options) || cache[cid]) { postponedCount += 1; empty = false; continue; } } if (priority > p) { priority = p; } updatedCount += 1; delete cache[cid]; } } return { empty: empty, priority: priority, mountedCount: mountedCount, unmountedCount: unmountedCount, updatedCount: updatedCount, postponedCount: postponedCount, }; }; Renderer.prototype.updateViewsAsync = function (options, data) { var _this = this; if (options === void 0) { options = {}; } if (data === void 0) { data = { processed: 0, priority: Renderer.MIN_PRIORITY, }; } var updates = this.updates; var animationId = updates.animationId; if (animationId) { util_1.Dom.cancelAnimationFrame(animationId); if (data.processed === 0) { var beforeFn = options.before; if (typeof beforeFn === 'function') { util_1.FunctionExt.call(beforeFn, this.graph, this.graph); } } var stats = this.updateViewsBatch(options); var checkout = this.checkViewImpl({ checkView: options.checkView, mountedBatchSize: Renderer.MOUNT_BATCH_SIZE - stats.mountedCount, unmountedBatchSize: Renderer.MOUNT_BATCH_SIZE - stats.unmountedCount, }); var processed = data.processed; var total = updates.count; var mountedCount = checkout.mountedCount; var unmountedCount = checkout.unmountedCount; if (stats.updatedCount > 0) { // Some updates have been just processed processed += stats.updatedCount + stats.unmountedCount; data.priority = Math.min(stats.priority, data.priority); if (stats.empty && mountedCount === 0) { stats.priority = data.priority; stats.mountedCount += mountedCount; stats.unmountedCount += unmountedCount; this.graph.trigger('render:done', { stats: stats, options: options }); data.processed = 0; updates.count = 0; } else { data.processed = processed; } } // Progress callback var progressFn = options.progress; if (total && typeof progressFn === 'function') { util_1.FunctionExt.call(progressFn, this.graph, { total: total, done: stats.empty, current: processed, }); } // The current frame could have been canceled in a callback if (updates.animationId !== animationId) { return; } } updates.animationId = util_1.Dom.requestAnimationFrame(function () { _this.updateViewsAsync(options, data); }); }; Renderer.prototype.registerMountedView = function (view) { var cid = view.cid; var updates = this.updates; if (cid in updates.mounted) { return 0; } updates.mounted[cid] = true; updates.mountedCids.push(cid); var flag = updates.unmounted[cid] || 0; delete updates.unmounted[cid]; return flag; }; Renderer.prototype.registerUnmountedView = function (view) { var cid = view.cid; var updates = this.updates; if (cid in updates.unmounted) { return 0; } updates.unmounted[cid] |= Renderer.FLAG_INSERT; var flag = updates.unmounted[cid]; updates.unmountedCids.push(cid); delete updates.mounted[cid]; return flag; }; Renderer.prototype.isViewMounted = function (view) { if (view == null) { return false; } var cid = view.cid; return cid in this.updates.mounted; }; Renderer.prototype.getMountedViews = function () { return Object.keys(this.updates.mounted).map(function (cid) { return view_1.CellView.views[cid]; }); }; Renderer.prototype.getUnmountedViews = function () { return Object.keys(this.updates.unmounted).map(function (cid) { return view_1.CellView.views[cid]; }); }; Renderer.prototype.checkMountedViews = function (viewportFn, batchSize) { var unmountCount = 0; if (typeof viewportFn !== 'function') { return unmountCount; } var updates = this.updates; var mounted = updates.mounted; var mountedCids = updates.mountedCids; var size = batchSize == null ? mountedCids.length : Math.min(mountedCids.length, batchSize); for (var i = 0; i < size; i += 1) { var cid = mountedCids[i]; if (!(cid in mounted)) { continue; } var view = view_1.CellView.views[cid]; if (view == null) { continue; } var shouldMount = util_1.FunctionExt.call(viewportFn, this.graph, { view: view, unmounted: true, }); if (shouldMount) { // Push at the end of all mounted ids mountedCids.push(cid); continue; } unmountCount += 1; var flag = this.registerUnmountedView(view); if (flag) { view.unmount(); } } // Get rid of views, that have been unmounted mountedCids.splice(0, size); return unmountCount; }; Renderer.prototype.checkUnmountedViews = function (checkView, batchSize) { var mountCount = 0; if (typeof checkView !== 'function') { checkView = null; // eslint-disable-line } var updates = this.updates; var unmounted = updates.unmounted; var unmountedCids = updates.unmountedCids; var size = batchSize == null ? unmountedCids.length : Math.min(unmountedCids.length, batchSize); for (var i = 0; i < size; i += 1) { var cid = unmountedCids[i]; if (!(cid in unmounted)) { continue; } var view = view_1.CellView.views[cid]; if (view == null) { continue; } if (checkView && !util_1.FunctionExt.call(checkView, this.graph, { view: view, unmounted: false })) { unmountedCids.push(cid); continue; } mountCount += 1; var flag = this.registerMountedView(view); if (flag) { this.scheduleViewUpdate(view, flag, view.priority, { mounting: true, }); } } // Get rid of views, that have been mounted unmountedCids.splice(0, size); return mountCount; }; Renderer.prototype.checkViewImpl = function (options) { if (options === void 0) { options = { mountedBatchSize: Number.MAX_SAFE_INTEGER, unmountedBatchSize: Number.MAX_SAFE_INTEGER, }; } var checkView = options.checkView || this.options.checkView; var unmountedCount = this.checkMountedViews(checkView, options.unmountedBatchSize); var mountedCount = this.checkUnmountedViews(checkView, // Do not check views, that have been just unmounted // and pushed at the end of the cids array unmountedCount > 0 ? Math.min(this.updates.unmountedCids.length - unmountedCount, options.mountedBatchSize) : options.mountedBatchSize); return { mountedCount: mountedCount, unmountedCount: unmountedCount }; }; /** * Determine every view in the graph should be attached/detached. */ Renderer.prototype.checkView = function (options) { if (options === void 0) { options = {}; } return this.checkViewImpl(options); }; Renderer.prototype.isFrozen = function () { return !!this.options.frozen; }; /** * Freeze the graph then the graph does not automatically re-render upon * changes in the graph. This is useful when adding large numbers of cells. */ Renderer.prototype.freeze = function (options) { if (options === void 0) { options = {}; } var key = options.key; var updates = this.updates; var frozen = this.options.frozen; var freezeKey = updates.freezeKey; if (key && key !== freezeKey) { if (frozen && freezeKey) { // key passed, but the graph is already freezed with another key return; } updates.frozen = frozen; updates.freezeKey = key; } this.options.frozen = true; var animationId = updates.animationId; updates.animationId = null; if (this.isAsync() && animationId != null) { util_1.Dom.cancelAnimationFrame(animationId); } this.graph.trigger('freeze', { key: key }); }; Renderer.prototype.unfreeze = function (options) { var _this = this; if (options === void 0) { options = {}; } var key = options.key; var updates = this.updates; var freezeKey = updates.freezeKey; // key passed, but the graph is already freezed with another key if (key && freezeKey && key !== freezeKey) { return; } updates.freezeKey = null; // key passed, but the graph is already freezed if (key && key === freezeKey && updates.frozen) { return; } var callback = function () { _this.options.frozen = updates.frozen = false; if (updates.sort) { _this.sortViews(); updates.sort = false; } var afterFn = options.after; if (afterFn) { util_1.FunctionExt.call(afterFn, _this.graph, _this.graph); } _this.graph.trigger('unfreeze', { key: key }); }; if (this.isAsync()) { this.freeze(); var onProgress_1 = options.progress; this.updateViewsAsync(__assign(__assign({}, options), { progress: function (_a) { var done = _a.done, current = _a.current, total = _a.total; if (onProgress_1) { util_1.FunctionExt.call(onProgress_1, _this.graph, { done: done, current: current, total: total }); } // sort views after async render if (done) { callback(); } } })); } else { this.updateViews(options); callback(); } }; Renderer.prototype.isAsync = function () { return !!this.options.async; }; Renderer.prototype.setAsync = function (async) { this.options.async = async; }; Renderer.prototype.onRemove = function () { this.freeze(); this.removeViews(); }; Renderer.prototype.resetViews = function (cells, options) { if (cells === void 0) { cells = []; } if (options === void 0) { options = {}; } this.resetUpdates(); this.removeViews(); this.freeze({ key: 'reset' }); for (var i = 0, n = cells.length; i < n; i += 1) { this.renderView(cells[i], options); } this.unfreeze({ key: 'reset' }); this.sortViews(); }; Renderer.prototype.removeView = function (cell) { var view = this.views[cell.id]; if (view) { var cid = view.cid; var updates = this.updates; var mounted = updates.mounted; var unmounted = updates.unmounted; view.remove(); delete this.views[cell.id]; delete mounted[cid]; delete unmounted[cid]; } return view; }; Renderer.prototype.removeViews = function () { var _this = this; if (this.views) { Object.keys(this.views).forEach(function (id) { var view = _this.views[id]; if (view) { _this.removeView(view.cell); } }); } this.views = {}; }; Renderer.prototype.renderView = function (cell, options) { if (options === void 0) { options = {}; } var id = cell.id; var views = this.views; var flag = 0; var view = views[id]; if (!cell.isVisible()) { return; } if (cell.isEdge()) { if (!this.isEdgeTerminalVisible(cell, 'source') || !this.isEdgeTerminalVisible(cell, 'target')) { return; } } if (view) { flag = Renderer.FLAG_INSERT; } else { var tmp = this.graph.hook.createCellView(cell); if (tmp) { view = views[cell.id] = tmp; view.graph = this.graph; flag = this.registerUnmountedView(view) | view.getBootstrapFlag(); } } if (view) { this.requestViewUpdate(view, flag, view.priority, options); } }; Renderer.prototype.isExactSorting = function () { return this.options.sorting === 'exact'; }; Renderer.prototype.sortViews = function () { if (!this.isExactSorting()) { return; } if (this.isFrozen()) { // sort views once unfrozen this.updates.sort = true; return; } this.sortViewsExact(); }; Renderer.prototype.sortElements = function (elems, comparator) { // Highly inspired by the jquery.sortElements plugin by Padolsey. // See http://james.padolsey.com/javascript/sorting-elements-with-jquery/. var placements = elems.map(function (elem) { var parentNode = elem.parentNode; // Since the element itself will change position, we have // to have some way of storing it's original position in // the DOM. The easiest way is to have a 'flag' node: var nextSibling = parentNode.insertBefore(document.createTextNode(''), elem.nextSibling); return function (targetNode) { if (parentNode === targetNode) { throw new Error("You can't sort elements if any one is a descendant of another."); } // Insert before flag parentNode.insertBefore(targetNode, nextSibling); // Remove flag parentNode.removeChild(nextSibling); }; }); elems.sort(comparator).forEach(function (elem, index) { return placements[index](elem); }); }; Renderer.prototype.sortViewsExact = function () { // const elems = this.view.stage.querySelectorAll('[data-cell-id]') // const length = elems.length // const cells = [] // for (let i = 0; i < length; i++) { // const cell = this.model.getCell(elems[i].getAttribute('data-cell-id') || '') // cells.push({ // id: cell.id, // zIndex: cell.getZIndex() || 0, // elem: elems[i], // }) // } // const sortedCells = [...cells].sort((cell1, cell2) => cell1.zIndex - cell2.zIndex) // const moves = ArrayExt.diff(cells, sortedCells, 'zIndex').moves // if (moves && moves.length) { // moves.forEach((move) => { // if (move.type) { // const elem = move.item.elem as Element // const parentNode = elem.parentNode // const index = move.index // if (parentNode) { // if (index === length - 1) { // parentNode.appendChild(elem) // } else if (index < length - 1) { // parentNode.insertBefore(elem, elems[index + 1]) // } // } // } // }) // } // Run insertion sort algorithm in order to efficiently sort DOM // elements according to their associated cell `zIndex` attribute. var elems = this.view .$(this.view.stage) .children('[data-cell-id]') .toArray(); var model = this.model; this.sortElements(elems, function (a, b) { var cellA = model.getCell(a.getAttribute('data-cell-id') || ''); var cellB = model.getCell(b.getAttribute('data-cell-id') || ''); var z1 = cellA.getZIndex() || 0; var z2 = cellB.getZIndex() || 0; return z1 === z2 ? 0 : z1 < z2 ? -1 : 1; }); }; Renderer.prototype.addZPivot = function (zIndex) { if (zIndex === void 0) { zIndex = 0; } if (this.zPivots == null) { this.zPivots = {}; } var pivots = this.zPivots; var pivot = pivots[zIndex]; if (pivot) { return pivot; } pivot = pivots[zIndex] = document.createComment("z-index:" + (zIndex + 1)); var neighborZ = -Infinity; // eslint-disable-next-line for (var key in pivots) { var currentZ = +key; if (currentZ < zIndex && currentZ > neighborZ) { neighborZ = currentZ; if (neighborZ === zIndex - 1) { continue; } } } var layer = this.view.stage; if (neighborZ !== -Infinity) { var neighborPivot = pivots[neighborZ]; layer.insertBefore(pivot, neighborPivot.nextSibling); } else { layer.insertBefore(pivot, layer.firstChild); } return pivot; }; Renderer.prototype.removeZPivots = function () { var _this = this; if (this.zPivots) { Object.keys(this.zPivots).forEach(function (z) { var elem = _this.zPivots[z]; if (elem && elem.parentNode) { elem.parentNode.removeChild(elem); } }); } this.zPivots = {}; }; Renderer.prototype.insertView = function (view) { var stage = this.view.stage; switch (this.options.sorting) { case 'approx': { var zIndex = view.cell.getZIndex(); var pivot = this.addZPivot(zIndex); stage.insertBefore(view.container, pivot); break; } case 'exact': default: stage.appendChild(view.container); break; } }; Renderer.prototype.findViewByCell = function (cell) { if (cell == null) { return null; } var id = model_1.Cell.isCell(cell) ? cell.id : cell; return this.views[id]; }; Renderer.prototype.findViewByElem = function (elem) { if (elem == null) { return null; } var target = typeof elem === 'string' ? this.view.stage.querySelector(elem) : elem instanceof Element ? elem : elem[0]; if (target) { var id = this.view.findAttr('data-cell-id', target); if (id) { return this.views[id]; } } return null; }; Renderer.prototype.findViewsFromPoint = function (p) { var _this = this; var ref = { x: p.x, y: p.y }; return this.model .getCells() .map(function (cell) { return _this.findViewByCell(cell); }) .filter(function (view) { if (view != null) { return util_1.Dom.getBBox(view.container, { target: _this.view.stage, }).containsPoint(ref); } return false; }); }; Renderer.prototype.findEdgeViewsInArea = function (rect, options) { var _this = this; if (options === void 0) { options = {}; } var area = geometry_1.Rectangle.create(rect); return this.model .getEdges() .map(function (edge) { return _this.findViewByCell(edge); }) .filter(function (view) { if (view) { var bbox = util_1.Dom.getBBox(view.container, { target: _this.view.stage, }); return options.strict ? area.containsRect(bbox) : area.isIntersectWithRect(bbox); } return false; }); }; Renderer.prototype.findViewsInArea = function (rect, options) { var _this = this; if (options === void 0) { options = {}; } var area = geometry_1.Rectangle.create(rect); return this.model .getNodes() .map(function (node) { return _this.findViewByCell(node); }) .filter(function (view) { if (view) { var bbox = util_1.Dom.getBBox(view.container, { target: _this.view.stage, }); return options.strict ? area.containsRect(bbox) : area.isIntersectWithRect(bbox); } return false; }); }; Renderer.prototype.dispose = function () { this.resetUpdates(); this.stopListening(); }; __decorate([ base_1.Base.dispose() ], Renderer.prototype, "dispose", null); return Renderer; }(base_1.Base)); exports.Renderer = Renderer; (function (Renderer) { Renderer.FLAG_INSERT = 1 << 30; Renderer.FLAG_REMOVE = 1 << 29; Renderer.MOUNT_BATCH_SIZE = 1000; Renderer.UPDATE_BATCH_SIZE = 1000; Renderer.MIN_PRIORITY = 2; Renderer.SORT_DELAYING_BATCHES = [ 'add', 'to-front', 'to-back', ]; Renderer.UPDATE_DELAYING_BATCHES = ['translate']; })(Renderer = exports.Renderer || (exports.Renderer = {})); exports.Renderer = Renderer; //# sourceMappingURL=renderer.js.map