2020-02-21 22:15:02 +08:00

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,
};
}
}