mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2025-12-17 15:23:00 +00:00
150 lines
3.4 KiB
TypeScript
150 lines
3.4 KiB
TypeScript
import { obx, computed } from '@recore/obx';
|
|
import { Point } from '../../../designer/helper/location';
|
|
import { ScrollTarget } from '../../../designer/helper/scroller';
|
|
import { AutoFit, IViewport } from '../../../designer/simulator';
|
|
|
|
export default class Viewport implements IViewport {
|
|
@obx.ref private rect?: DOMRect;
|
|
private _bounds?: DOMRect;
|
|
get bounds(): DOMRect {
|
|
if (this._bounds) {
|
|
return this._bounds;
|
|
}
|
|
this._bounds = this.viewportElement!.getBoundingClientRect();
|
|
requestAnimationFrame(() => {
|
|
this._bounds = undefined;
|
|
});
|
|
return this._bounds;
|
|
}
|
|
|
|
get contentBounds(): DOMRect {
|
|
const bounds = this.bounds;
|
|
const scale = this.scale;
|
|
return new DOMRect(0, 0, bounds.width / scale, bounds.height / scale);
|
|
}
|
|
|
|
private viewportElement?: Element;
|
|
mount(viewportElement: Element | null) {
|
|
if (!viewportElement) {
|
|
return;
|
|
}
|
|
this.viewportElement = viewportElement;
|
|
this.touch();
|
|
}
|
|
|
|
touch() {
|
|
if (this.viewportElement) {
|
|
this.rect = this.bounds;
|
|
}
|
|
}
|
|
|
|
@computed get height(): number {
|
|
if (!this.rect) {
|
|
return 600;
|
|
}
|
|
return this.rect.height;
|
|
}
|
|
@computed get width(): number {
|
|
if (!this.rect) {
|
|
return 1000;
|
|
}
|
|
return this.rect.width;
|
|
}
|
|
|
|
/**
|
|
* 缩放比例
|
|
*/
|
|
get scale(): number {
|
|
if (!this.rect || this.contentWidth === AutoFit) {
|
|
return 1;
|
|
}
|
|
return this.width / this.contentWidth;
|
|
}
|
|
|
|
@obx.ref private _contentWidth: number | AutoFit = AutoFit;
|
|
|
|
get contentHeight(): number | AutoFit {
|
|
if (!this.rect || this.scale === 1) {
|
|
return AutoFit;
|
|
}
|
|
return this.height / this.scale;
|
|
}
|
|
|
|
get contentWidth(): number | AutoFit {
|
|
if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) {
|
|
return AutoFit;
|
|
}
|
|
return this._contentWidth;
|
|
}
|
|
|
|
set contentWidth(val: number | AutoFit) {
|
|
this._contentWidth = val;
|
|
}
|
|
|
|
@obx.ref private _scrollX = 0;
|
|
@obx.ref private _scrollY = 0;
|
|
get scrollX() {
|
|
return this._scrollX;
|
|
}
|
|
get scrollY() {
|
|
return this._scrollY;
|
|
}
|
|
|
|
private _scrollTarget?: ScrollTarget;
|
|
/**
|
|
* 滚动对象
|
|
*/
|
|
get scrollTarget(): ScrollTarget | undefined {
|
|
return this._scrollTarget;
|
|
}
|
|
|
|
@obx private _scrolling: boolean = false;
|
|
get scrolling(): boolean {
|
|
return this._scrolling;
|
|
}
|
|
|
|
setScrollTarget(target: Window) {
|
|
const scrollTarget = new ScrollTarget(target);
|
|
this._scrollX = scrollTarget.left;
|
|
this._scrollY = scrollTarget.top;
|
|
|
|
let scrollTimer: any;
|
|
target.addEventListener('scroll', () => {
|
|
this._scrollX = scrollTarget.left;
|
|
this._scrollY = scrollTarget.top;
|
|
this._scrolling = true;
|
|
if (scrollTimer) {
|
|
clearTimeout(scrollTimer);
|
|
}
|
|
scrollTimer = setTimeout(() => {
|
|
this._scrolling = false;
|
|
}, 80);
|
|
});
|
|
this._scrollTarget = scrollTarget;
|
|
}
|
|
|
|
toGlobalPoint(point: Point): Point {
|
|
if (!this.viewportElement) {
|
|
return point;
|
|
}
|
|
|
|
const rect = this.bounds;
|
|
return {
|
|
clientX: point.clientX * this.scale + rect.left,
|
|
clientY: point.clientY * this.scale + rect.top,
|
|
};
|
|
}
|
|
|
|
toLocalPoint(point: Point): Point {
|
|
if (!this.viewportElement) {
|
|
return point;
|
|
}
|
|
|
|
const rect = this.bounds;
|
|
return {
|
|
clientX: (point.clientX - rect.left) / this.scale,
|
|
clientY: (point.clientY - rect.top) / this.scale,
|
|
};
|
|
}
|
|
}
|