refactor: refactor calculator

This commit is contained in:
chenshenhai 2023-06-11 15:38:07 +08:00
parent 7fdd24a765
commit f4ebe720a4
4 changed files with 32 additions and 149 deletions

View file

@ -1,14 +1,5 @@
import type { Data, Point, Element, ElementType, ViewCalculator, ViewCalculatorOptions, ViewScaleInfo, ElementSize, ViewSizeInfo } from '@idraw/types';
import {
rotateElementVertexes,
checkRectIntersect,
viewScale,
viewScroll,
calcElementSize,
isViewPointInElement,
getViewPointAtElement,
isElementInView
} from '@idraw/util';
import { calcElementSize, isViewPointInElement, getViewPointAtElement, isElementInView } from '@idraw/util';
export class Calculator implements ViewCalculator {
private _opts: ViewCalculatorOptions;
@ -17,135 +8,31 @@ export class Calculator implements ViewCalculator {
this._opts = opts;
}
viewScroll(opts: { moveX?: number; moveY?: number }, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ViewScaleInfo {
const scale = viewScaleInfo.scale;
const { moveX, moveY } = opts;
const { width, height, contextWidth, contextHeight } = viewSizeInfo;
let offsetLeft = viewScaleInfo.offsetLeft;
let offsetRight = viewScaleInfo.offsetRight;
let offsetTop = viewScaleInfo.offsetTop;
let offsetBottom = viewScaleInfo.offsetBottom;
if (moveX !== undefined && (moveX > 0 || moveX <= 0)) {
if (contextWidth * scale < width) {
offsetLeft = offsetRight = (width - contextWidth * scale) / 2;
} else if (contextWidth * scale > width) {
if (offsetLeft + moveX >= 0) {
offsetLeft = 0;
offsetRight = width - contextWidth * scale;
} else if (offsetLeft + moveX < width - contextWidth * scale) {
offsetLeft = width - contextWidth * scale;
offsetRight = 0;
} else {
offsetLeft += moveX;
offsetRight = width - contextWidth * scale - offsetLeft;
}
} else {
offsetLeft = offsetRight = 0;
}
}
if (moveY !== undefined && (moveY > 0 || moveY <= 0)) {
if (contextHeight * scale < height) {
offsetTop = offsetBottom = (height - contextHeight * scale) / 2;
} else if (contextHeight * scale > height) {
if (offsetTop + moveY >= 0) {
offsetTop = 0;
offsetBottom = height - contextHeight * scale;
} else if (offsetTop + moveY < height - contextHeight * scale) {
offsetTop = height - contextHeight * scale;
offsetBottom = 0;
} else {
offsetTop += moveY;
offsetBottom = height - contextHeight * scale - offsetTop;
}
} else {
offsetTop = offsetBottom = 0;
}
}
return {
scale,
offsetTop,
offsetLeft,
offsetRight,
offsetBottom
};
}
elementSize(size: ElementSize, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ElementSize {
const { x, y, w, h, angle } = size;
const { contextX = 0, contextY = 0 } = viewSizeInfo;
const { scale, offsetTop, offsetLeft } = viewScaleInfo;
const newSize = {
x: x * scale + offsetLeft - contextX,
y: y * scale + offsetTop - contextY,
w: w * scale,
h: h * scale,
angle
};
return newSize;
return calcElementSize(size, { viewScaleInfo, viewSizeInfo });
}
isElementInView(elem: ElementSize, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean {
const { width, height } = viewSizeInfo;
const { angle } = elem;
const { x, y, w, h } = this.elementSize(elem, viewScaleInfo, viewSizeInfo);
const ves = rotateElementVertexes({ x, y, w, h, angle });
const viewSize = { x: 0, y: 0, w: width, h: height };
const elemStartX = Math.min(ves[0].x, ves[1].x, ves[2].x, ves[3].x);
const elemStartY = Math.min(ves[0].y, ves[1].y, ves[2].y, ves[3].y);
const elemEndX = Math.max(ves[0].x, ves[1].x, ves[2].x, ves[3].x);
const elemEndY = Math.max(ves[0].y, ves[1].y, ves[2].y, ves[3].y);
const elemSize = { x: elemStartX, y: elemStartY, w: elemEndX - elemStartX, h: elemEndY - elemStartY };
return checkRectIntersect(viewSize, elemSize);
return isElementInView(elem, { viewScaleInfo, viewSizeInfo });
}
isPointInElement(p: Point, elem: Element<ElementType>, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): boolean {
const ctx = this._opts.viewContent.boardContext;
const { angle = 0 } = elem;
const { x, y, w, h } = this.elementSize(elem, viewScaleInfo, viewSize);
const vertexes = rotateElementVertexes({ x, y, w, h, angle });
if (vertexes.length >= 2) {
ctx.beginPath();
ctx.moveTo(vertexes[0].x, vertexes[0].y);
for (let i = 1; i < vertexes.length; i++) {
ctx.lineTo(vertexes[i].x, vertexes[i].y);
}
ctx.closePath();
}
if (ctx.isPointInPath(p.x, p.y)) {
return true;
}
return false;
isPointInElement(p: Point, elem: Element<ElementType>, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean {
const context2d = this._opts.viewContent.boardContext;
return isViewPointInElement(p, {
context2d,
element: elem,
viewScaleInfo,
viewSizeInfo
});
}
getPointElement(p: Point, data: Data, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): { index: number; element: null | Element<ElementType> } {
const result: { index: number; element: null | Element<ElementType> } = {
index: -1,
element: null
};
for (let i = data.elements.length - 1; i >= 0; i--) {
const elem = data.elements[i];
if (this.isPointInElement(p, elem, viewScaleInfo, viewSize)) {
result.index = i;
result.element = elem;
break;
}
}
return result;
getPointElement(p: Point, data: Data, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): { index: number; element: null | Element<ElementType> } {
const context2d = this._opts.viewContent.boardContext;
return getViewPointAtElement(p, {
data,
context2d,
viewScaleInfo,
viewSizeInfo
});
}
// rotateElementSize(elemSize: ElementSize): PointSize[] {
// // const { x, y, w, h, angle = 0 } = elemSize;
// // const pointSizes: PointSize[] = [];
// return [];
// }
// pointToViewPoint(p: Point): Point {
// // TODO
// return {};
// }
}

View file

@ -1,4 +1,4 @@
import { EventEmitter, viewScale } from '@idraw/util';
import { EventEmitter, viewScale, viewScroll } from '@idraw/util';
import type { BoardViewer, BoardViewerEventMap, BoardViewerOptions, ActiveStore, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
const { requestAnimationFrame } = window;
@ -93,26 +93,26 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
const { sharer, renderer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const viewScaleInfo = viewScale(num, { prevViewScaleInfo, viewSizeInfo });
const viewScaleInfo = viewScale({ num, prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
renderer.scale(num);
return viewScaleInfo;
}
scrollX(num: number): ViewScaleInfo {
const { sharer, calculator } = this._opts;
const { sharer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const viewScaleInfo = calculator.viewScroll({ moveX: num - (prevViewScaleInfo.offsetLeft || 0) }, prevViewScaleInfo, viewSizeInfo);
const viewScaleInfo = viewScroll({ moveX: num - (prevViewScaleInfo.offsetLeft || 0), viewScaleInfo: prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
return viewScaleInfo;
}
scrollY(num: number): ViewScaleInfo {
const { sharer, calculator } = this._opts;
const { sharer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const viewScaleInfo = calculator.viewScroll({ moveY: num - (prevViewScaleInfo.offsetTop || 0) }, prevViewScaleInfo, viewSizeInfo);
const viewScaleInfo = viewScroll({ moveY: num - (prevViewScaleInfo.offsetTop || 0), viewScaleInfo: prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
return viewScaleInfo;
}

View file

@ -35,10 +35,8 @@ export interface ViewCalculatorOptions {
}
export interface ViewCalculator {
// viewScale(num: number, prevScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): ViewScaleInfo;
isElementInView(elem: Element<ElementType>, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean;
isPointInElement(p: Point, elem: Element<ElementType>, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): boolean;
elementSize(size: ElementSize, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ElementSize;
viewScroll(opts: { moveX?: number; moveY?: number }, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ViewScaleInfo;
getPointElement(p: Point, data: Data, viewScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): { index: number; element: null | Element<ElementType> };
}

View file

@ -1,11 +1,9 @@
import { Point, Data, ViewScaleInfo, ViewSizeInfo, Element, ElementType, ElementSize } from '@idraw/types';
import { Point, Data, ViewScaleInfo, ViewSizeInfo, Element, ElementType, ElementSize, ViewContext2D } from '@idraw/types';
import { rotateElementVertexes } from './rotate';
import { Context2D } from './context2d';
import { checkRectIntersect } from './rect';
export function viewScale(num: number, opts: { prevViewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewScaleInfo {
const scale = num;
const { prevViewScaleInfo, viewSizeInfo } = opts;
export function viewScale(opts: { num: number; prevViewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewScaleInfo {
const { num: scale, prevViewScaleInfo, viewSizeInfo } = opts;
const { width, height, contextWidth, contextHeight } = viewSizeInfo;
let offsetLeft = 0;
let offsetRight = 0;
@ -39,9 +37,9 @@ export function viewScale(num: number, opts: { prevViewScaleInfo: ViewScaleInfo;
};
}
export function viewScroll(opts: { moveX?: number; moveY?: number }, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ViewScaleInfo {
export function viewScroll(opts: { moveX?: number; moveY?: number; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ViewScaleInfo {
const { moveX, moveY, viewScaleInfo, viewSizeInfo } = opts;
const scale = viewScaleInfo.scale;
const { moveX, moveY } = opts;
const { width, height, contextWidth, contextHeight } = viewSizeInfo;
let offsetLeft = viewScaleInfo.offsetLeft;
let offsetRight = viewScaleInfo.offsetRight;
@ -113,7 +111,7 @@ export function calcElementSize(size: ElementSize, opts: { viewScaleInfo: ViewSc
export function isViewPointInElement(
p: Point,
opts: { context2d: Context2D; element: Element<ElementType>; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
opts: { context2d: ViewContext2D; element: Element<ElementType>; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): boolean {
const { context2d: ctx, element: elem, viewScaleInfo, viewSizeInfo } = opts;
@ -137,7 +135,7 @@ export function isViewPointInElement(
export function getViewPointAtElement(
p: Point,
opts: {
context2d: Context2D;
context2d: ViewContext2D;
data: Data;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;