UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering

869 lines 34 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ScrollerImplBackground = exports.ScrollerImpl = exports.defaultOptions = exports.transitionEventName = exports.transitionClassName = exports.backgroundClass = exports.contentClass = exports.pagedClass = exports.pannableClass = exports.panningClass = exports.containerClass = void 0; exports.getOptions = getOptions; const tslib_1 = require("tslib"); const common_1 = require("../../common"); const geometry_1 = require("../../geometry"); const graph_1 = require("../../graph"); const view_1 = require("../../view"); exports.containerClass = 'graph-scroller'; exports.panningClass = `${exports.containerClass}-panning`; exports.pannableClass = `${exports.containerClass}-pannable`; exports.pagedClass = `${exports.containerClass}-paged`; exports.contentClass = `${exports.containerClass}-content`; exports.backgroundClass = `${exports.containerClass}-background`; exports.transitionClassName = 'transition-in-progress'; exports.transitionEventName = 'transitionend.graph-scroller-transition'; exports.defaultOptions = { padding() { const size = this.getClientSize(); const minWidth = Math.max(this.options.minVisibleWidth || 0, 1) || 1; const minHeight = Math.max(this.options.minVisibleHeight || 0, 1) || 1; const left = Math.max(size.width - minWidth, 0); const top = Math.max(size.height - minHeight, 0); return { left, top, right: left, bottom: top }; }, minVisibleWidth: 50, minVisibleHeight: 50, pageVisible: false, pageBreak: false, autoResize: true, }; function getOptions(options) { const result = common_1.ObjectExt.merge({}, exports.defaultOptions, options); if (result.pageWidth == null) { result.pageWidth = options.graph.options.width; } if (result.pageHeight == null) { result.pageHeight = options.graph.options.height; } const graphOptions = options.graph.options; if (graphOptions.background && result.enabled && result.background == null) { result.background = graphOptions.background; options.graph.background.clear(); } return result; } class ScrollerImpl extends view_1.View { get graph() { return this.options.graph; } get model() { return this.graph.model; } constructor(options) { super(); this.padding = { left: 0, top: 0, right: 0, bottom: 0 }; this.options = getOptions(options); this.onUpdate = common_1.FunctionExt.debounce(this.onUpdate, 200); const scale = this.graph.transform.getScale(); this.sx = scale.sx; this.sy = scale.sy; const width = this.options.width || this.graph.options.width; const height = this.options.height || this.graph.options.height; this.container = document.createElement('div'); common_1.Dom.addClass(this.container, this.prefixClassName(exports.containerClass)); common_1.Dom.css(this.container, { width, height }); if (this.options.pageVisible) { common_1.Dom.addClass(this.container, this.prefixClassName(exports.pagedClass)); } if (this.options.className) { common_1.Dom.addClass(this.container, this.options.className); } const graphContainer = this.graph.container; if (graphContainer.parentNode) { common_1.Dom.before(graphContainer, this.container); } this.content = document.createElement('div'); common_1.Dom.addClass(this.content, this.prefixClassName(exports.contentClass)); common_1.Dom.css(this.content, { width: this.graph.options.width, height: this.graph.options.height, }); // custom background this.background = document.createElement('div'); common_1.Dom.addClass(this.background, this.prefixClassName(exports.backgroundClass)); common_1.Dom.append(this.content, this.background); if (!this.options.pageVisible) { common_1.Dom.append(this.content, this.graph.view.grid); } common_1.Dom.append(this.content, graphContainer); common_1.Dom.appendTo(this.content, this.container); this.startListening(); if (!this.options.pageVisible) { this.graph.grid.update(); } this.backgroundManager = new ScrollerImplBackground(this); if (!this.options.autoResize) { this.update(); } } startListening() { const graph = this.graph; const model = this.model; graph.on('scale', this.onScale, this); graph.on('resize', this.onResize, this); graph.on('before:print', this.storeScrollPosition, this); graph.on('before:export', this.storeScrollPosition, this); graph.on('after:print', this.restoreScrollPosition, this); graph.on('after:export', this.restoreScrollPosition, this); model.on('reseted', this.onUpdate, this); model.on('cell:added', this.onUpdate, this); model.on('cell:removed', this.onUpdate, this); model.on('cell:changed', this.onUpdate, this); this.delegateBackgroundEvents(); } stopListening() { const graph = this.graph; const model = this.model; graph.off('scale', this.onScale, this); graph.off('resize', this.onResize, this); graph.off('beforeprint', this.storeScrollPosition, this); graph.off('beforeexport', this.storeScrollPosition, this); graph.off('afterprint', this.restoreScrollPosition, this); graph.off('afterexport', this.restoreScrollPosition, this); model.off('reseted', this.onUpdate, this); model.off('cell:added', this.onUpdate, this); model.off('cell:removed', this.onUpdate, this); model.off('cell:changed', this.onUpdate, this); this.undelegateBackgroundEvents(); } enableAutoResize() { this.options.autoResize = true; } disableAutoResize() { this.options.autoResize = false; } onUpdate() { if (this.options.autoResize) { this.update(); } } delegateBackgroundEvents(events) { const evts = events || graph_1.GraphView.events; this.delegatedHandlers = Object.keys(evts).reduce((memo, name) => { const handler = evts[name]; if (name.indexOf(' ') === -1) { if (typeof handler === 'function') { memo[name] = handler; } else { let method = this.graph.view[handler]; if (typeof method === 'function') { method = method.bind(this.graph.view); memo[name] = method; } } } return memo; }, {}); this.onBackgroundEvent = this.onBackgroundEvent.bind(this); Object.keys(this.delegatedHandlers).forEach((name) => { this.delegateEvent(name, { guarded: false, }, this.onBackgroundEvent); }); } undelegateBackgroundEvents() { Object.keys(this.delegatedHandlers).forEach((name) => { this.undelegateEvent(name, this.onBackgroundEvent); }); } onBackgroundEvent(e) { let valid = false; const target = e.target; if (!this.options.pageVisible) { const view = this.graph.view; valid = view.background === target || view.grid === target; } else if (this.options.background) { valid = this.background === target; } else { valid = this.content === target; } if (valid) { const handler = this.delegatedHandlers[e.type]; if (typeof handler === 'function') { handler.apply(this.graph, arguments); // eslint-disable-line } } } onResize() { if (this.cachedCenterPoint) { this.centerPoint(this.cachedCenterPoint.x, this.cachedCenterPoint.y); this.updatePageBreak(); } } onScale({ sx, sy, ox, oy }) { this.updateScale(sx, sy); if (ox || oy) { this.centerPoint(ox, oy); this.updatePageBreak(); } const autoResizeOptions = this.options.autoResizeOptions; if (typeof autoResizeOptions === 'function') { this.update(); } } storeScrollPosition() { this.cachedScrollLeft = this.container.scrollLeft; this.cachedScrollTop = this.container.scrollTop; } restoreScrollPosition() { this.container.scrollLeft = this.cachedScrollLeft; this.container.scrollTop = this.cachedScrollTop; this.cachedScrollLeft = null; this.cachedScrollTop = null; } storeClientSize() { this.cachedClientSize = { width: this.container.clientWidth, height: this.container.clientHeight, }; } restoreClientSize() { this.cachedClientSize = null; } beforeManipulation() { if (common_1.IS_IE || common_1.IS_EDGE) { common_1.Dom.css(this.container, { visibility: 'hidden' }); } } afterManipulation() { if (common_1.IS_IE || common_1.IS_EDGE) { common_1.Dom.css(this.container, { visibility: 'visible' }); } } updatePageSize(width, height) { if (width != null) { this.options.pageWidth = width; } if (height != null) { this.options.pageHeight = height; } this.updatePageBreak(); } updatePageBreak() { if (this.pageBreak && this.pageBreak.parentNode) { this.pageBreak.parentNode.removeChild(this.pageBreak); } this.pageBreak = null; if (this.options.pageVisible && this.options.pageBreak) { const graphWidth = this.graph.options.width; const graphHeight = this.graph.options.height; const pageWidth = this.options.pageWidth * this.sx; const pageHeight = this.options.pageHeight * this.sy; if (pageWidth === 0 || pageHeight === 0) { return; } if (graphWidth > pageWidth || graphHeight > pageHeight) { let hasPageBreak = false; const container = document.createElement('div'); for (let i = 1, l = Math.floor(graphWidth / pageWidth); i < l; i += 1) { const div = document.createElement('div'); common_1.Dom.addClass(div, this.prefixClassName(`graph-pagebreak-vertical`)); common_1.Dom.css(div, { left: i * pageWidth }); common_1.Dom.appendTo(div, container); hasPageBreak = true; } for (let i = 1, l = Math.floor(graphHeight / pageHeight); i < l; i += 1) { const div = document.createElement('div'); common_1.Dom.addClass(div, this.prefixClassName(`graph-pagebreak-horizontal`)); common_1.Dom.css(div, { top: i * pageHeight }); common_1.Dom.appendTo(div, container); hasPageBreak = true; } if (hasPageBreak) { common_1.Dom.addClass(container, this.prefixClassName('graph-pagebreak')); common_1.Dom.after(this.graph.view.grid, container); this.pageBreak = container; } } } } update() { const size = this.getClientSize(); this.cachedCenterPoint = this.clientToLocalPoint(size.width / 2, size.height / 2); let resizeOptions = this.options.autoResizeOptions; if (typeof resizeOptions === 'function') { resizeOptions = common_1.FunctionExt.call(resizeOptions, this, this); } const options = Object.assign({ gridWidth: this.options.pageWidth, gridHeight: this.options.pageHeight, allowNewOrigin: 'negative' }, resizeOptions); this.graph.fitToContent(this.getFitToContentOptions(options)); } getFitToContentOptions(options) { const sx = this.sx; const sy = this.sy; options.gridWidth && (options.gridWidth *= sx); options.gridHeight && (options.gridHeight *= sy); options.minWidth && (options.minWidth *= sx); options.minHeight && (options.minHeight *= sy); if (typeof options.padding === 'object') { options.padding = { left: (options.padding.left || 0) * sx, right: (options.padding.right || 0) * sx, top: (options.padding.top || 0) * sy, bottom: (options.padding.bottom || 0) * sy, }; } else if (typeof options.padding === 'number') { options.padding *= sx; } if (!this.options.autoResize) { options.contentArea = geometry_1.Rectangle.create(); } return options; } updateScale(sx, sy) { const options = this.graph.options; const dx = sx / this.sx; const dy = sy / this.sy; this.sx = sx; this.sy = sy; this.graph.translate(options.x * dx, options.y * dy); this.graph.transform.resize(options.width * dx, options.height * dy); } scrollbarPosition(left, top) { if (left == null && top == null) { return { left: this.container.scrollLeft, top: this.container.scrollTop, }; } const prop = {}; if (typeof left === 'number') { prop.scrollLeft = left; } if (typeof top === 'number') { prop.scrollTop = top; } common_1.Dom.prop(this.container, prop); return this; } /** * Try to scroll to ensure that the position (x,y) on the graph (in local * coordinates) is at the center of the viewport. If only one of the * coordinates is specified, only scroll in the specified dimension and * keep the other coordinate unchanged. */ scrollToPoint(x, y) { const size = this.getClientSize(); const ctm = this.graph.matrix(); const prop = {}; if (typeof x === 'number') { prop.scrollLeft = x - size.width / 2 + ctm.e + (this.padding.left || 0); } if (typeof y === 'number') { prop.scrollTop = y - size.height / 2 + ctm.f + (this.padding.top || 0); } common_1.Dom.prop(this.container, prop); return this; } /** * Try to scroll to ensure that the center of graph content is at the * center of the viewport. */ scrollToContent() { const sx = this.sx; const sy = this.sy; const center = this.graph.getContentArea().getCenter(); return this.scrollToPoint(center.x * sx, center.y * sy); } /** * Try to scroll to ensure that the center of cell is at the center of * the viewport. */ scrollToCell(cell) { const sx = this.sx; const sy = this.sy; const center = cell.getBBox().getCenter(); return this.scrollToPoint(center.x * sx, center.y * sy); } /** * The center methods are more aggressive than the scroll methods. These * methods position the graph so that a specific point on the graph lies * at the center of the viewport, adding paddings around the paper if * necessary (e.g. if the requested point lies in a corner of the paper). * This means that the requested point will always move into the center * of the viewport. (Use the scroll functions to avoid adding paddings * and only scroll the viewport as far as the graph boundary.) */ /** * Position the center of graph to the center of the viewport. */ center(optons) { return this.centerPoint(optons); } centerPoint(x, y, options) { const ctm = this.graph.matrix(); const sx = ctm.a; const sy = ctm.d; const tx = -ctm.e; const ty = -ctm.f; const tWidth = tx + this.graph.options.width; const tHeight = ty + this.graph.options.height; let localOptions; this.storeClientSize(); // avoid multilple reflow if (typeof x === 'number' || typeof y === 'number') { localOptions = options; const visibleCenter = this.getVisibleArea().getCenter(); if (typeof x === 'number') { x *= sx; // eslint-disable-line } else { x = visibleCenter.x; // eslint-disable-line } if (typeof y === 'number') { y *= sy; // eslint-disable-line } else { y = visibleCenter.y; // eslint-disable-line } } else { localOptions = x; x = (tx + tWidth) / 2; // eslint-disable-line y = (ty + tHeight) / 2; // eslint-disable-line } if (localOptions && localOptions.padding) { return this.positionPoint({ x, y }, '50%', '50%', localOptions); } const padding = this.getPadding(); const clientSize = this.getClientSize(); const cx = clientSize.width / 2; const cy = clientSize.height / 2; const left = cx - padding.left - x + tx; const right = cx - padding.right + x - tWidth; const top = cy - padding.top - y + ty; const bottom = cy - padding.bottom + y - tHeight; this.addPadding(Math.max(left, 0), Math.max(right, 0), Math.max(top, 0), Math.max(bottom, 0)); const result = this.scrollToPoint(x, y); this.restoreClientSize(); return result; } centerContent(options) { return this.positionContent('center', options); } centerCell(cell, options) { return this.positionCell(cell, 'center', options); } /** * The position methods are a more general version of the center methods. * They position the graph so that a specific point on the graph lies at * requested coordinates inside the viewport. */ /** * */ positionContent(pos, options) { const rect = this.graph.getContentArea(options); return this.positionRect(rect, pos, options); } positionCell(cell, pos, options) { const bbox = cell.getBBox(); return this.positionRect(bbox, pos, options); } positionRect(rect, pos, options) { const bbox = geometry_1.Rectangle.create(rect); switch (pos) { case 'center': return this.positionPoint(bbox.getCenter(), '50%', '50%', options); case 'top': return this.positionPoint(bbox.getTopCenter(), '50%', 0, options); case 'top-right': return this.positionPoint(bbox.getTopRight(), '100%', 0, options); case 'right': return this.positionPoint(bbox.getRightMiddle(), '100%', '50%', options); case 'bottom-right': return this.positionPoint(bbox.getBottomRight(), '100%', '100%', options); case 'bottom': return this.positionPoint(bbox.getBottomCenter(), '50%', '100%', options); case 'bottom-left': return this.positionPoint(bbox.getBottomLeft(), 0, '100%', options); case 'left': return this.positionPoint(bbox.getLeftMiddle(), 0, '50%', options); case 'top-left': return this.positionPoint(bbox.getTopLeft(), 0, 0, options); default: return this; } } positionPoint(point, x, y, options = {}) { const { padding: pad } = options, localOptions = tslib_1.__rest(options, ["padding"]); const padding = common_1.NumberExt.normalizeSides(pad); const clientRect = geometry_1.Rectangle.fromSize(this.getClientSize()); const targetRect = clientRect.clone().moveAndExpand({ x: padding.left, y: padding.top, width: -padding.right - padding.left, height: -padding.top - padding.bottom, }); // eslint-disable-next-line x = common_1.NumberExt.normalizePercentage(x, Math.max(0, targetRect.width)); if (x < 0) { x = targetRect.width + x; // eslint-disable-line } // eslint-disable-next-line y = common_1.NumberExt.normalizePercentage(y, Math.max(0, targetRect.height)); if (y < 0) { y = targetRect.height + y; // eslint-disable-line } const origin = targetRect.getTopLeft().translate(x, y); const diff = clientRect.getCenter().diff(origin); const scale = this.zoom(); const rawDiff = diff.scale(1 / scale, 1 / scale); const result = geometry_1.Point.create(point).translate(rawDiff); return this.centerPoint(result.x, result.y, localOptions); } zoom(factor, options) { if (factor == null) { return this.sx; } options = options || {}; // eslint-disable-line let cx; let cy; const clientSize = this.getClientSize(); const center = this.clientToLocalPoint(clientSize.width / 2, clientSize.height / 2); let sx = factor; let sy = factor; if (!options.absolute) { sx += this.sx; sy += this.sy; } if (options.scaleGrid) { sx = Math.round(sx / options.scaleGrid) * options.scaleGrid; sy = Math.round(sy / options.scaleGrid) * options.scaleGrid; } if (options.maxScale) { sx = Math.min(options.maxScale, sx); sy = Math.min(options.maxScale, sy); } if (options.minScale) { sx = Math.max(options.minScale, sx); sy = Math.max(options.minScale, sy); } sx = this.graph.transform.clampScale(sx); sy = this.graph.transform.clampScale(sy); if (options.center) { const fx = sx / this.sx; const fy = sy / this.sy; cx = options.center.x - (options.center.x - center.x) / fx; cy = options.center.y - (options.center.y - center.y) / fy; } else { cx = center.x; cy = center.y; } this.beforeManipulation(); this.graph.transform.scale(sx, sy, cx, cy, false); this.centerPoint(cx, cy); this.afterManipulation(); return this; } zoomToRect(rect, options = {}) { const area = geometry_1.Rectangle.create(rect); const graph = this.graph; options.contentArea = area; if (options.viewportArea == null) { const bound = this.container.getBoundingClientRect(); options.viewportArea = { x: graph.options.x, y: graph.options.y, width: bound.width, height: bound.height, }; } this.beforeManipulation(); graph.transform.scaleContentToFitImpl(options, false); const center = area.getCenter(); this.centerPoint(center.x, center.y); this.afterManipulation(); return this; } zoomToFit(options = {}) { return this.zoomToRect(this.graph.getContentArea(options), options); } transitionToPoint(x, y, options) { if (typeof x === 'object') { options = y; // eslint-disable-line y = x.y; // eslint-disable-line x = x.x; // eslint-disable-line } else { y = y; // eslint-disable-line } if (options == null) { options = {}; // eslint-disable-line } let transform; let transformOrigin; const scale = this.sx; const targetScale = Math.max(options.scale || scale, 0.000001); const clientSize = this.getClientSize(); const targetPoint = new geometry_1.Point(x, y); const localPoint = this.clientToLocalPoint(clientSize.width / 2, clientSize.height / 2); if (scale === targetScale) { const translate = localPoint.diff(targetPoint).scale(scale, scale).round(); transform = `translate(${translate.x}px,${translate.y}px)`; } else { const delta = (targetScale / (scale - targetScale)) * targetPoint.distance(localPoint); const range = localPoint.clone().move(targetPoint, delta); const origin = this.localToBackgroundPoint(range).round(); transform = `scale(${targetScale / scale})`; transformOrigin = `${origin.x}px ${origin.y}px`; } const onTransitionEnd = options.onTransitionEnd; common_1.Dom.addClass(this.container, exports.transitionClassName); common_1.Dom.Event.off(this.content, exports.transitionEventName); common_1.Dom.Event.on(this.content, exports.transitionEventName, (e) => { this.syncTransition(targetScale, { x: x, y: y }); if (typeof onTransitionEnd === 'function') { common_1.FunctionExt.call(onTransitionEnd, this, e.originalEvent); } }); common_1.Dom.css(this.content, { transform, transformOrigin, transition: 'transform', transitionDuration: options.duration || '1s', transitionDelay: options.delay, transitionTimingFunction: options.timing, }); return this; } syncTransition(scale, p) { this.beforeManipulation(); this.graph.scale(scale); this.removeTransition(); this.centerPoint(p.x, p.y); this.afterManipulation(); return this; } removeTransition() { common_1.Dom.removeClass(this.container, exports.transitionClassName); common_1.Dom.Event.off(this.content, exports.transitionEventName); common_1.Dom.css(this.content, { transform: '', transformOrigin: '', transition: '', transitionDuration: '', transitionDelay: '', transitionTimingFunction: '', }); return this; } transitionToRect(rectangle, options = {}) { const rect = geometry_1.Rectangle.create(rectangle); const maxScale = options.maxScale || Infinity; const minScale = options.minScale || Number.MIN_VALUE; const scaleGrid = options.scaleGrid || null; const PIXEL_SIZE = options.visibility || 1; const center = options.center ? geometry_1.Point.create(options.center) : rect.getCenter(); const clientSize = this.getClientSize(); const w = clientSize.width * PIXEL_SIZE; const h = clientSize.height * PIXEL_SIZE; let scale = new geometry_1.Rectangle(center.x - w / 2, center.y - h / 2, w, h).getMaxUniformScaleToFit(rect, center); scale = Math.min(scale, maxScale); if (scaleGrid) { scale = Math.floor(scale / scaleGrid) * scaleGrid; } scale = Math.max(minScale, scale); return this.transitionToPoint(center, Object.assign({ scale }, options)); } startPanning(evt) { const e = this.normalizeEvent(evt); this.clientX = e.clientX; this.clientY = e.clientY; this.trigger('pan:start', { e }); common_1.Dom.Event.on(document.body, { 'mousemove.panning touchmove.panning': this.pan.bind(this), 'mouseup.panning touchend.panning': this.stopPanning.bind(this), 'mouseleave.panning': this.stopPanning.bind(this), }); common_1.Dom.Event.on(window, 'mouseup.panning', this.stopPanning.bind(this)); } pan(evt) { const e = this.normalizeEvent(evt); const dx = e.clientX - this.clientX; const dy = e.clientY - this.clientY; this.container.scrollTop -= dy; this.container.scrollLeft -= dx; this.clientX = e.clientX; this.clientY = e.clientY; this.trigger('panning', { e }); } stopPanning(e) { common_1.Dom.Event.off(document.body, '.panning'); common_1.Dom.Event.off(window, '.panning'); this.trigger('pan:stop', { e }); } clientToLocalPoint(a, b) { let x = typeof a === 'object' ? a.x : a; let y = typeof a === 'object' ? a.y : b; const ctm = this.graph.matrix(); x += this.container.scrollLeft - this.padding.left - ctm.e; y += this.container.scrollTop - this.padding.top - ctm.f; return new geometry_1.Point(x / ctm.a, y / ctm.d); } localToBackgroundPoint(x, y) { const p = typeof x === 'object' ? geometry_1.Point.create(x) : new geometry_1.Point(x, y); const ctm = this.graph.matrix(); const padding = this.padding; return common_1.Util.transformPoint(p, ctm).translate(padding.left, padding.top); } resize(width, height) { let w = width != null ? width : this.container.offsetWidth; let h = height != null ? height : this.container.offsetHeight; if (typeof w === 'number') { w = Math.round(w); } if (typeof h === 'number') { h = Math.round(h); } this.options.width = w; this.options.height = h; common_1.Dom.css(this.container, { width: w, height: h }); this.update(); } getClientSize() { if (this.cachedClientSize) { return this.cachedClientSize; } return { width: this.container.clientWidth, height: this.container.clientHeight, }; } autoScroll(clientX, clientY) { const buffer = 10; const container = this.container; const rect = container.getBoundingClientRect(); let dx = 0; let dy = 0; if (clientX <= rect.left + buffer) { dx = -buffer; } if (clientY <= rect.top + buffer) { dy = -buffer; } if (clientX >= rect.right - buffer) { dx = buffer; } if (clientY >= rect.bottom - buffer) { dy = buffer; } if (dx !== 0) { container.scrollLeft += dx; } if (dy !== 0) { container.scrollTop += dy; } return { scrollerX: dx, scrollerY: dy, }; } addPadding(left, right, top, bottom) { let padding = this.getPadding(); this.padding = { left: Math.round(padding.left + (left || 0)), top: Math.round(padding.top + (top || 0)), bottom: Math.round(padding.bottom + (bottom || 0)), right: Math.round(padding.right + (right || 0)), }; padding = this.padding; common_1.Dom.css(this.content, { width: padding.left + this.graph.options.width + padding.right, height: padding.top + this.graph.options.height + padding.bottom, }); const container = this.graph.container; container.style.left = `${this.padding.left}px`; container.style.top = `${this.padding.top}px`; return this; } getPadding() { const padding = this.options.padding; if (typeof padding === 'function') { return common_1.NumberExt.normalizeSides(common_1.FunctionExt.call(padding, this, this)); } return common_1.NumberExt.normalizeSides(padding); } /** * Returns the untransformed size and origin of the current viewport. */ getVisibleArea() { const ctm = this.graph.matrix(); const size = this.getClientSize(); const box = { x: this.container.scrollLeft || 0, y: this.container.scrollTop || 0, width: size.width, height: size.height, }; const area = common_1.Util.transformRectangle(box, ctm.inverse()); area.x -= (this.padding.left || 0) / this.sx; area.y -= (this.padding.top || 0) / this.sy; return area; } isCellVisible(cell, options = {}) { const bbox = cell.getBBox(); const area = this.getVisibleArea(); return options.strict ? area.containsRect(bbox) : area.isIntersectWithRect(bbox); } isPointVisible(point) { return this.getVisibleArea().containsPoint(point); } /** * Lock the current viewport by disabling user scrolling. */ lock() { common_1.Dom.css(this.container, { overflow: 'hidden' }); return this; } /** * Enable user scrolling if previously locked. */ unlock() { common_1.Dom.css(this.container, { overflow: 'scroll' }); return this; } onRemove() { this.stopListening(); } dispose() { common_1.Dom.before(this.container, this.graph.container); this.remove(); } } exports.ScrollerImpl = ScrollerImpl; tslib_1.__decorate([ (0, common_1.disposable)() ], ScrollerImpl.prototype, "dispose", null); class ScrollerImplBackground extends graph_1.BackgroundManager { get elem() { return this.scroller.background; } constructor(scroller) { super(scroller.graph); this.scroller = scroller; if (scroller.options.background) { this.draw(scroller.options.background); } } init() { this.graph.on('scale', this.update, this); this.graph.on('translate', this.update, this); } updateBackgroundOptions(options) { this.scroller.options.background = options; } } exports.ScrollerImplBackground = ScrollerImplBackground; //# sourceMappingURL=scroller.js.map