UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering.

986 lines 35.8 kB
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; }; import { Dom, FunctionExt } from '../util'; import { Rectangle } from '../geometry'; import { Cell } from '../model'; import { View, CellView } from '../view'; import { Base } from './base'; export class Renderer extends Base { init() { 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(); } } startListening() { 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); } stopListening() { 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); } resetUpdates() { this.updates = { priorities: [{}, {}, {}], mounted: {}, mountedCids: [], unmounted: {}, unmountedCids: [], count: 0, sort: false, frozen: false, freezeKey: null, animationId: null, }; } onSortModel() { if (this.model.hasActiveBatch(Renderer.SORT_DELAYING_BATCHES)) { return; } this.sortViews(); } onModelReseted({ options }) { this.removeZPivots(); this.resetViews(this.model.getCells(), options); } onBatchStop({ name, data }) { if (this.isFrozen()) { return; } const model = this.model; if (!this.isAsync()) { const updateDelayingBatches = Renderer.UPDATE_DELAYING_BATCHES; if (updateDelayingBatches.includes(name) && !model.hasActiveBatch(updateDelayingBatches)) { this.updateViews(data); } } const sortDelayingBatches = Renderer.SORT_DELAYING_BATCHES; if (sortDelayingBatches.includes(name) && !model.hasActiveBatch(sortDelayingBatches)) { this.sortViews(); } } onCellAdded({ cell, options }) { const 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' }); } } } onCellRemoved({ cell, options }) { const view = this.findViewByCell(cell); if (view) { this.requestViewUpdate(view, Renderer.FLAG_REMOVE, view.priority, options); } } onCellZIndexChanged({ cell, options, }) { if (this.options.sorting === 'approx') { const view = this.findViewByCell(cell); if (view) { this.requestViewUpdate(view, Renderer.FLAG_INSERT, view.priority, options); } } } onCellVisibleChanged({ cell, current: visible, options, }) { // Hide connected edges before cell if (!visible) { this.processEdgeOnTerminalVisibleChanged(cell, false); } const 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); } } processEdgeOnTerminalVisibleChanged(node, visible) { const getOpposite = (edge, currentTerminal) => { const sourceId = edge.getSourceCellId(); if (sourceId !== currentTerminal.id) { return edge.getSourceCell(); } const targetId = edge.getTargetCellId(); if (targetId !== currentTerminal.id) { return edge.getTargetCell(); } return null; }; this.model.getConnectedEdges(node).forEach((edge) => { const opposite = getOpposite(edge, node); if (opposite == null || opposite.isVisible()) { visible ? edge.show() : edge.hide(); } }); } isEdgeTerminalVisible(edge, terminal) { const cellId = terminal === 'source' ? edge.getSourceCellId() : edge.getTargetCellId(); const cell = cellId ? this.model.getCell(cellId) : null; if (cell && !cell.isVisible()) { return false; } return true; } requestConnectedEdgesUpdate(view, options = {}) { if (CellView.isCellView(view)) { const cell = view.cell; const edges = this.model.getConnectedEdges(cell); for (let j = 0, n = edges.length; j < n; j += 1) { const edge = edges[j]; const edgeView = this.findViewByCell(edge); if (!edgeView) { continue; } const 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); } } } forcePostponedViewUpdate(view, flag) { if (!view || !CellView.isCellView(view)) { return false; } const cell = view.cell; if (cell.isNode()) { return false; } const 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. let sourceFlag = 0; const sourceView = this.findViewByCell(cell.getSourceCell()); if (sourceView && !this.isViewMounted(sourceView)) { sourceFlag = this.dumpView(sourceView); edgeView.updateTerminalMagnet('source'); } let targetFlag = 0; const 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; } scheduleViewUpdate(view, flag, priority, options = {}) { const cid = view.cid; const updates = this.updates; let cache = updates.priorities[priority]; if (!cache) { cache = updates.priorities[priority] = {}; } const 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); } requestViewUpdate(view, flag, priority, options = {}) { this.scheduleViewUpdate(view, flag, priority, options); const isAsync = this.isAsync(); if (this.isFrozen() || (isAsync && options.async !== false) || this.model.hasActiveBatch(Renderer.UPDATE_DELAYING_BATCHES)) { return; } const stats = this.updateViews(options); if (isAsync) { this.graph.trigger('render:done', { stats, options }); } } /** * Adds view into the DOM and update it. */ dumpView(view, options = {}) { if (view == null) { return 0; } const cid = view.cid; const updates = this.updates; const cache = updates.priorities[view.priority]; const 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. */ dumpViews(options = {}) { this.checkView(options); this.updateViews(options); } /** * Ensure the view associated with the cell is attached * to the DOM and updated. */ requireView(cell, options = {}) { const view = this.findViewByCell(cell); if (view == null) { return null; } this.dumpView(view, options); return view; } updateView(view, flag, options = {}) { if (view == null) { return 0; } if (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); } updateViews(options = {}) { let result; let batchCount = 0; let updatedCount = 0; let 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, batchCount, updatedCount, }; } updateViewsBatch(options = {}) { const updates = this.updates; const priorities = updates.priorities; const batchSize = options.batchSize || Renderer.UPDATE_BATCH_SIZE; let empty = true; let priority = Renderer.MIN_PRIORITY; let mountedCount = 0; let unmountedCount = 0; let updatedCount = 0; let postponedCount = 0; let checkView = options.checkView || this.options.checkView; if (typeof checkView !== 'function') { checkView = null; } // eslint-disable-next-line main: for (let p = 0, n = priorities.length; p < n; p += 1) { const cache = priorities[p]; // eslint-disable-next-line for (const cid in cache) { if (updatedCount >= batchSize) { empty = false; // goto next batch break main; // eslint-disable-line no-labels } const view = View.views[cid]; if (!view) { delete cache[cid]; continue; } let currentFlag = cache[cid]; // Do not check a view for viewport if we are about to remove the view. if ((currentFlag & Renderer.FLAG_REMOVE) === 0) { const isUnmounted = cid in updates.unmounted; if (checkView && !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); } const cellView = view; let leftoverFlag = this.updateView(view, currentFlag, options); if (leftoverFlag > 0) { const 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, priority, mountedCount, unmountedCount, updatedCount, postponedCount, }; } updateViewsAsync(options = {}, data = { processed: 0, priority: Renderer.MIN_PRIORITY, }) { const updates = this.updates; const animationId = updates.animationId; if (animationId) { Dom.cancelAnimationFrame(animationId); if (data.processed === 0) { const beforeFn = options.before; if (typeof beforeFn === 'function') { FunctionExt.call(beforeFn, this.graph, this.graph); } } const stats = this.updateViewsBatch(options); const checkout = this.checkViewImpl({ checkView: options.checkView, mountedBatchSize: Renderer.MOUNT_BATCH_SIZE - stats.mountedCount, unmountedBatchSize: Renderer.MOUNT_BATCH_SIZE - stats.unmountedCount, }); let processed = data.processed; const total = updates.count; const mountedCount = checkout.mountedCount; const 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, options }); data.processed = 0; updates.count = 0; } else { data.processed = processed; } } // Progress callback const progressFn = options.progress; if (total && typeof progressFn === 'function') { FunctionExt.call(progressFn, this.graph, { total, done: stats.empty, current: processed, }); } // The current frame could have been canceled in a callback if (updates.animationId !== animationId) { return; } } updates.animationId = Dom.requestAnimationFrame(() => { this.updateViewsAsync(options, data); }); } registerMountedView(view) { const cid = view.cid; const updates = this.updates; if (cid in updates.mounted) { return 0; } updates.mounted[cid] = true; updates.mountedCids.push(cid); const flag = updates.unmounted[cid] || 0; delete updates.unmounted[cid]; return flag; } registerUnmountedView(view) { const cid = view.cid; const updates = this.updates; if (cid in updates.unmounted) { return 0; } updates.unmounted[cid] |= Renderer.FLAG_INSERT; const flag = updates.unmounted[cid]; updates.unmountedCids.push(cid); delete updates.mounted[cid]; return flag; } isViewMounted(view) { if (view == null) { return false; } const cid = view.cid; return cid in this.updates.mounted; } getMountedViews() { return Object.keys(this.updates.mounted).map((cid) => CellView.views[cid]); } getUnmountedViews() { return Object.keys(this.updates.unmounted).map((cid) => CellView.views[cid]); } checkMountedViews(viewportFn, batchSize) { let unmountCount = 0; if (typeof viewportFn !== 'function') { return unmountCount; } const updates = this.updates; const mounted = updates.mounted; const mountedCids = updates.mountedCids; const size = batchSize == null ? mountedCids.length : Math.min(mountedCids.length, batchSize); for (let i = 0; i < size; i += 1) { const cid = mountedCids[i]; if (!(cid in mounted)) { continue; } const view = CellView.views[cid]; if (view == null) { continue; } const shouldMount = 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; const flag = this.registerUnmountedView(view); if (flag) { view.unmount(); } } // Get rid of views, that have been unmounted mountedCids.splice(0, size); return unmountCount; } checkUnmountedViews(checkView, batchSize) { let mountCount = 0; if (typeof checkView !== 'function') { checkView = null; // eslint-disable-line } const updates = this.updates; const unmounted = updates.unmounted; const unmountedCids = updates.unmountedCids; const size = batchSize == null ? unmountedCids.length : Math.min(unmountedCids.length, batchSize); for (let i = 0; i < size; i += 1) { const cid = unmountedCids[i]; if (!(cid in unmounted)) { continue; } const view = CellView.views[cid]; if (view == null) { continue; } if (checkView && !FunctionExt.call(checkView, this.graph, { view, unmounted: false })) { unmountedCids.push(cid); continue; } mountCount += 1; const 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; } checkViewImpl(options = { mountedBatchSize: Number.MAX_SAFE_INTEGER, unmountedBatchSize: Number.MAX_SAFE_INTEGER, }) { const checkView = options.checkView || this.options.checkView; const unmountedCount = this.checkMountedViews(checkView, options.unmountedBatchSize); const 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, unmountedCount }; } /** * Determine every view in the graph should be attached/detached. */ checkView(options = {}) { return this.checkViewImpl(options); } isFrozen() { 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. */ freeze(options = {}) { const key = options.key; const updates = this.updates; const frozen = this.options.frozen; const 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; const animationId = updates.animationId; updates.animationId = null; if (this.isAsync() && animationId != null) { Dom.cancelAnimationFrame(animationId); } this.graph.trigger('freeze', { key }); } unfreeze(options = {}) { const key = options.key; const updates = this.updates; const 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; } const callback = () => { this.options.frozen = updates.frozen = false; if (updates.sort) { this.sortViews(); updates.sort = false; } const afterFn = options.after; if (afterFn) { FunctionExt.call(afterFn, this.graph, this.graph); } this.graph.trigger('unfreeze', { key }); }; if (this.isAsync()) { this.freeze(); const onProgress = options.progress; this.updateViewsAsync(Object.assign(Object.assign({}, options), { progress: ({ done, current, total }) => { if (onProgress) { FunctionExt.call(onProgress, this.graph, { done, current, total }); } // sort views after async render if (done) { callback(); } } })); } else { this.updateViews(options); callback(); } } isAsync() { return !!this.options.async; } setAsync(async) { this.options.async = async; } onRemove() { this.freeze(); this.removeViews(); } resetViews(cells = [], options = {}) { this.resetUpdates(); this.removeViews(); this.freeze({ key: 'reset' }); for (let i = 0, n = cells.length; i < n; i += 1) { this.renderView(cells[i], options); } this.unfreeze({ key: 'reset' }); this.sortViews(); } removeView(cell) { const view = this.views[cell.id]; if (view) { const cid = view.cid; const updates = this.updates; const mounted = updates.mounted; const unmounted = updates.unmounted; view.remove(); delete this.views[cell.id]; delete mounted[cid]; delete unmounted[cid]; } return view; } removeViews() { if (this.views) { Object.keys(this.views).forEach((id) => { const view = this.views[id]; if (view) { this.removeView(view.cell); } }); } this.views = {}; } renderView(cell, options = {}) { const id = cell.id; const views = this.views; let flag = 0; let 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 { const 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); } } isExactSorting() { return this.options.sorting === 'exact'; } sortViews() { if (!this.isExactSorting()) { return; } if (this.isFrozen()) { // sort views once unfrozen this.updates.sort = true; return; } this.sortViewsExact(); } sortElements(elems, comparator) { // Highly inspired by the jquery.sortElements plugin by Padolsey. // See http://james.padolsey.com/javascript/sorting-elements-with-jquery/. const placements = elems.map((elem) => { const 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: const nextSibling = parentNode.insertBefore(document.createTextNode(''), elem.nextSibling); return (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((elem, index) => placements[index](elem)); } sortViewsExact() { // 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. const elems = this.view .$(this.view.stage) .children('[data-cell-id]') .toArray(); const model = this.model; this.sortElements(elems, (a, b) => { const cellA = model.getCell(a.getAttribute('data-cell-id') || ''); const cellB = model.getCell(b.getAttribute('data-cell-id') || ''); const z1 = cellA.getZIndex() || 0; const z2 = cellB.getZIndex() || 0; return z1 === z2 ? 0 : z1 < z2 ? -1 : 1; }); } addZPivot(zIndex = 0) { if (this.zPivots == null) { this.zPivots = {}; } const pivots = this.zPivots; let pivot = pivots[zIndex]; if (pivot) { return pivot; } pivot = pivots[zIndex] = document.createComment(`z-index:${zIndex + 1}`); let neighborZ = -Infinity; // eslint-disable-next-line for (const key in pivots) { const currentZ = +key; if (currentZ < zIndex && currentZ > neighborZ) { neighborZ = currentZ; if (neighborZ === zIndex - 1) { continue; } } } const layer = this.view.stage; if (neighborZ !== -Infinity) { const neighborPivot = pivots[neighborZ]; layer.insertBefore(pivot, neighborPivot.nextSibling); } else { layer.insertBefore(pivot, layer.firstChild); } return pivot; } removeZPivots() { if (this.zPivots) { Object.keys(this.zPivots).forEach((z) => { const elem = this.zPivots[z]; if (elem && elem.parentNode) { elem.parentNode.removeChild(elem); } }); } this.zPivots = {}; } insertView(view) { const stage = this.view.stage; switch (this.options.sorting) { case 'approx': { const zIndex = view.cell.getZIndex(); const pivot = this.addZPivot(zIndex); stage.insertBefore(view.container, pivot); break; } case 'exact': default: stage.appendChild(view.container); break; } } findViewByCell(cell) { if (cell == null) { return null; } const id = Cell.isCell(cell) ? cell.id : cell; return this.views[id]; } findViewByElem(elem) { if (elem == null) { return null; } const target = typeof elem === 'string' ? this.view.stage.querySelector(elem) : elem instanceof Element ? elem : elem[0]; if (target) { const id = this.view.findAttr('data-cell-id', target); if (id) { return this.views[id]; } } return null; } findViewsFromPoint(p) { const ref = { x: p.x, y: p.y }; return this.model .getCells() .map((cell) => this.findViewByCell(cell)) .filter((view) => { if (view != null) { return Dom.getBBox(view.container, { target: this.view.stage, }).containsPoint(ref); } return false; }); } findEdgeViewsInArea(rect, options = {}) { const area = Rectangle.create(rect); return this.model .getEdges() .map((edge) => this.findViewByCell(edge)) .filter((view) => { if (view) { const bbox = Dom.getBBox(view.container, { target: this.view.stage, }); return options.strict ? area.containsRect(bbox) : area.isIntersectWithRect(bbox); } return false; }); } findViewsInArea(rect, options = {}) { const area = Rectangle.create(rect); return this.model .getNodes() .map((node) => this.findViewByCell(node)) .filter((view) => { if (view) { const bbox = Dom.getBBox(view.container, { target: this.view.stage, }); return options.strict ? area.containsRect(bbox) : area.isIntersectWithRect(bbox); } return false; }); } dispose() { this.resetUpdates(); this.stopListening(); } } __decorate([ Base.dispose() ], Renderer.prototype, "dispose", null); (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 || (Renderer = {})); //# sourceMappingURL=renderer.js.map