refactor: refactor middleware scaler and scroller

This commit is contained in:
chenshenhai 2023-09-10 10:42:26 +08:00
parent 2636531a29
commit 4781931eb1
12 changed files with 321 additions and 244 deletions

View file

@ -1,6 +1,6 @@
import { Renderer } from '@idraw/renderer';
import { throttle } from '@idraw/util';
import type { Data, BoardMode, BoardOptions, BoardMiddleware, BoardMiddlewareObject, BoardWatcherEventMap, ViewSizeInfo } from '@idraw/types';
import { throttle, calcElementsContextSize } from '@idraw/util';
import type { Data, BoardMode, BoardOptions, BoardMiddleware, BoardMiddlewareObject, BoardWatcherEventMap, ViewSizeInfo, PointSize } from '@idraw/types';
import { Calculator } from './lib/calculator';
import { BoardWatcher } from './lib/watcher';
import { Sharer } from './lib/sharer';
@ -90,7 +90,7 @@ export class Board {
this._handleWheelScale(e);
}, frameTime)
);
this._watcher.on('scale', this._handleScale.bind(this));
// this._watcher.on('scale', this._handleScale.bind(this));
this._watcher.on('scrollX', this._handleScrollX.bind(this));
this._watcher.on('scrollY', this._handleScrollY.bind(this));
this._watcher.on('resize', this._handleResize.bind(this));
@ -177,15 +177,15 @@ export class Board {
}
}
private _handleScale(e: BoardWatcherEventMap['scale']) {
for (let i = 0; i < this._activeMiddlewareObjs.length; i++) {
const obj = this._activeMiddlewareObjs[i];
const result = obj?.scale?.(e);
if (result === false) {
return;
}
}
}
// private _handleScale(e: BoardWatcherEventMap['scale']) {
// for (let i = 0; i < this._activeMiddlewareObjs.length; i++) {
// const obj = this._activeMiddlewareObjs[i];
// const result = obj?.scale?.(e);
// if (result === false) {
// return;
// }
// }
// }
private _handleScrollX(e: BoardWatcherEventMap['scrollX']) {
for (let i = 0; i < this._activeMiddlewareObjs.length; i++) {
@ -266,9 +266,24 @@ export class Board {
return this._sharer;
}
setData(data: Data) {
setData(data: Data): { viewSizeInfo: ViewSizeInfo } {
const sharer = this._sharer;
this._sharer.setActiveStorage('data', data);
const viewSizeInfo = sharer.getActiveViewSizeInfo();
// const currentScaleInfo = sharer.getActiveViewScaleInfo();
const newViewContextSize = calcElementsContextSize(data.elements, {
viewWidth: viewSizeInfo.width,
viewHeight: viewSizeInfo.height,
extend: true
});
this._viewer.drawFrame();
const newViewSizeInfo = {
...viewSizeInfo,
...newViewContextSize
};
this._sharer.setActiveViewSizeInfo(newViewSizeInfo);
return { viewSizeInfo: newViewSizeInfo };
}
getData(): Data | null {
@ -284,22 +299,14 @@ export class Board {
this._activeMiddlewareObjs.push(obj);
}
scale(num: number) {
const viewScaleInfo = this._viewer.scale(num);
this._viewer.drawFrame();
this._watcher.trigger('scale', viewScaleInfo);
scale(opts: { scale: number; point: PointSize }) {
const { _viewer: viewer } = this;
const { moveX, moveY } = viewer.scale(opts);
viewer.scroll({ moveX, moveY });
}
scrollX(num: number) {
const viewScaleInfo = this._viewer.scrollX(num);
this._viewer.drawFrame();
this._watcher.trigger('scrollX', viewScaleInfo);
}
scrollY(num: number) {
const viewScaleInfo = this._viewer.scrollY(num);
this._viewer.drawFrame();
this._watcher.trigger('scrollY', viewScaleInfo);
scroll(opts: { moveX: number; moveY: number }) {
return this._viewer.scroll(opts);
}
resize(newViewSize: ViewSizeInfo) {

View file

@ -60,7 +60,7 @@ export class Sharer implements StoreSharer<Record<string | number | symbol, any>
// get/set active info
getActiveScaleInfo(): ViewScaleInfo {
getActiveViewScaleInfo(): ViewScaleInfo {
const viewScaleInfo: ViewScaleInfo = {
scale: this._activeStore.get('scale'),
offsetTop: this._activeStore.get('offsetTop'),
@ -71,7 +71,7 @@ export class Sharer implements StoreSharer<Record<string | number | symbol, any>
return viewScaleInfo;
}
setActiveScaleInfo(viewScaleInfo: ViewScaleInfo) {
setActiveViewScaleInfo(viewScaleInfo: ViewScaleInfo) {
const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
this._activeStore.set('scale', scale);
this._activeStore.set('offsetTop', offsetTop);

View file

@ -1,5 +1,14 @@
import { EventEmitter, viewScale, viewScroll } from '@idraw/util';
import type { BoardViewer, BoardViewerEventMap, BoardViewerOptions, ActiveStore, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
import type {
PointSize,
BoardViewer,
BoardViewerEventMap,
BoardViewerOptions,
ActiveStore,
BoardViewerFrameSnapshot,
ViewScaleInfo,
ViewSizeInfo
} from '@idraw/types';
const { requestAnimationFrame } = window;
@ -89,33 +98,58 @@ export class Viewer extends EventEmitter<BoardViewerEventMap> implements BoardVi
this._drawAnimationFrame();
}
scale(num: number): ViewScaleInfo {
const { sharer, renderer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
scale(opts: { scale: number; point: PointSize }): { moveX: number; moveY: number } {
const { scale, point } = opts;
const { sharer } = this._opts;
const { moveX, moveY } = viewScale({
scale,
point,
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo()
});
sharer.setActiveStorage('scale', scale);
// renderer.scale(scale);
return { moveX, moveY };
}
scroll(opts: { moveX: number; moveY: number }): ViewScaleInfo {
const { sharer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveViewScaleInfo();
const { moveX, moveY } = opts;
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const viewScaleInfo = viewScale({ num, prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
renderer.scale(num);
const viewScaleInfo = viewScroll({
moveX,
moveY,
viewScaleInfo: prevViewScaleInfo,
viewSizeInfo
});
sharer.setActiveViewScaleInfo(viewScaleInfo);
return viewScaleInfo;
}
scrollX(num: number): ViewScaleInfo {
const { sharer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const viewScaleInfo = viewScroll({ moveX: num - (prevViewScaleInfo.offsetLeft || 0), viewScaleInfo: prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
return viewScaleInfo;
}
// scrollX(num: number): ViewScaleInfo {
// // TODO
// const { sharer } = this._opts;
// return sharer.getActiveViewScaleInfo();
// // const { sharer } = this._opts;
// // const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveViewScaleInfo();
// // const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
// // const viewScaleInfo = viewScroll({ moveX: num - (prevViewScaleInfo.offsetLeft || 0), viewScaleInfo: prevViewScaleInfo, viewSizeInfo });
// // sharer.setActiveViewScaleInfo(viewScaleInfo);
// // return viewScaleInfo;
// }
scrollY(num: number): ViewScaleInfo {
const { sharer } = this._opts;
const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveScaleInfo();
const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
const viewScaleInfo = viewScroll({ moveY: num - (prevViewScaleInfo.offsetTop || 0), viewScaleInfo: prevViewScaleInfo, viewSizeInfo });
sharer.setActiveScaleInfo(viewScaleInfo);
return viewScaleInfo;
}
// scrollY(num: number): ViewScaleInfo {
// // TODO
// const { sharer } = this._opts;
// return sharer.getActiveViewScaleInfo();
// // const { sharer } = this._opts;
// // const prevViewScaleInfo: ViewScaleInfo = sharer.getActiveViewScaleInfo();
// // const viewSizeInfo: ViewSizeInfo = sharer.getActiveViewSizeInfo();
// // const viewScaleInfo = viewScroll({ moveY: num - (prevViewScaleInfo.offsetTop || 0), viewScaleInfo: prevViewScaleInfo, viewSizeInfo });
// // sharer.setActiveViewScaleInfo(viewScaleInfo);
// // return viewScaleInfo;
// }
resize(viewSize: Partial<ViewSizeInfo> = {}): ViewSizeInfo {
const { sharer } = this._opts;

View file

@ -1,4 +1,4 @@
import type { Data, CoreOptions, BoardMiddleware, ViewSizeInfo } from '@idraw/types';
import type { Data, PointSize, CoreOptions, BoardMiddleware, ViewSizeInfo } from '@idraw/types';
import { Board } from '@idraw/board';
import { createBoardContexts, validateElements, calcElementsContextSize } from '@idraw/util';
@ -45,37 +45,19 @@ export class Core {
setData(data: Data) {
validateElements(data?.elements || []);
this._board.setData(data);
const sharer = this._board.getSharer();
const currentViewSize = sharer.getActiveViewSizeInfo();
// const currentScaleInfo = sharer.getActiveScaleInfo();
const newViewContextSize = calcElementsContextSize(data.elements, {
viewWidth: currentViewSize.width,
viewHeight: currentViewSize.height,
extend: true
});
this.resize({
...currentViewSize,
...newViewContextSize
});
this.scrollX(newViewContextSize.contextX);
this.scrollY(newViewContextSize.contextY);
}
scale(num: number) {
this._board.scale(num);
scale(opts: { scale: number; point: PointSize }) {
this._board.scale(opts);
}
scrollX(num: number) {
this._board.scrollX(num);
}
scrollY(num: number) {
this._board.scrollY(num);
}
// scroll(num: number) {
// this._board.scroll(num);
// }
resize(newViewSize: ViewSizeInfo) {
// const sharer = this._board.getSharer();
// const viewScaleInfo = sharer.getActiveScaleInfo();
// const viewScaleInfo = sharer.getActiveViewScaleInfo();
this._board.resize(newViewSize);
// this._board.scale(viewScaleInfo.scale);
// this._board.scrollX(viewScaleInfo.offsetLeft);

View file

@ -1,4 +1,4 @@
import type { Point, BoardMiddleware, PointWatcherEvent, BoardWatherWheelXEvent, BoardWatherWheelYEvent } from '@idraw/types';
import type { PointSize, BoardMiddleware, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
export const MiddlewareScaler: BoardMiddleware = (opts) => {
const key = 'SCALE';
@ -7,16 +7,17 @@ export const MiddlewareScaler: BoardMiddleware = (opts) => {
mode: key,
isDefault: true,
wheelScale(e) {
// console.log(' wheelScale ============= ', e);
const { deltaY } = e;
const { scale } = sharer.getActiveScaleInfo();
const { deltaY, point } = e;
const { scale } = sharer.getActiveViewScaleInfo();
let newScaleNum = scale;
if (deltaY < 0) {
viewer.scale(scale * 1.1);
viewer.drawFrame();
newScaleNum = scale * 1.1;
} else if (deltaY > 0) {
viewer.scale(scale * 0.9);
viewer.drawFrame();
newScaleNum = scale * 0.9;
}
const { moveX, moveY } = viewer.scale({ scale: newScaleNum, point });
viewer.scroll({ moveX, moveY });
viewer.drawFrame();
}
};
};

View file

@ -0,0 +1,6 @@
export const key = 'SCROLL';
export const keyXThumbRect = Symbol(`${key}_xThumbRect`);
export const keyYThumbRect = Symbol(`${key}_yThumbRect`);
export const keyPrevPoint = Symbol(`${key}_prevPoint`);
export const keyActivePoint = Symbol(`${key}_activePoint`);
export const keyActiveThumbType = Symbol(`${key}_activeThumbType`);

View file

@ -1,92 +1,120 @@
import type { ElementSize } from '@idraw/types';
import type { Point, BoardMiddleware, PointWatcherEvent, BoardWatherWheelXEvent, BoardWatherWheelYEvent } from '@idraw/types';
import { drawScroller, isPointInScrollbar, calcScrollerInfo } from './util';
import type { ScrollbarThumbType } from './util';
import { drawScroller, isPointInScrollThumb } from './util';
// import type { ScrollbarThumbType } from './util';
import { key, keyXThumbRect, keyYThumbRect, keyPrevPoint, keyActivePoint, keyActiveThumbType } from './config';
export const MiddlewareScroller: BoardMiddleware = (opts) => {
const key = 'SCROLL';
const { viewer, viewContent, sharer } = opts;
const { helperContext } = viewContent;
// viewer.drawFrame();
sharer.setSharedStorage(keyXThumbRect, null); // null | ElementSize
sharer.setSharedStorage(keyYThumbRect, null); // null | ElementSize
let activeThumbType: ScrollbarThumbType | null = null;
// viewer.drawFrame();
const clear = () => {
sharer.setSharedStorage(keyPrevPoint, null); // null | Point;
sharer.setSharedStorage(keyActivePoint, null); // null | Point;
sharer.setSharedStorage(keyActiveThumbType, null); // null | 'X' | 'Y'
};
clear();
// let activeThumbType: ScrollbarThumbType | null = null;
const scrollX = (p: Point) => {
const scrollerInfo = calcScrollerInfo(sharer.getActiveScaleInfo(), sharer.getActiveViewSizeInfo());
const offsetLeft = sharer.getActiveStorage('offsetLeft');
const moveX = p.x - (scrollerInfo.translateX + scrollerInfo.xSize / 2);
viewer.scrollX(offsetLeft - moveX);
viewer.drawFrame();
const prevPoint: null | Point = sharer.getSharedStorage(keyPrevPoint);
if (prevPoint) {
const { offsetLeft, offsetRight } = sharer.getActiveViewScaleInfo();
const { width } = sharer.getActiveViewSizeInfo();
const thumbMoveX = -(p.x - prevPoint.x);
const totalWidth = width + Math.abs(offsetLeft) + Math.abs(offsetRight);
const moveX = (thumbMoveX * totalWidth) / width;
viewer.scroll({ moveX });
viewer.drawFrame();
}
};
const scrollY = (p: Point) => {
const scrollerInfo = calcScrollerInfo(sharer.getActiveScaleInfo(), sharer.getActiveViewSizeInfo());
const offsetTop = sharer.getActiveStorage('offsetTop');
const moveY = p.y - (scrollerInfo.translateY + scrollerInfo.ySize / 2);
viewer.scrollY(offsetTop - moveY);
viewer.drawFrame();
const prevPoint: null | Point = sharer.getSharedStorage(keyPrevPoint);
if (prevPoint) {
const { offsetTop, offsetBottom } = sharer.getActiveViewScaleInfo();
const { height } = sharer.getActiveViewSizeInfo();
const thumbMoveY = -(p.y - prevPoint.y);
const totalHeight = height + Math.abs(offsetTop) + Math.abs(offsetBottom);
const moveY = (thumbMoveY * totalHeight) / height;
viewer.scroll({ moveY });
viewer.drawFrame();
}
};
const getThumbType = (p: Point) => {
return isPointInScrollThumb(helperContext, p, {
xThumbRect: sharer.getSharedStorage(keyXThumbRect),
yThumbRect: sharer.getSharedStorage(keyYThumbRect)
});
};
return {
mode: key,
hover: (e: PointWatcherEvent) => {
const { point } = e;
const thumbType = isPointInScrollbar(helperContext, point, sharer.getActiveViewSizeInfo());
if (thumbType === 'X' || thumbType === 'Y') {
return false;
}
},
// hover: (e: PointWatcherEvent) => {
// const { point } = e;
// const thumbType = getThumbType(point);
// if (thumbType === 'X' || thumbType === 'Y') {
// return false;
// }
// },
wheelX: (e: BoardWatherWheelXEvent) => {
const offsetLeft = sharer.getActiveStorage('offsetLeft');
if ((e.deltaX >= 0 || e.deltaX < 0) && offsetLeft <= 0) {
viewer.scrollX(offsetLeft - e.deltaX);
if (e.deltaX >= 0 || e.deltaX < 0) {
viewer.scroll({ moveX: 0 - e.deltaX });
viewer.drawFrame();
}
},
wheelY: (e: BoardWatherWheelYEvent) => {
const offsetTop = sharer.getActiveStorage('offsetTop');
if ((e.deltaY >= 0 || e.deltaY < 0) && offsetTop <= 0) {
viewer.scrollY(offsetTop - e.deltaY);
if (e.deltaY >= 0 || e.deltaY < 0) {
viewer.scroll({ moveY: 0 - e.deltaY });
viewer.drawFrame();
}
},
pointStart: (e: PointWatcherEvent) => {
const { point } = e;
const thumbType = isPointInScrollbar(helperContext, point, sharer.getActiveViewSizeInfo());
const thumbType = getThumbType(point);
if (thumbType === 'X' || thumbType === 'Y') {
activeThumbType = thumbType;
if (thumbType === 'X') {
scrollX(point);
} else if (thumbType === 'Y') {
scrollY(point);
}
sharer.setSharedStorage(keyActiveThumbType, thumbType);
sharer.setSharedStorage(keyPrevPoint, point);
return false;
}
},
pointMove: (e: PointWatcherEvent) => {
const { point } = e;
const activeThumbType = sharer.getSharedStorage(keyActiveThumbType);
if (activeThumbType === 'X' || activeThumbType === 'Y') {
sharer.setSharedStorage(keyActivePoint, point);
if (activeThumbType === 'X') {
scrollX(point);
} else if (activeThumbType === 'Y') {
scrollY(point);
}
sharer.setSharedStorage(keyPrevPoint, point);
return false;
}
},
pointEnd: (e: PointWatcherEvent) => {
const { point } = e;
if (activeThumbType === 'X' || activeThumbType === 'Y') {
if (activeThumbType === 'X') {
scrollX(point);
} else if (activeThumbType === 'Y') {
scrollY(point);
}
activeThumbType = null;
return false;
}
// const { point } = e;
// if (activeThumbType === 'X' || activeThumbType === 'Y') {
// if (activeThumbType === 'X') {
// scrollX(point);
// } else if (activeThumbType === 'Y') {
// scrollY(point);
// }
// activeThumbType = null;
// return false;
// }
clear();
},
beforeDrawFrame({ snapshot }) {
drawScroller(helperContext, { snapshot });
const { xThumbRect, yThumbRect } = drawScroller(helperContext, { snapshot });
sharer.setSharedStorage(keyXThumbRect, xThumbRect);
sharer.setSharedStorage(keyYThumbRect, yThumbRect);
}
};
};

View file

@ -1,4 +1,4 @@
import type { Point, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo, ViewContext2D } from '@idraw/types';
import type { Point, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo, ViewContext2D, ElementSize } from '@idraw/types';
import { getViewScaleInfoFromSnapshot, getViewSizeInfoFromSnapshot } from '@idraw/util';
const minScrollerWidth = 12;
@ -48,40 +48,98 @@ export function isPointInScrollbar(helperContext: ViewContext2D, p: Point, viewS
return thumbType;
}
export function calcScrollerInfo(viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo) {
function isPointAtRect(helperContext: ViewContext2D, p: Point, rect: ElementSize): boolean {
const ctx = helperContext;
const { x, y, w, h } = rect;
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.closePath();
if (ctx.isPointInPath(p.x, p.y)) {
return true;
}
return false;
}
export function isPointInScrollThumb(
helperContext: ViewContext2D,
p: Point,
opts: {
xThumbRect?: ElementSize | null;
yThumbRect?: ElementSize | null;
}
): ScrollbarThumbType | null {
let thumbType: ScrollbarThumbType | null = null;
const { xThumbRect, yThumbRect } = opts;
if (xThumbRect && isPointAtRect(helperContext, p, xThumbRect)) {
thumbType = 'X';
} else if (yThumbRect && isPointAtRect(helperContext, p, yThumbRect)) {
thumbType = 'Y';
}
return thumbType;
}
function calcScrollerInfo(viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo) {
const { width, height } = viewSizeInfo;
const { offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
const sliderMinSize = scrollerLineWidth * 2.5;
const lineSize = scrollerLineWidth;
let xSize = 0;
let ySize = 0;
if (offsetLeft <= 0 && offsetRight <= 0) {
xSize = Math.max(sliderMinSize, width - (Math.abs(offsetLeft) + Math.abs(offsetRight)));
if (xSize >= width) xSize = 0;
xSize = Math.max(sliderMinSize, width - (Math.abs(offsetLeft) + Math.abs(offsetRight)));
if (xSize >= width) {
xSize = width;
}
if (offsetTop <= 0 || offsetBottom <= 0) {
ySize = Math.max(sliderMinSize, height - (Math.abs(offsetTop) + Math.abs(offsetBottom)));
if (ySize >= height) ySize = 0;
ySize = Math.max(sliderMinSize, height - (Math.abs(offsetTop) + Math.abs(offsetBottom)));
if (ySize >= height) {
ySize = width;
}
let translateX = 0;
if (xSize > 0) {
const xStart = lineSize / 2;
const xEnd = width - xSize - lineSize;
let translateX = xStart;
if (offsetLeft > 0) {
translateX = xStart;
} else if (offsetRight > 0) {
translateX = xEnd;
} else if (offsetLeft <= 0 && xSize > 0 && !(offsetLeft === 0 && offsetRight === 0)) {
translateX = xSize / 2 + ((width - xSize) * Math.abs(offsetLeft)) / (Math.abs(offsetLeft) + Math.abs(offsetRight));
translateX = Math.min(Math.max(0, translateX - xSize / 2), width - xSize);
}
let translateY = 0;
if (ySize > 0) {
const yStart = lineSize / 2;
const yEnd = width - xSize - lineSize;
let translateY = yStart;
if (offsetTop > 0) {
translateY = yStart;
} else if (offsetBottom > 0) {
translateY = yEnd;
} else if (offsetTop <= 0 && ySize > 0 && !(offsetTop === 0 && offsetBottom === 0)) {
translateY = ySize / 2 + ((height - ySize) * Math.abs(offsetTop)) / (Math.abs(offsetTop) + Math.abs(offsetBottom));
translateY = Math.min(Math.max(0, translateY - ySize / 2), height - ySize);
}
const xThumbRect: ElementSize = {
x: translateX,
y: height - lineSize,
w: xSize,
h: lineSize
};
const yThumbRect: ElementSize = {
x: width - lineSize,
y: translateY,
w: lineSize,
h: ySize
};
const scrollWrapper = {
lineSize,
xSize,
ySize,
translateY,
translateX,
color: '#0000007A'
color: '#0000007A',
xThumbRect,
yThumbRect
};
return scrollWrapper;
}
@ -143,6 +201,7 @@ function drawScrollerInfo(helperContext: ViewContext2D, opts: { viewScaleInfo: V
const { viewScaleInfo, viewSizeInfo } = opts;
const { width, height } = viewSizeInfo;
const wrapper = calcScrollerInfo(viewScaleInfo, viewSizeInfo);
const { xThumbRect, yThumbRect } = wrapper;
if (wrapper.xSize > 0) {
if (scrollConfig.showBackground === true) {
ctx.globalAlpha = scrollerAlpha;
@ -155,10 +214,7 @@ function drawScrollerInfo(helperContext: ViewContext2D, opts: { viewScaleInfo: V
// x-slider
drawScrollerThumb(ctx, {
axis: 'X',
x: wrapper.translateX,
y: height - wrapper.lineSize,
w: wrapper.xSize,
h: wrapper.lineSize,
...xThumbRect,
r: wrapper.lineSize / 2,
color: wrapper.color
});
@ -176,21 +232,23 @@ function drawScrollerInfo(helperContext: ViewContext2D, opts: { viewScaleInfo: V
// y-slider
drawScrollerThumb(ctx, {
axis: 'Y',
x: width - wrapper.lineSize,
y: wrapper.translateY,
w: wrapper.lineSize,
h: wrapper.ySize,
...yThumbRect,
r: wrapper.lineSize / 2,
color: wrapper.color
});
}
ctx.globalAlpha = 1;
return {
xThumbRect,
yThumbRect
};
}
export function drawScroller(ctx: ViewContext2D, opts: { snapshot: BoardViewerFrameSnapshot }) {
const { snapshot } = opts;
const viewSizeInfo = getViewSizeInfoFromSnapshot(snapshot);
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);
drawScrollerInfo(ctx, { viewSizeInfo, viewScaleInfo });
const { xThumbRect, yThumbRect } = drawScrollerInfo(ctx, { viewSizeInfo, viewScaleInfo });
return { xThumbRect, yThumbRect };
}

View file

@ -91,7 +91,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
const controller = calcElementSizeController(list[0], {
groupQueue: sharer.getSharedStorage(keyGroupQueue),
controllerSize: 10,
viewScaleInfo: sharer.getActiveScaleInfo()
viewScaleInfo: sharer.getActiveViewScaleInfo()
});
sharer.setSharedStorage(keySelectedElementController, controller);
} else {
@ -105,7 +105,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
calculator,
data: sharer.getActiveStorage('data'),
selectedElements: getActiveElements(),
viewScaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
groupQueue: sharer.getSharedStorage(keyGroupQueue),
areaSize: null,
@ -140,7 +140,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
// in group
const isInActiveGroup = isPointInViewActiveGroup(e.point, {
ctx: helperContext,
viewScaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
groupQueue: sharer.getSharedStorage(keyGroupQueue)
});
@ -177,7 +177,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
}
const selectedElements = getActiveElements();
const viewScaleInfo = sharer.getActiveScaleInfo();
const viewScaleInfo = sharer.getActiveViewScaleInfo();
const viewSizeInfo = sharer.getActiveViewSizeInfo();
const target = getPointTarget(e.point, {
...pointTargetBaseOptions(),
@ -212,7 +212,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
if (
isPointInViewActiveGroup(e.point, {
ctx: helperContext,
viewScaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
groupQueue
})
@ -238,7 +238,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
// not in group
const listAreaSize = calcSelectedElementsArea(getActiveElements(), {
viewScaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
calculator
});
@ -341,9 +341,9 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
const data = sharer.getActiveStorage('data');
const resizeType = sharer.getSharedStorage(keyResizeType);
const actionType = sharer.getSharedStorage(keyActionType);
const viewScaleInfo = sharer.getActiveScaleInfo();
// const viewScaleInfo = sharer.getActiveViewScaleInfo();
const viewSizeInfo = sharer.getActiveViewSizeInfo();
const { offsetLeft, offsetTop } = viewScaleInfo;
// const { offsetLeft, offsetTop } = viewScaleInfo;
let needDrawFrame = false;
prevPoint = null;
if (actionType === 'resize' && resizeType) {
@ -358,7 +358,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
start,
end,
calculator,
viewScaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo()
});
@ -373,7 +373,11 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
sharer.setSharedStorage(keyActionType, 'drag-list-end');
needDrawFrame = true;
} else if (data) {
const result = calculator.getPointElement(e.point, { data, viewScaleInfo: sharer.getActiveScaleInfo(), viewSizeInfo: sharer.getActiveViewSizeInfo() });
const result = calculator.getPointElement(e.point, {
data,
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo()
});
if (result.element) {
sharer.setSharedStorage(keyActionType, 'select');
needDrawFrame = true;
@ -396,8 +400,9 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage> = (o
sharer.setActiveStorage('contextY', viewInfo.contextSize.contextY);
sharer.setActiveStorage('contextHeight', viewInfo.contextSize.contextHeight);
sharer.setActiveStorage('contextWidth', viewInfo.contextSize.contextWidth);
viewer.scrollX(offsetLeft + viewInfo.changeContextLeft);
viewer.scrollY(offsetTop + viewInfo.changeContextTop);
// TODO
// viewer.scrollX(offsetLeft + viewInfo.changeContextLeft);
// viewer.scrollY(offsetTop + viewInfo.changeContextTop);
}
viewer.drawFrame();
};
@ -464,7 +469,7 @@ 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(), {
viewScaleInfo: sharer.getActiveScaleInfo(),
viewScaleInfo: sharer.getActiveViewScaleInfo(),
viewSizeInfo: sharer.getActiveViewSizeInfo(),
calculator
});

View file

@ -1,4 +1,4 @@
import type { Point } from './point';
import type { Point, PointSize } from './point';
import type { ViewContent, ViewCalculator, ViewScaleInfo, ViewSizeInfo } from './view';
import type { UtilEventEmitter } from './util';
import type { ActiveStore, StoreSharer } from './store';
@ -23,7 +23,7 @@ export interface BoardWatherDrawFrameEvent<S extends Record<any | symbol, any>>
snapshot: BoardViewerFrameSnapshot<S>;
}
export type BoardWatherScaleEvent = ViewScaleInfo;
export type BoardWatherScaleEvent = { scale: number };
export type BoardWatherScrollXEvent = ViewScaleInfo;
@ -41,7 +41,7 @@ export interface BoardWatcherEventMap<S extends Record<any | symbol, any> = any>
wheelX: BoardWatherWheelXEvent;
wheelY: BoardWatherWheelYEvent;
wheelScale: BoardWatherWheelScaleEvent;
scale: BoardWatherScaleEvent;
// scale: BoardWatherScaleEvent;
scrollX: BoardWatherScrollXEvent;
scrollY: BoardWatherScrollYEvent;
resize: BoardWatherResizeEvent;
@ -67,7 +67,7 @@ export interface BoardMiddlewareObject<S extends Record<any | symbol, any> = any
wheelY?: (e: BoardWatcherEventMap<S>['wheelY']) => void | boolean;
wheelScale?: (e: BoardWatcherEventMap<S>['wheelScale']) => void | boolean;
scale?: (e: BoardWatcherEventMap<S>['scale']) => void | boolean;
// scale?: (e: BoardWatcherEventMap<S>['scale']) => void | boolean;
scrollX?: (e: BoardWatcherEventMap<S>['scrollX']) => void | boolean;
scrollY?: (e: BoardWatcherEventMap<S>['scrollY']) => void | boolean;
resize?: (e: BoardWatcherEventMap<S>['resize']) => void | boolean;
@ -113,9 +113,10 @@ export interface BoardViewerOptions {
export interface BoardViewer extends UtilEventEmitter<BoardViewerEventMap> {
drawFrame(): void;
scale(num: number): ViewScaleInfo;
scrollX(num: number): ViewScaleInfo;
scrollY(num: number): ViewScaleInfo;
scale(opts: { scale: number; point: PointSize }): { moveX: number; moveY: number };
scroll(opts: { moveX?: number; moveY?: number }): ViewScaleInfo;
// scrollX(num: number): ViewScaleInfo;
// scrollY(num: number): ViewScaleInfo;
resize(viewSize: Partial<ViewSizeInfo>): ViewSizeInfo;
}

View file

@ -14,8 +14,8 @@ export interface StoreSharer<S extends Record<any, any> = any> {
setSharedStorage<K extends keyof S = string>(key: K, storage: S[K]): void;
getSharedStoreSnapshot(): Record<string, any>;
getActiveScaleInfo(): ViewScaleInfo;
setActiveScaleInfo(viewScaleInfo: ViewScaleInfo): void;
getActiveViewScaleInfo(): ViewScaleInfo;
setActiveViewScaleInfo(viewScaleInfo: ViewScaleInfo): void;
setActiveViewSizeInfo(size: ViewSizeInfo): void;
getActiveViewSizeInfo(): ViewSizeInfo;
}

View file

@ -2,86 +2,41 @@ import { Point, PointSize, Data, ViewScaleInfo, ViewSizeInfo, Element, ElementTy
import { rotateElementVertexes } from './rotate';
import { checkRectIntersect } from './rect';
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;
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));
}
}
export function viewScale(opts: { scale: number; point: PointSize; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }): {
moveX: number;
moveY: number;
} {
const { scale, point, viewScaleInfo: prevViewScaleInfo } = opts;
const { offsetLeft, offsetTop } = prevViewScaleInfo;
const scaleDiff = scale / prevViewScaleInfo.scale;
const x0 = point.x;
const y0 = point.y;
const moveX = x0 - x0 * scaleDiff + (offsetLeft * scaleDiff - offsetLeft);
const moveY = y0 - y0 * scaleDiff + (offsetTop * scaleDiff - offsetTop);
return {
scale,
offsetTop,
offsetLeft,
offsetRight,
offsetBottom
moveX,
moveY
};
}
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 = 0, moveY = 0, viewScaleInfo, viewSizeInfo } = opts;
const { scale } = viewScaleInfo;
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;
}
}
offsetLeft += moveX;
offsetTop += moveY;
const w = contextWidth * scale;
const h = contextHeight * scale;
offsetRight = width - (w + offsetLeft);
offsetBottom = height - (h + offsetTop);
return {
scale,