refactor: refactor util calc

This commit is contained in:
chenshenhai 2023-06-11 13:32:53 +08:00
parent 06dc95707b
commit 3aba19d564
30 changed files with 409 additions and 241 deletions

View file

@ -259,21 +259,21 @@ export class Board {
}
scale(num: number) {
const scaleInfo = this._viewer.scale(num);
const viewScaleInfo = this._viewer.scale(num);
this._viewer.drawFrame();
this._watcher.trigger('scale', scaleInfo);
this._watcher.trigger('scale', viewScaleInfo);
}
scrollX(num: number) {
const scaleInfo = this._viewer.scrollX(num);
const viewScaleInfo = this._viewer.scrollX(num);
this._viewer.drawFrame();
this._watcher.trigger('scrollX', scaleInfo);
this._watcher.trigger('scrollX', viewScaleInfo);
}
scrollY(num: number) {
const scaleInfo = this._viewer.scrollY(num);
const viewScaleInfo = this._viewer.scrollY(num);
this._viewer.drawFrame();
this._watcher.trigger('scrollY', scaleInfo);
this._watcher.trigger('scrollY', viewScaleInfo);
}
resize(newViewSize: ViewSizeInfo) {

View file

@ -1,5 +1,14 @@
import type { Data, Point, Element, ElementType, ViewCalculator, ViewCalculatorOptions, ViewScaleInfo, ElementSize, ViewSizeInfo } from '@idraw/types';
import { rotateElementVertexes, checkRectIntersect } from '@idraw/util';
import {
rotateElementVertexes,
checkRectIntersect,
viewScale,
viewScroll,
calcElementSize,
isViewPointInElement,
getViewPointAtElement,
isElementInView
} from '@idraw/util';
export class Calculator implements ViewCalculator {
private _opts: ViewCalculatorOptions;
@ -8,50 +17,14 @@ export class Calculator implements ViewCalculator {
this._opts = opts;
}
viewScale(num: number, prevScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ViewScaleInfo {
const scale = num;
const { width, height, contextWidth, contextHeight } = viewSizeInfo;
let offsetLeft = 0;
let offsetRight = 0;
let offsetTop = 0;
let offsetBottom = 0;
if (contextWidth * scale < width) {
offsetLeft = offsetRight = (width - contextWidth * scale) / 2;
} else if (contextWidth * scale > width) {
if (prevScaleInfo.offsetLeft < 0) {
offsetLeft = (prevScaleInfo.offsetLeft / prevScaleInfo.scale) * scale;
offsetRight = 0 - (contextWidth * scale - width - Math.abs(offsetLeft));
}
}
if (contextHeight * scale < height) {
offsetTop = offsetBottom = (height - contextHeight * scale) / 2;
} else if (contextHeight * scale > height) {
if (prevScaleInfo.offsetTop < 0) {
offsetTop = (prevScaleInfo.offsetTop / prevScaleInfo.scale) * scale;
offsetBottom = 0 - (contextHeight * scale - height - Math.abs(offsetTop));
}
}
return {
scale,
offsetTop,
offsetLeft,
offsetRight,
offsetBottom
};
}
viewScroll(opts: { moveX?: number; moveY?: number }, scaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ViewScaleInfo {
const scale = scaleInfo.scale;
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 = scaleInfo.offsetLeft;
let offsetRight = scaleInfo.offsetRight;
let offsetTop = scaleInfo.offsetTop;
let offsetBottom = scaleInfo.offsetBottom;
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;
@ -99,10 +72,10 @@ export class Calculator implements ViewCalculator {
};
}
elementSize(size: ElementSize, scaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ElementSize {
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 } = scaleInfo;
const { scale, offsetTop, offsetLeft } = viewScaleInfo;
const newSize = {
x: x * scale + offsetLeft - contextX,
@ -113,33 +86,12 @@ export class Calculator implements ViewCalculator {
};
return newSize;
// const { x, y, w, h, angle } = size;
// const { scale, offsetTop, offsetLeft } = scaleInfo;
// return {
// x: x * scale + offsetLeft,
// y: y * scale + offsetTop,
// w: w * scale,
// h: h * scale,
// angle
// };
}
isElementInView(elem: ElementSize, scaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean {
// const { width, height } = viewSizeInfo;
// const { angle } = elem;
// const { x, y, w, h } = this.elementSize(elem, scaleInfo, viewSizeInfo);
// const ves = rotateElementVertexes({ x, y, w, h, angle });
// for (let i = 0; i < ves.length; i++) {
// const v = ves[i];
// if (v.x >= 0 && v.x <= width && v.y >= 0 && v.y <= height) {
// return true;
// }
// }
isElementInView(elem: ElementSize, viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean {
const { width, height } = viewSizeInfo;
const { angle } = elem;
const { x, y, w, h } = this.elementSize(elem, scaleInfo, viewSizeInfo);
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 };
@ -148,14 +100,13 @@ export class Calculator implements ViewCalculator {
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);
}
isPointInElement(p: Point, elem: Element<ElementType>, scaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): boolean {
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, scaleInfo, viewSize);
const { x, y, w, h } = this.elementSize(elem, viewScaleInfo, viewSize);
const vertexes = rotateElementVertexes({ x, y, w, h, angle });
if (vertexes.length >= 2) {
ctx.beginPath();
@ -171,14 +122,14 @@ export class Calculator implements ViewCalculator {
return false;
}
getPointElement(p: Point, data: Data, scaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): { index: number; element: null | Element<ElementType> } {
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, scaleInfo, viewSize)) {
if (this.isPointInElement(p, elem, viewScaleInfo, viewSize)) {
result.index = i;
result.element = elem;
break;

View file

@ -19,10 +19,10 @@ const defaultActiveStorage: ActiveStore = {
offsetBottom: 0
};
export class Sharer implements StoreSharer {
export class Sharer implements StoreSharer<Record<string | number | symbol, any>> {
private _activeStore: Store<ActiveStore>;
private _sharedStore: Store<{
[string: string]: any;
[string: string | number | symbol]: any;
}>;
constructor() {
@ -48,11 +48,11 @@ export class Sharer implements StoreSharer {
return this._activeStore.getSnapshot();
}
getSharedStorage(key: string): any {
getSharedStorage(key: string | number | symbol): any {
return this._sharedStore.get(key);
}
setSharedStorage(key: string, storage: any) {
setSharedStorage(key: string | number | symbol, storage: any) {
return this._sharedStore.set(key, storage);
}
@ -63,18 +63,18 @@ export class Sharer implements StoreSharer {
// get/set active info
getActiveScaleInfo(): ViewScaleInfo {
const scaleInfo: ViewScaleInfo = {
const viewScaleInfo: ViewScaleInfo = {
scale: this._activeStore.get('scale'),
offsetTop: this._activeStore.get('offsetTop'),
offsetBottom: this._activeStore.get('offsetBottom'),
offsetLeft: this._activeStore.get('offsetLeft'),
offsetRight: this._activeStore.get('offsetRight')
};
return scaleInfo;
return viewScaleInfo;
}
setActiveScaleInfo(scaleInfo: ViewScaleInfo) {
const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = scaleInfo;
setActiveScaleInfo(viewScaleInfo: ViewScaleInfo) {
const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
this._activeStore.set('scale', scale);
this._activeStore.set('offsetTop', offsetTop);
this._activeStore.set('offsetBottom', offsetBottom);

View file

@ -1,4 +1,4 @@
import { EventEmitter } from '@idraw/util';
import { EventEmitter, viewScale } from '@idraw/util';
import type { BoardViewer, BoardViewerEventMap, BoardViewerOptions, ActiveStore, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
const { requestAnimationFrame } = window;
@ -40,14 +40,14 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
if (snapshot?.activeStore.data) {
renderer.drawData(snapshot.activeStore.data, {
scaleInfo: {
viewScaleInfo: {
scale,
offsetTop,
offsetBottom,
offsetLeft,
offsetRight
},
viewSize: {
viewSizeInfo: {
width,
height,
contextX,
@ -90,31 +90,31 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
}
scale(num: number): ViewScaleInfo {
const { sharer, renderer, calculator } = this._opts;
const prevScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const { sharer, renderer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const scaleInfo = calculator.viewScale(num, prevScaleInfo, viewSizeInfo);
sharer.setActiveScaleInfo(scaleInfo);
const viewScaleInfo = viewScale(num, { prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
renderer.scale(num);
return scaleInfo;
return viewScaleInfo;
}
scrollX(num: number): ViewScaleInfo {
const { sharer, calculator } = this._opts;
const prevScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const scaleInfo = calculator.viewScroll({ moveX: num - (prevScaleInfo.offsetLeft || 0) }, prevScaleInfo, viewSizeInfo);
sharer.setActiveScaleInfo(scaleInfo);
return scaleInfo;
const viewScaleInfo = calculator.viewScroll({ moveX: num - (prevViewScaleInfo.offsetLeft || 0) }, prevViewScaleInfo, viewSizeInfo);
sharer.setActiveScaleInfo(viewScaleInfo);
return viewScaleInfo;
}
scrollY(num: number): ViewScaleInfo {
const { sharer, calculator } = this._opts;
const prevScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const scaleInfo = calculator.viewScroll({ moveY: num - (prevScaleInfo.offsetTop || 0) }, prevScaleInfo, viewSizeInfo);
sharer.setActiveScaleInfo(scaleInfo);
return scaleInfo;
const viewScaleInfo = calculator.viewScroll({ moveY: num - (prevViewScaleInfo.offsetTop || 0) }, prevViewScaleInfo, viewSizeInfo);
sharer.setActiveScaleInfo(viewScaleInfo);
return viewScaleInfo;
}
resize(viewSize: Partial<ViewSizeInfo> = {}): ViewSizeInfo {

View file

@ -134,8 +134,8 @@ export class BoardWatcher extends EventEmitter<BoardWatcherEventMap> {
}
private _isVaildPoint(p: Point): boolean {
const viewSize = this._opts.sharer.getActiveViewSizeInfo();
const { width, height } = viewSize;
const viewSizeInfo = this._opts.sharer.getActiveViewSizeInfo();
const { width, height } = viewSizeInfo;
if (isBoardAvailableNum(p.x) && isBoardAvailableNum(p.y) && p.x <= width && p.y <= height) {
return true;
}

View file

@ -76,10 +76,10 @@ export class Core {
resize(newViewSize: ViewSizeInfo) {
const sharer = this._board.getSharer();
const scaleInfo = sharer.getActiveScaleInfo();
const viewScaleInfo = sharer.getActiveScaleInfo();
this._board.resize(newViewSize);
// this._board.scale(scaleInfo.scale);
// this._board.scrollX(scaleInfo.offsetLeft);
// this._board.scrollY(scaleInfo.offsetTop);
// this._board.scale(viewScaleInfo.scale);
// this._board.scrollX(viewScaleInfo.offsetLeft);
// this._board.scrollY(viewScaleInfo.offsetTop);
}
}

View file

@ -4,11 +4,12 @@ export const keyActionType = Symbol(`${key}_actionType`); // 'select' | 'drag-li
export const keyResizeType = Symbol(`${key}_resizeType`); // ResizeType | null;
export const keyAreaStart = Symbol(`${key}_areaStart`); // Point
export const keyAreaEnd = Symbol(`${key}_areaEnd`); // Point
export const keyInGroupQueue = Symbol(`${key}_targetQueue`); // Element<'group'>[]
export const keyGroupQueue = Symbol(`${key}_groupQueue`); // Element<'group'>[]
export const keyInGroup = Symbol(`${key}_inGroup`); // Element<'group'>[]
// export const keyHoverElementSize = `${key}_hoverElementSize`;
// export const keyActionType = `${key}_actionType`; // 'select' | 'drag-list' | 'drag-list-end' | 'drag' | 'hover' | 'resize' | 'area' | null = null;
// export const keyResizeType = `${key}_resizeType`; // ResizeType | null;
// export const keyAreaStart = `${key}_areaStart`; // Point
// export const keyAreaEnd = `${key}_areaEnd`; // Point
// export const keyInGroupQueue = `${key}_targetQueue`; // Element<'group'>[]
// export const keyGroupQueue = `${key}_targetQueue`; // Element<'group'>[]

View file

@ -101,7 +101,7 @@ export function drawElementListShadows(ctx: ViewContext2D, elements: Element<Ele
const { angle = 0 } = elem;
if (opts?.calculator) {
const { calculator } = opts;
const size = calculator.elementSize({ x, y, w, h }, opts.scaleInfo, opts.viewSize);
const size = calculator.elementSize({ x, y, w, h }, opts.viewScaleInfo, opts.viewSizeInfo);
x = size.x;
y = size.y;
w = size.w;

View file

@ -3,7 +3,7 @@ import type { Point, PointWatcherEvent, BoardMiddleware, Element, ElementSize, A
import { drawPointWrapper, drawHoverWrapper, drawElementControllers, drawArea, drawListArea, drawGroupsWrapper } from './draw-wrapper';
import { calcElementControllerStyle } from './controller';
import { getPointTarget, resizeElement, getSelectedListArea, calcSelectedElementsArea, isElementInGroup } from './util';
import { key, keyHoverElementSize, keyActionType, keyResizeType, keyAreaStart, keyAreaEnd, keyInGroupQueue } from './config';
import { key, keyHoverElementSize, keyActionType, keyResizeType, keyAreaStart, keyAreaEnd, keyGroupQueue, keyInGroup } from './config';
export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (opts) => {
const { viewer, sharer, viewContent, calculator } = opts;
@ -35,7 +35,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
};
const pushGroupQueue = (elem: Element<'group'>) => {
let groupQueue = sharer.getSharedStorage(keyInGroupQueue);
let groupQueue = sharer.getSharedStorage(keyGroupQueue);
if (!Array.isArray(groupQueue)) {
groupQueue = [];
}
@ -48,7 +48,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
} else if (groupQueue.length === 0) {
groupQueue.push(elem);
}
sharer.setSharedStorage(keyInGroupQueue, groupQueue);
sharer.setSharedStorage(keyGroupQueue, groupQueue);
return groupQueue.length > 0;
};
@ -58,7 +58,8 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
sharer.setSharedStorage(keyResizeType, null);
sharer.setSharedStorage(keyAreaStart, null);
sharer.setSharedStorage(keyAreaEnd, null);
sharer.setSharedStorage(keyInGroupQueue, null);
sharer.setSharedStorage(keyGroupQueue, null);
sharer.setSharedStorage(keyInGroup, null);
};
clear();
@ -78,23 +79,23 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
sharer.setSharedStorage(keyHoverElementSize, null);
} else if (data) {
const selectedElements = getActiveElements();
const scaleInfo = sharer.getActiveScaleInfo();
const viewSize = sharer.getActiveViewSizeInfo();
const viewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo = sharer.getActiveViewSizeInfo();
const target = getPointTarget(e.point, {
ctx: helperContext,
data,
selectedIndexes: getIndexes(),
selectedUUIDs: sharer.getActiveStorage('selectedUUIDs') || [],
selectedElements: selectedElements,
scaleInfo,
viewSize,
viewScaleInfo,
viewSizeInfo,
calculator,
areaSize: calcSelectedElementsArea(selectedElements, {
scaleInfo,
viewSize,
viewScaleInfo,
viewSizeInfo,
calculator
}),
groupQueue: [] // TODO
groupQueue: sharer.getSharedStorage(keyGroupQueue)
});
if (target.type === 'over-element' && target?.elements?.length === 1) {
const { x, y, w, h, angle } = target.elements[0];
@ -116,8 +117,8 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
sharer.setSharedStorage(keyHoverElementSize, null);
const data = sharer.getActiveStorage('data');
const listAreaSize = calcSelectedElementsArea(getActiveElements(), {
scaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
calculator
});
const target = getPointTarget(e.point, {
@ -126,13 +127,26 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
selectedIndexes: getIndexes(),
selectedUUIDs: sharer.getActiveStorage('selectedUUIDs') || [],
selectedElements: getActiveElements(),
scaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
calculator,
areaSize: listAreaSize,
groupQueue: [] // TODO
groupQueue: sharer.getSharedStorage(keyGroupQueue)
});
console.log('pointStart target ====== ', target);
if (sharer.getSharedStorage(keyInGroup) === true) {
if (target.type === 'in-group-element' && target?.elements?.length > 0) {
// TODO
sharer.setSharedStorage(keyGroupQueue, target.elements as Element<'group'>[]);
return;
} else {
sharer.setSharedStorage(keyInGroup, false);
sharer.setSharedStorage(keyGroupQueue, null);
}
}
if (target.type === 'list-area') {
sharer.setSharedStorage(keyActionType, 'drag-list');
} else if (target.type === 'over-element' && target?.uuids?.length === 1 && target?.elements?.length === 1) {
@ -220,9 +234,9 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
const data = sharer.getActiveStorage('data');
const resizeType = sharer.getSharedStorage(keyResizeType);
const actionType = sharer.getSharedStorage(keyActionType);
const scaleInfo = sharer.getActiveScaleInfo();
const viewSize = sharer.getActiveViewSizeInfo();
const { offsetLeft, offsetTop } = scaleInfo;
const viewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo = sharer.getActiveViewSizeInfo();
const { offsetLeft, offsetTop } = viewScaleInfo;
let needDrawFrame = false;
if (actionType === 'resize' && resizeType) {
@ -237,8 +251,8 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
start,
end,
calculator,
scaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo()
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo()
});
if (uuids.length > 0) {
@ -270,7 +284,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
return;
}
if (data && Array.isArray(data?.elements) && (['drag', 'drag-list'] as ActionType[]).includes(actionType)) {
const viewInfo = calcElementsViewInfo(data.elements, viewSize, { extend: true });
const viewInfo = calcElementsViewInfo(data.elements, viewSizeInfo, { extend: true });
sharer.setActiveStorage('contextX', viewInfo.contextSize.contextX);
sharer.setActiveStorage('contextY', viewInfo.contextSize.contextY);
sharer.setActiveStorage('contextHeight', viewInfo.contextSize.contextHeight);
@ -290,8 +304,6 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
},
doubleClick(e: PointWatcherEvent) {
// console.log('doubleClick =====', e);
const groupQueue = sharer.getSharedStorage(keyInGroupQueue);
const data = sharer.getActiveStorage('data');
const target = getPointTarget(e.point, {
ctx: helperContext,
@ -299,14 +311,18 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
selectedIndexes: getIndexes(),
selectedUUIDs: sharer.getActiveStorage('selectedUUIDs') || [],
selectedElements: getActiveElements(),
scaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
calculator,
areaSize: null,
groupQueue: [] // TODO
groupQueue: sharer.getSharedStorage(keyGroupQueue)
});
if (target.elements.length === 1 && target.elements[0]?.type === 'group') {
if (target.type === 'in-group-element' && target.elements.length > 0) {
sharer.setSharedStorage(keyGroupQueue, target.elements as Element<'group'>[]);
sharer.setSharedStorage(keyInGroup, true);
} else if (target.elements.length === 1 && target.elements[0]?.type === 'group') {
const pushResult = pushGroupQueue(target.elements[0] as Element<'group'>);
sharer.setSharedStorage(keyInGroup, pushResult);
if (pushResult === true) {
viewer.drawFrame();
return;
@ -334,8 +350,8 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
contextWidth,
devicePixelRatio
} = activeStore;
const scaleInfo = { scale, offsetLeft, offsetTop, offsetRight, offsetBottom };
const viewSize = { width, height, contextX, contextY, contextHeight, contextWidth, devicePixelRatio };
const viewScaleInfo = { scale, offsetLeft, offsetTop, offsetRight, offsetBottom };
const viewSizeInfo = { width, height, contextX, contextY, contextHeight, contextWidth, devicePixelRatio };
// const elem = data?.elements?.[selectedIndexes?.[0] as number];
const selectedElements = getSelectedElements(data, selectedUUIDs);
const elem = selectedElements[0];
@ -343,21 +359,22 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
const actionType: ActionType = sharedStore[keyActionType] as ActionType;
const areaStart: Point | null = sharedStore[keyAreaStart];
const areaEnd: Point | null = sharedStore[keyAreaEnd];
const groupQueue: Element<'group'>[] | null = sharedStore[keyInGroupQueue];
const inGroup: boolean | null = sharedStore[keyInGroup];
const groupQueue: Element<'group'>[] | null = sharedStore[keyGroupQueue];
if (groupQueue && groupQueue?.length > 0) {
if (inGroup && groupQueue && groupQueue?.length > 0) {
// in group
drawGroupsWrapper(helperContext, groupQueue);
} else {
// in root
const drawOpts = { calculator, scaleInfo, viewSize };
const drawOpts = { calculator, viewScaleInfo, viewSizeInfo };
if (hoverElement && actionType !== 'drag') {
const hoverElemSize = calculator.elementSize(hoverElement, scaleInfo, viewSize);
const hoverElemSize = calculator.elementSize(hoverElement, viewScaleInfo, viewSizeInfo);
drawHoverWrapper(helperContext, hoverElemSize);
}
if (elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
const selectedElemSize = calculator.elementSize(elem, scaleInfo, viewSize);
const selectedElemSize = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
const sizeControllers = calcElementControllerStyle(selectedElemSize);
drawPointWrapper(helperContext, selectedElemSize);
drawElementControllers(helperContext, selectedElemSize, { ...drawOpts, sizeControllers });
@ -365,8 +382,8 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
drawArea(helperContext, { start: areaStart, end: areaEnd });
} else if ((['drag-list', 'drag-list-end'] as ActionType[]).includes(actionType)) {
const listAreaSize = calcSelectedElementsArea(getActiveElements(), {
scaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
calculator
});
if (listAreaSize) {

View file

@ -1,4 +1,4 @@
import { keyHoverElementSize, keyActionType, keyResizeType, keyAreaStart, keyAreaEnd, keyInGroupQueue } from './config';
import { keyHoverElementSize, keyActionType, keyResizeType, keyAreaStart, keyAreaEnd, keyGroupQueue, keyInGroup } from './config';
import {
Data,
@ -40,7 +40,7 @@ export type ElementSizeController = Record<string, ControllerStyle>;
export type ResizeType = 'resize-left' | 'resize-right' | 'resize-top' | 'resize-bottom';
export type PointTargetType = null | 'list-area' | 'over-element' | ResizeType;
export type PointTargetType = null | ResizeType | 'list-area' | 'over-element' | 'in-group-element';
export interface PointTarget {
type: PointTargetType;
@ -55,9 +55,10 @@ export type ActionType = 'select' | 'drag-list' | 'drag-list-end' | 'drag' | 'ho
export type DeepSelectorSharedStorage = {
[keyHoverElementSize]: ElementSize | null;
[keyActionType]: ActionType;
[keyActionType]: ActionType | null;
[keyResizeType]: ResizeType | null;
[keyAreaStart]: Point | null;
[keyAreaEnd]: Point | null;
[keyInGroupQueue]: Element<'group'>[] | null;
[keyGroupQueue]: Element<'group'>[] | null;
[keyInGroup]: boolean | null;
};

View file

@ -38,10 +38,10 @@ export function getPointTarget(
selectedUUIDs: Array<string>;
selectedElements?: Element<ElementType>[];
areaSize?: AreaSize | null;
scaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
calculator: ViewCalculator;
groupQueue: Element<'group'>[];
groupQueue: Element<'group'>[] | null;
}
): PointTarget {
const target: PointTarget = {
@ -50,7 +50,31 @@ export function getPointTarget(
indexes: [],
uuids: []
};
const { ctx, data, calculator, selectedElements, selectedIndexes, selectedUUIDs, scaleInfo, viewSize, areaSize } = opts;
const { ctx, data, calculator, selectedElements, selectedIndexes, selectedUUIDs, viewScaleInfo, viewSizeInfo, areaSize, groupQueue } = opts;
// in-group-element
if (groupQueue && Array.isArray(groupQueue) && groupQueue.length > 0 && data) {
const { index, element } = calculator.getPointElement(p as Point, data, viewScaleInfo, viewSizeInfo);
if (index >= 0 && element) {
const newQueue: Element<'group'>[] = [];
for (let i = 0; i < groupQueue.length; i++) {
const group = groupQueue[i];
if (group.type !== 'group') {
break;
}
if (element.uuid === group.uuid) {
// isElementInGroup(element, group)
// TODO check in group
newQueue.push(group);
target.indexes = [];
target.elements = newQueue;
target.uuids = [];
target.type = 'in-group-element';
return target;
}
}
}
}
// list area
if (areaSize && Array.isArray(selectedElements) && selectedElements?.length > 1 && Array.isArray(selectedIndexes) && selectedIndexes?.length > 1) {
@ -66,7 +90,7 @@ export function getPointTarget(
// resize
if (selectedElements?.length === 1) {
const elemSize = calculator.elementSize(selectedElements[0], scaleInfo, viewSize);
const elemSize = calculator.elementSize(selectedElements[0], viewScaleInfo, viewSizeInfo);
const ctrls = calcElementControllerStyle(elemSize);
rotateElement(ctx, elemSize, () => {
const ctrlKeys = Object.keys(ctrls);
@ -93,7 +117,7 @@ export function getPointTarget(
// over-element
if (data) {
const { index, element } = calculator.getPointElement(p as Point, data, scaleInfo, viewSize);
const { index, element } = calculator.getPointElement(p as Point, data, viewScaleInfo, viewSizeInfo);
if (index >= 0 && element) {
target.indexes = [index];
target.elements = [element];
@ -383,14 +407,14 @@ export function getSelectedListArea(
opts: {
start: Point;
end: Point;
scaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
calculator: ViewCalculator;
}
): { indexes: number[]; uuids: string[] } {
const indexes: number[] = [];
const uuids: string[] = [];
const { calculator, scaleInfo, viewSize, start, end } = opts;
const { calculator, viewScaleInfo, viewSizeInfo, start, end } = opts;
if (!(Array.isArray(data.elements) && start && end)) {
return { indexes, uuids };
@ -401,7 +425,7 @@ export function getSelectedListArea(
const endY = Math.max(start.y, end.y);
data.elements.forEach((elem, idx) => {
const elemSize = calculator.elementSize(elem, scaleInfo, viewSize);
const elemSize = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
const center = calcElementCenter(elemSize);
if (center.x >= startX && center.x <= endX && center.y >= startY && center.y <= endY) {
@ -426,8 +450,8 @@ export function getSelectedListArea(
export function calcSelectedElementsArea(
elements: Element<ElementType>[],
opts: {
scaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
calculator: ViewCalculator;
}
): AreaSize | null {
@ -435,11 +459,11 @@ export function calcSelectedElementsArea(
return null;
}
const area: AreaSize = { x: 0, y: 0, w: 0, h: 0 };
const { calculator, scaleInfo, viewSize } = opts;
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
let prevElemSize: ElementSize | null = null;
elements.forEach((elem) => {
const elemSize = calculator.elementSize(elem, scaleInfo, viewSize);
const elemSize = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
if (elemSize.angle && (elemSize.angle > 0 || elemSize.angle < 0)) {
const ves = rotateElementVertexes(elemSize);

View file

@ -48,9 +48,9 @@ export function isPointInScrollbar(helperContext: ViewContext2D, p: Point, sizeI
return thumbType;
}
export function calcScrollerInfo(scaleInfo: ViewScaleInfo, sizeInfo: ViewSizeInfo) {
export function calcScrollerInfo(viewScaleInfo: ViewScaleInfo, sizeInfo: ViewSizeInfo) {
const { width, height } = sizeInfo;
const { offsetTop, offsetBottom, offsetLeft, offsetRight } = scaleInfo;
const { offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
const sliderMinSize = scrollerLineWidth * 2.5;
const lineSize = scrollerLineWidth;
let xSize = 0;
@ -138,11 +138,11 @@ function drawScrollerThumb(
ctx.stroke();
}
function drawScrollerInfo(helperContext: ViewContext2D, opts: { scaleInfo: ViewScaleInfo; sizeInfo: ViewSizeInfo }) {
function drawScrollerInfo(helperContext: ViewContext2D, opts: { viewScaleInfo: ViewScaleInfo; sizeInfo: ViewSizeInfo }) {
const ctx = helperContext;
const { scaleInfo, sizeInfo } = opts;
const { viewScaleInfo, sizeInfo } = opts;
const { width, height } = sizeInfo;
const wrapper = calcScrollerInfo(scaleInfo, sizeInfo);
const wrapper = calcScrollerInfo(viewScaleInfo, sizeInfo);
if (wrapper.xSize > 0) {
if (scrollConfig.showBackground === true) {
ctx.globalAlpha = scrollerAlpha;
@ -191,6 +191,6 @@ function drawScrollerInfo(helperContext: ViewContext2D, opts: { scaleInfo: ViewS
export function drawScroller(ctx: ViewContext2D, opts: { snapshot: BoardViewerFrameSnapshot }) {
const { snapshot } = opts;
const sizeInfo = getViewSizeInfoFromSnapshot(snapshot);
const scaleInfo = getViewScaleInfoFromSnapshot(snapshot);
drawScrollerInfo(ctx, { sizeInfo, scaleInfo });
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);
drawScrollerInfo(ctx, { sizeInfo, viewScaleInfo });
}

View file

@ -101,7 +101,7 @@ export function drawElementListShadows(ctx: ViewContext2D, elements: Element<Ele
const { angle = 0 } = elem;
if (opts?.calculator) {
const { calculator } = opts;
const size = calculator.elementSize({ x, y, w, h }, opts.scaleInfo, opts.viewSize);
const size = calculator.elementSize({ x, y, w, h }, opts.viewScaleInfo, opts.viewSizeInfo);
x = size.x;
y = size.y;
w = size.w;

View file

@ -65,7 +65,7 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
sharer.setSharedStorage(keyHoverElementSize, null);
} else if (data) {
const selectedElements = getActiveElements();
const scaleInfo = sharer.getActiveScaleInfo();
const viewScaleInfo = sharer.getActiveScaleInfo();
const viewSize = sharer.getActiveViewSizeInfo();
const target = getPointTarget(e.point, {
ctx: helperContext,
@ -73,11 +73,11 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
selectedIndexes: getIndexes(),
selectedUUIDs: sharer.getActiveStorage('selectedUUIDs') || [],
selectedElements: selectedElements,
scaleInfo,
viewScaleInfo,
viewSize,
calculator,
areaSize: calcSelectedElementsArea(selectedElements, {
scaleInfo,
viewScaleInfo,
viewSize,
calculator
})
@ -102,7 +102,7 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
sharer.setSharedStorage(keyHoverElementSize, null);
const data = sharer.getActiveStorage('data');
const listAreaSize = calcSelectedElementsArea(getActiveElements(), {
scaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
calculator
});
@ -112,7 +112,7 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
selectedIndexes: getIndexes(),
selectedUUIDs: sharer.getActiveStorage('selectedUUIDs') || [],
selectedElements: getActiveElements(),
scaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
calculator,
areaSize: listAreaSize
@ -205,9 +205,9 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
const data = sharer.getActiveStorage('data');
const resizeType = sharer.getSharedStorage(keyResizeType);
const actionType = sharer.getSharedStorage(keyActionType);
const scaleInfo = sharer.getActiveScaleInfo();
const viewScaleInfo = sharer.getActiveScaleInfo();
const viewSize = sharer.getActiveViewSizeInfo();
const { scale, offsetLeft, offsetTop } = scaleInfo;
const { scale, offsetLeft, offsetTop } = viewScaleInfo;
const { width, height, contextHeight, contextWidth, contextX, contextY } = viewSize;
let needDrawFrame = false;
@ -222,7 +222,7 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
start,
end,
calculator,
scaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo()
});
@ -291,8 +291,8 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
contextWidth,
devicePixelRatio
} = activeStore;
const scaleInfo = { scale, offsetLeft, offsetTop, offsetRight, offsetBottom };
const viewSize = { width, height, contextX, contextY, contextHeight, contextWidth, devicePixelRatio };
const viewScaleInfo = { scale, offsetLeft, offsetTop, offsetRight, offsetBottom };
const viewSizeInfo = { width, height, contextX, contextY, contextHeight, contextWidth, devicePixelRatio };
// const elem = data?.elements?.[selectedIndexes?.[0] as number];
const selectedElements = getSelectedElements(data, selectedUUIDs);
const elem = selectedElements[0];
@ -301,14 +301,14 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
const areaStart: Point | null = sharedStore[keyAreaStart];
const areaEnd: Point | null = sharedStore[keyAreaEnd];
const drawOpts = { calculator, scaleInfo, viewSize };
const drawOpts = { calculator, viewScaleInfo, viewSizeInfo };
if (hoverElement && actionType !== 'drag') {
const hoverElemSize = calculator.elementSize(hoverElement, scaleInfo, viewSize);
const hoverElemSize = calculator.elementSize(hoverElement, viewScaleInfo, viewSizeInfo);
drawHoverWrapper(helperContext, hoverElemSize);
}
if (elem && ['select', 'drag', 'resize'].includes(actionType)) {
const selectedElemSize = calculator.elementSize(elem, scaleInfo, viewSize);
const selectedElemSize = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
const sizeControllers = calcElementControllerStyle(selectedElemSize);
drawPointWrapper(helperContext, selectedElemSize);
drawElementControllers(helperContext, selectedElemSize, { ...drawOpts, sizeControllers });
@ -316,7 +316,7 @@ export const MiddlewareSelector: BoardMiddleware = (opts) => {
drawArea(helperContext, { start: areaStart, end: areaEnd });
} else if (['drag-list', 'drag-list-end'].includes(actionType)) {
const listAreaSize = calcSelectedElementsArea(getActiveElements(), {
scaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewSize: sharer.getActiveViewSizeInfo(),
calculator
});

View file

@ -38,7 +38,7 @@ export function getPointTarget(
selectedUUIDs: Array<string>;
selectedElements?: Element<ElementType>[];
areaSize?: AreaSize | null;
scaleInfo: ViewScaleInfo;
viewScaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
calculator: ViewCalculator;
}
@ -49,7 +49,7 @@ export function getPointTarget(
indexes: [],
uuids: []
};
const { ctx, data, calculator, selectedElements, selectedIndexes, selectedUUIDs, scaleInfo, viewSize, areaSize } = opts;
const { ctx, data, calculator, selectedElements, selectedIndexes, selectedUUIDs, viewScaleInfo, viewSize, areaSize } = opts;
// list area
if (areaSize && Array.isArray(selectedElements) && selectedElements?.length > 1 && Array.isArray(selectedIndexes) && selectedIndexes?.length > 1) {
@ -65,7 +65,7 @@ export function getPointTarget(
// resize
if (selectedElements?.length === 1) {
const elemSize = calculator.elementSize(selectedElements[0], scaleInfo, viewSize);
const elemSize = calculator.elementSize(selectedElements[0], viewScaleInfo, viewSize);
const ctrls = calcElementControllerStyle(elemSize);
rotateElement(ctx, elemSize, () => {
const ctrlKeys = Object.keys(ctrls);
@ -92,7 +92,7 @@ export function getPointTarget(
// over-element
if (data) {
const { index, element } = calculator.getPointElement(p as Point, data, scaleInfo, viewSize);
const { index, element } = calculator.getPointElement(p as Point, data, viewScaleInfo, viewSize);
if (index >= 0 && element) {
target.indexes = [index];
target.elements = [element];
@ -382,14 +382,14 @@ export function getSelectedListArea(
opts: {
start: Point;
end: Point;
scaleInfo: ViewScaleInfo;
viewScaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
calculator: ViewCalculator;
}
): { indexes: number[]; uuids: string[] } {
const indexes: number[] = [];
const uuids: string[] = [];
const { calculator, scaleInfo, viewSize, start, end } = opts;
const { calculator, viewScaleInfo, viewSize, start, end } = opts;
if (!(Array.isArray(data.elements) && start && end)) {
return { indexes, uuids };
@ -400,7 +400,7 @@ export function getSelectedListArea(
const endY = Math.max(start.y, end.y);
data.elements.forEach((elem, idx) => {
const elemSize = calculator.elementSize(elem, scaleInfo, viewSize);
const elemSize = calculator.elementSize(elem, viewScaleInfo, viewSize);
const center = calcElementCenter(elemSize);
if (center.x >= startX && center.x <= endX && center.y >= startY && center.y <= endY) {
@ -425,7 +425,7 @@ export function getSelectedListArea(
export function calcSelectedElementsArea(
elements: Element<ElementType>[],
opts: {
scaleInfo: ViewScaleInfo;
viewScaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
calculator: ViewCalculator;
}
@ -434,11 +434,11 @@ export function calcSelectedElementsArea(
return null;
}
const area: AreaSize = { x: 0, y: 0, w: 0, h: 0 };
const { calculator, scaleInfo, viewSize } = opts;
const { calculator, viewScaleInfo, viewSize } = opts;
let prevElemSize: ElementSize | null = null;
elements.forEach((elem) => {
const elemSize = calculator.elementSize(elem, scaleInfo, viewSize);
const elemSize = calculator.elementSize(elem, viewScaleInfo, viewSize);
if (elemSize.angle && (elemSize.angle > 0 || elemSize.angle < 0)) {
const ves = rotateElementVertexes(elemSize);

View file

@ -4,9 +4,9 @@ import { rotateElement } from '@idraw/util';
export function drawCircle(ctx: ViewContext2D, elem: Element<'circle'>, opts: RendererDrawElementOptions) {
const { desc, angle } = elem;
const { bgColor = '#000000', borderColor = '#000000', borderWidth = 0 } = desc;
const { calculator, scaleInfo, viewSize } = opts;
// const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = scaleInfo;
const { x, y, w, h } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, scaleInfo, viewSize);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
// const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
const { x, y, w, h } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
const a = w / 2;
const b = h / 2;

View file

@ -51,7 +51,7 @@ export function drawElementList(ctx: ViewContext2D, elements: Data['elements'],
for (let i = 0; i < elements.length; i++) {
const elem = elements[i];
// TODO
if (!opts.calculator.isElementInView(elem, opts.scaleInfo, opts.viewSize)) {
if (!opts.calculator.isElementInView(elem, opts.viewScaleInfo, opts.viewSizeInfo)) {
continue;
}
try {

View file

@ -49,8 +49,8 @@ export function drawElement(ctx: ViewContext2D, elem: Element<ElementType>, opts
}
export function drawGroup(ctx: ViewContext2D, elem: Element<'group'>, opts: RendererDrawElementOptions) {
const { calculator, scaleInfo, viewSize } = opts;
const { x, y, w, h, angle } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, scaleInfo, viewSize);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h, angle: elem.angle }, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
drawBox(ctx, { ...elem, ...{ x, y, w, h, angle } }, elem?.desc?.bgColor);
@ -83,7 +83,7 @@ export function drawGroup(ctx: ViewContext2D, elem: Element<'group'>, opts: Rend
y: newParentSize.y + child.y
}
};
if (!calculator.isElementInView(child, opts.scaleInfo, opts.viewSize)) {
if (!calculator.isElementInView(child, opts.viewScaleInfo, opts.viewSizeInfo)) {
continue;
}
try {

View file

@ -3,8 +3,8 @@ import { rotateElement } from '@idraw/util';
export function drawHTML(ctx: ViewContext2D, elem: Element<'html'>, opts: RendererDrawElementOptions) {
const content = opts.loader.getContent(elem.uuid);
const { calculator, scaleInfo, viewSize } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, scaleInfo, viewSize);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
if (!content) {
opts.loader.load(elem as Element<'html'>);

View file

@ -3,8 +3,8 @@ import { rotateElement } from '@idraw/util';
export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: RendererDrawElementOptions) {
const content = opts.loader.getContent(elem.uuid);
const { calculator, scaleInfo, viewSize } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, scaleInfo, viewSize);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
if (!content) {
opts.loader.load(elem as Element<'image'>);

View file

@ -3,11 +3,11 @@ import { rotateElement } from '@idraw/util';
export function drawRect(ctx: ViewContext2D, elem: Element<'rect'>, opts: RendererDrawElementOptions) {
// const { desc } = elem;
const { calculator, scaleInfo, viewSize } = opts;
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, scaleInfo, viewSize);
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
let r: number = (elem.desc.borderRadius || 0) * scaleInfo.scale;
let r: number = (elem.desc.borderRadius || 0) * viewScaleInfo.scale;
r = Math.min(r, w / 2, h / 2);
if (w < r * 2 || h < r * 2) {
r = 0;

View file

@ -3,8 +3,8 @@ import { rotateElement } from '@idraw/util';
export function drawSVG(ctx: ViewContext2D, elem: Element<'svg'>, opts: RendererDrawElementOptions) {
const content = opts.loader.getContent(elem.uuid);
const { calculator, scaleInfo, viewSize } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, scaleInfo, viewSize);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
if (!content) {
opts.loader.load(elem as Element<'svg'>);

View file

@ -4,8 +4,8 @@ import { is, isColorStr } from '@idraw/util';
import { drawBox } from './base';
export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: RendererDrawElementOptions) {
const { calculator, scaleInfo, viewSize } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, scaleInfo, viewSize);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
drawBox(ctx, { ...elem, ...{ x, y, w, h, angle } }, elem.desc.bgColor || 'transparent');
const desc: Element<'text'>['desc'] = {

View file

@ -43,8 +43,8 @@ export class Renderer extends EventEmitter<RendererEventMap> implements BoardRen
const parentElementSize = {
x: 0,
y: 0,
w: opts.viewSize.width,
h: opts.viewSize.height
w: opts.viewSizeInfo.width,
h: opts.viewSizeInfo.height
};
drawElementList(viewContext, data.elements, {
loader,
@ -60,14 +60,14 @@ export class Renderer extends EventEmitter<RendererEventMap> implements BoardRen
sharer.getActiveStoreSnapshot();
if (data) {
this.drawData(data, {
scaleInfo: {
viewScaleInfo: {
scale: num,
offsetTop,
offsetBottom,
offsetLeft,
offsetRight
},
viewSize: {
viewSizeInfo: {
width,
height,
contextX,

View file

@ -30,7 +30,7 @@ export type BoardWatherScrollYEvent = ViewScaleInfo;
export type BoardWatherResizeEvent = ViewSizeInfo;
export interface BoardWatcherEventMap<S extends Record<any | symbol, any>> {
export interface BoardWatcherEventMap<S extends Record<any | symbol, any> = any> {
hover: BoardWatcherPointEvent;
pointStart: BoardWatcherPointEvent;
pointMove: BoardWatcherPointEvent;
@ -49,7 +49,7 @@ export interface BoardWatcherEventMap<S extends Record<any | symbol, any>> {
export type BoardMode = 'SELECT' | 'SCROLL' | 'RULE' | 'CONNECT' | 'PENCIL' | 'PEN' | string;
export interface BoardMiddlewareObject<S extends Record<any | symbol, any>> {
export interface BoardMiddlewareObject<S extends Record<any | symbol, any> = any> {
mode: BoardMode;
isDefault?: boolean;
created?: () => void;
@ -86,7 +86,7 @@ export interface BoardOptions {
viewContent: ViewContent;
}
export interface BoardViewerFrameSnapshot<S extends Record<any | symbol, any>> {
export interface BoardViewerFrameSnapshot<S extends Record<any | symbol, any> = any> {
activeStore: ActiveStore;
sharedStore: S;
}

View file

@ -24,14 +24,14 @@ export interface RendererLoader extends UtilEventEmitter<LoaderEventMap> {
}
export interface RendererDrawOptions {
viewSize: ViewSizeInfo;
scaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
viewScaleInfo: ViewScaleInfo;
}
export interface RendererDrawElementOptions extends RendererDrawOptions {
loader: RendererLoader;
calculator: ViewCalculator;
scaleInfo: ViewScaleInfo;
viewSize: ViewSizeInfo;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
parentElementSize: ElementSize;
}

View file

@ -8,16 +8,16 @@ export type ActiveStore = ViewSizeInfo &
selectedUUIDs: string[];
};
export interface StoreSharer<S extends Record<any, any>> {
export interface StoreSharer<S extends Record<any, any> = any> {
getActiveStorage<T extends keyof ActiveStore>(key: T): ActiveStore[T];
setActiveStorage<T extends keyof ActiveStore>(key: T, storage: ActiveStore[T]): void;
getActiveStoreSnapshot(): ActiveStore;
getSharedStorage<K extends keyof S>(key: K): S[K];
setSharedStorage<K extends keyof S>(key: K, storage: S[K]): void;
getSharedStorage<K extends keyof S = string>(key: K): S[K];
setSharedStorage<K extends keyof S = string>(key: K, storage: S[K]): void;
getSharedStoreSnapshot(): Record<string, any>;
getActiveScaleInfo(): ViewScaleInfo;
setActiveScaleInfo(scaleInfo: ViewScaleInfo): void;
setActiveScaleInfo(viewScaleInfo: ViewScaleInfo): void;
setActiveViewSizeInfo(size: ViewSizeInfo): void;
getActiveViewSizeInfo(): ViewSizeInfo;
}

View file

@ -35,13 +35,10 @@ export interface ViewCalculatorOptions {
}
export interface ViewCalculator {
viewScale(num: number, prevScaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): ViewScaleInfo;
isElementInView(elem: Element<ElementType>, scaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): boolean;
isPointInElement(p: Point, elem: Element<ElementType>, scaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): boolean;
elementSize(size: ElementSize, scaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ElementSize;
viewScroll(opts: { moveX?: number; moveY?: number }, scaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo): ViewScaleInfo;
getPointElement(p: Point, data: Data, scaleInfo: ViewScaleInfo, viewSize: ViewSizeInfo): { index: number; element: null | Element<ElementType> };
// rotateElementSize(elemSize: ElementSize): PointSize[];
// pointToViewPoint( p: Point): Point;
// TODO
// 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

@ -23,3 +23,4 @@ export {
calcElementsViewInfo
} from './lib/element';
export { checkRectIntersect } from './lib/rect';
export { viewScale, viewScroll, calcElementSize, isViewPointInElement, getViewPointAtElement, isElementInView } from './lib/view-calc';

View file

@ -0,0 +1,176 @@
import { Point, Data, ViewScaleInfo, ViewSizeInfo, Element, ElementType, ElementSize } 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;
const { width, height, contextWidth, contextHeight } = viewSizeInfo;
let offsetLeft = 0;
let offsetRight = 0;
let offsetTop = 0;
let offsetBottom = 0;
if (contextWidth * scale < width) {
offsetLeft = offsetRight = (width - contextWidth * scale) / 2;
} else if (contextWidth * scale > width) {
if (prevViewScaleInfo.offsetLeft < 0) {
offsetLeft = (prevViewScaleInfo.offsetLeft / prevViewScaleInfo.scale) * scale;
offsetRight = 0 - (contextWidth * scale - width - Math.abs(offsetLeft));
}
}
if (contextHeight * scale < height) {
offsetTop = offsetBottom = (height - contextHeight * scale) / 2;
} else if (contextHeight * scale > height) {
if (prevViewScaleInfo.offsetTop < 0) {
offsetTop = (prevViewScaleInfo.offsetTop / prevViewScaleInfo.scale) * scale;
offsetBottom = 0 - (contextHeight * scale - height - Math.abs(offsetTop));
}
}
return {
scale,
offsetTop,
offsetLeft,
offsetRight,
offsetBottom
};
}
export function 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
};
}
export function calcElementSize(size: ElementSize, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): ElementSize {
const { viewScaleInfo, viewSizeInfo } = opts;
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;
}
export function isViewPointInElement(
p: Point,
opts: { context2d: Context2D; element: Element<ElementType>; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): boolean {
const { context2d: ctx, element: elem, viewScaleInfo, viewSizeInfo } = opts;
const { angle = 0 } = elem;
const { x, y, w, h } = calcElementSize(elem, { viewScaleInfo, viewSizeInfo });
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;
}
export function getViewPointAtElement(
p: Point,
opts: {
context2d: Context2D;
data: Data;
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
}
): { index: number; element: null | Element<ElementType> } {
const { context2d: ctx, data, viewScaleInfo, viewSizeInfo } = opts;
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 (isViewPointInElement(p, { context2d: ctx, element: elem, viewScaleInfo, viewSizeInfo })) {
result.index = i;
result.element = elem;
break;
}
}
return result;
}
export function isElementInView(elem: ElementSize, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): boolean {
const { viewSizeInfo, viewScaleInfo } = opts;
const { width, height } = viewSizeInfo;
const { angle } = elem;
const { x, y, w, h } = calcElementSize(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);
}