mirror of
https://github.com/idrawjs/idraw
synced 2026-05-24 01:58:27 +00:00
feat: optimize middlewares and renderer
This commit is contained in:
parent
289657030e
commit
25a772420e
14 changed files with 437 additions and 275 deletions
|
|
@ -1,8 +1,12 @@
|
|||
export const key = 'LAYOUT_SELECT';
|
||||
// export const keyHoverElement = Symbol(`${key}_hoverElementSize`);
|
||||
export const keyLayoutActionType = Symbol(`${key}_layoutActionType`); // 'hover' | 'resize' | null = null;
|
||||
export const keyLayoutActionType = Symbol(`${key}_layoutActionType`); // 'resize' | null = null;
|
||||
export const keyLayoutControlType = Symbol(`${key}_layoutControlType`); // ControlType | null;
|
||||
export const keyLayoutController = Symbol(`${key}_layoutController`); // ElementSizeController | null = null;
|
||||
export const keyLayoutIsHover = Symbol(`${key}_layoutIsHover`); // boolean | null
|
||||
export const keyLayoutIsSelected = Symbol(`${key}_layoutIsSelected`); // boolean | null
|
||||
|
||||
export const selectColor = '#1973ba';
|
||||
// export const selectColor = '#1973ba';
|
||||
export const selectColor = '#b331c9';
|
||||
export const disableColor = '#5b5959b5';
|
||||
export const controllerSize = 10;
|
||||
|
|
|
|||
|
|
@ -1,60 +1,48 @@
|
|||
import type { BoardMiddleware, ElementSize, Point } from '@idraw/types';
|
||||
import { calcLayoutSizeController, isViewPointInVertexes, getViewScaleInfoFromSnapshot } from '@idraw/util';
|
||||
import { calcLayoutSizeController, isViewPointInVertexes, getViewScaleInfoFromSnapshot, isViewPointInElementSize, calcViewElementSize } from '@idraw/util';
|
||||
import type { LayoutSelectorSharedStorage, ControlType } from './types';
|
||||
import { keyLayoutActionType, keyLayoutController, keyLayoutControlType } from './config';
|
||||
import { keyActionType as keyElementActionType, middlewareEventSelectClear } from '../selector';
|
||||
import { drawLayoutController } from './util';
|
||||
import { keyLayoutActionType, keyLayoutController, keyLayoutControlType, keyLayoutIsHover, keyLayoutIsSelected, controllerSize } from './config';
|
||||
import { keyActionType as keyElementActionType, keyHoverElement, middlewareEventSelectClear } from '../selector';
|
||||
import { drawLayoutController, drawLayoutHover } from './util';
|
||||
import { eventChange } from '../../config';
|
||||
|
||||
export { keyLayoutIsSelected };
|
||||
|
||||
export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStorage> = (opts) => {
|
||||
const { sharer, boardContent, calculator, viewer, eventHub } = opts;
|
||||
const { overlayContext } = boardContent;
|
||||
|
||||
let prevPoint: Point | null = null;
|
||||
let prevIsHover: boolean | null = null;
|
||||
let prevIsSelected: boolean | null = null;
|
||||
let isBusy: boolean | null = null;
|
||||
|
||||
const clear = () => {
|
||||
prevPoint = null;
|
||||
sharer.setSharedStorage(keyLayoutActionType, null);
|
||||
sharer.setSharedStorage(keyLayoutControlType, null);
|
||||
sharer.setSharedStorage(keyLayoutController, null);
|
||||
sharer.setSharedStorage(keyLayoutIsHover, null);
|
||||
sharer.setSharedStorage(keyLayoutIsSelected, null);
|
||||
prevIsHover = null;
|
||||
prevIsSelected = null;
|
||||
isBusy = null;
|
||||
};
|
||||
|
||||
const isInElementAction = () => {
|
||||
const elementType = sharer.getSharedStorage(keyElementActionType);
|
||||
if (elementType) {
|
||||
const isInElementHover = () => {
|
||||
const hoverElement = sharer.getSharedStorage(keyHoverElement);
|
||||
if (hoverElement) {
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const isDisbaledControl = (controlType: ControlType) => {
|
||||
const data = sharer.getActiveStorage('data');
|
||||
if (data?.layout?.operations) {
|
||||
const operations = data.layout.operations;
|
||||
if (controlType === 'left' && operations.disabledLeft === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'top' && operations.disabledTop === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'right' && operations.disabledRight === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'bottom' && operations.disabledBottom === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'top-left' && operations.disabledTopLeft === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'top-right' && operations.disabledTopRight === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'bottom-left' && operations.disabledBottomLeft === true) {
|
||||
return true;
|
||||
}
|
||||
if (controlType === 'bottom-right' && operations.disabledBottomRight === true) {
|
||||
return true;
|
||||
}
|
||||
const isInElementAction = () => {
|
||||
const elementActionType = sharer.getSharedStorage(keyElementActionType);
|
||||
if (elementActionType && elementActionType !== 'area') {
|
||||
clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
|
@ -68,6 +56,25 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
|
|||
return null;
|
||||
};
|
||||
|
||||
const isInLayout = (p: Point) => {
|
||||
const size = getLayoutSize();
|
||||
if (size) {
|
||||
const { x, y, w, h } = size;
|
||||
const viewScaleInfo = sharer.getActiveViewScaleInfo();
|
||||
const viewSize = calcViewElementSize(
|
||||
{
|
||||
x: x - controllerSize / 2,
|
||||
y: y - controllerSize / 2,
|
||||
w: w + controllerSize,
|
||||
h: h + controllerSize
|
||||
},
|
||||
{ viewScaleInfo }
|
||||
);
|
||||
return isViewPointInElementSize(p, viewSize);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const resetController = () => {
|
||||
const viewScaleInfo = sharer.getActiveViewScaleInfo();
|
||||
const size: ElementSize | null = getLayoutSize();
|
||||
|
|
@ -105,6 +112,17 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
|
|||
return null;
|
||||
};
|
||||
|
||||
const updateCursor = (controlType?: ControlType | null) => {
|
||||
if (isBusy === true) {
|
||||
return;
|
||||
}
|
||||
eventHub.trigger('cursor', {
|
||||
type: controlType ? `resize-${controlType}` : controlType,
|
||||
groupQueue: [],
|
||||
element: getLayoutSize()
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
name: '@middleware/layout-selector',
|
||||
use: () => {
|
||||
|
|
@ -112,100 +130,160 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
|
|||
resetController();
|
||||
},
|
||||
hover: (e) => {
|
||||
if (isBusy === true) {
|
||||
return;
|
||||
}
|
||||
if (isInElementAction()) {
|
||||
return;
|
||||
}
|
||||
const prevLayoutActionType = sharer.getSharedStorage(keyLayoutActionType);
|
||||
|
||||
const data = sharer.getActiveStorage('data');
|
||||
if (data?.layout && prevLayoutActionType !== 'resize') {
|
||||
resetController();
|
||||
const layoutControlType = resetControlType(e);
|
||||
if (layoutControlType) {
|
||||
sharer.setSharedStorage(keyLayoutActionType, 'hover');
|
||||
if (!isDisbaledControl(layoutControlType)) {
|
||||
eventHub.trigger('cursor', {
|
||||
type: `resize-${layoutControlType}`,
|
||||
groupQueue: [],
|
||||
element: getLayoutSize()
|
||||
});
|
||||
}
|
||||
if (isInElementHover()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInLayout(e.point)) {
|
||||
sharer.setSharedStorage(keyLayoutIsHover, true);
|
||||
} else {
|
||||
sharer.setSharedStorage(keyLayoutIsHover, false);
|
||||
if (prevIsHover === true) {
|
||||
viewer.drawFrame();
|
||||
} else {
|
||||
sharer.setSharedStorage(keyLayoutActionType, null);
|
||||
prevIsHover = false;
|
||||
}
|
||||
}
|
||||
if (['hover', 'resize'].includes(sharer.getSharedStorage(keyLayoutActionType) as string)) {
|
||||
return false;
|
||||
|
||||
if (sharer.getSharedStorage(keyLayoutIsSelected) === true) {
|
||||
const prevLayoutActionType = sharer.getSharedStorage(keyLayoutActionType);
|
||||
const data = sharer.getActiveStorage('data');
|
||||
if (data?.layout) {
|
||||
if (prevLayoutActionType !== 'resize') {
|
||||
resetController();
|
||||
const layoutControlType = resetControlType(e);
|
||||
|
||||
if (layoutControlType) {
|
||||
updateCursor(layoutControlType);
|
||||
} else {
|
||||
updateCursor();
|
||||
sharer.setSharedStorage(keyLayoutActionType, null);
|
||||
}
|
||||
} else {
|
||||
const layoutControlType = resetControlType(e);
|
||||
updateCursor(layoutControlType);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (prevLayoutActionType === 'hover' && !sharer.getSharedStorage(keyLayoutActionType)) {
|
||||
|
||||
if (sharer.getSharedStorage(keyLayoutIsHover) && !prevIsHover) {
|
||||
viewer.drawFrame();
|
||||
}
|
||||
prevIsHover = sharer.getSharedStorage(keyLayoutIsHover);
|
||||
},
|
||||
|
||||
pointStart: (e) => {
|
||||
if (isInElementAction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInLayout(e.point)) {
|
||||
sharer.setSharedStorage(keyLayoutIsSelected, true);
|
||||
} else {
|
||||
if (prevIsSelected === true) {
|
||||
clear();
|
||||
viewer.drawFrame();
|
||||
}
|
||||
sharer.setSharedStorage(keyLayoutIsSelected, false);
|
||||
}
|
||||
|
||||
resetController();
|
||||
const layoutControlType = resetControlType(e);
|
||||
prevPoint = e.point;
|
||||
|
||||
if (layoutControlType) {
|
||||
if (isDisbaledControl(layoutControlType)) {
|
||||
return;
|
||||
}
|
||||
sharer.setSharedStorage(keyLayoutActionType, 'resize');
|
||||
return false;
|
||||
}
|
||||
const layoutActionType = sharer.getSharedStorage(keyLayoutActionType);
|
||||
if (['hover', 'resize'].includes(layoutActionType as string)) {
|
||||
return false;
|
||||
|
||||
if (sharer.getSharedStorage(keyLayoutIsSelected) === true && !prevIsSelected) {
|
||||
viewer.drawFrame();
|
||||
}
|
||||
prevIsSelected = sharer.getSharedStorage(keyLayoutIsSelected);
|
||||
},
|
||||
pointMove: (e) => {
|
||||
if (isInElementAction()) {
|
||||
return;
|
||||
if (!sharer.getSharedStorage(keyLayoutIsSelected)) {
|
||||
if (isInElementAction()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const layoutActionType = sharer.getSharedStorage(keyLayoutActionType);
|
||||
const layoutControlType = sharer.getSharedStorage(keyLayoutControlType);
|
||||
const data = sharer.getActiveStorage('data');
|
||||
if (layoutControlType && isDisbaledControl(layoutControlType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (layoutActionType === 'resize' && layoutControlType && data?.layout) {
|
||||
if (prevPoint) {
|
||||
isBusy = true;
|
||||
const scale = sharer.getActiveStorage('scale');
|
||||
const moveX = (e.point.x - prevPoint.x) / scale;
|
||||
const moveY = (e.point.y - prevPoint.y) / scale;
|
||||
const { x, y, w, h } = data.layout;
|
||||
|
||||
const viewMoveX = e.point.x - prevPoint.x;
|
||||
const viewMoveY = e.point.y - prevPoint.y;
|
||||
const moveX = viewMoveX / scale;
|
||||
const moveY = viewMoveY / scale;
|
||||
const { x, y, w, h, operations = {} } = data.layout;
|
||||
const { position = 'absolute' } = operations;
|
||||
if (layoutControlType === 'top') {
|
||||
data.layout.y = calculator.toGridNum(y + moveY);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
if (position === 'relative') {
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
viewer.scroll({ moveY: viewMoveY });
|
||||
} else {
|
||||
data.layout.y = calculator.toGridNum(y + moveY);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
}
|
||||
} else if (layoutControlType === 'right') {
|
||||
data.layout.w = calculator.toGridNum(w + moveX);
|
||||
} else if (layoutControlType === 'bottom') {
|
||||
data.layout.h = calculator.toGridNum(h + moveY);
|
||||
} else if (layoutControlType === 'left') {
|
||||
data.layout.x = calculator.toGridNum(x + moveX);
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
if (position === 'relative') {
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
viewer.scroll({ moveX: viewMoveX });
|
||||
} else {
|
||||
data.layout.x = calculator.toGridNum(x + moveX);
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
}
|
||||
} else if (layoutControlType === 'top-left') {
|
||||
data.layout.x = calculator.toGridNum(x + moveX);
|
||||
data.layout.y = calculator.toGridNum(y + moveY);
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
if (position === 'relative') {
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
viewer.scroll({ moveX: viewMoveX, moveY: viewMoveY });
|
||||
} else {
|
||||
data.layout.x = calculator.toGridNum(x + moveX);
|
||||
data.layout.y = calculator.toGridNum(y + moveY);
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
}
|
||||
} else if (layoutControlType === 'top-right') {
|
||||
data.layout.y = calculator.toGridNum(y + moveY);
|
||||
data.layout.w = calculator.toGridNum(w + moveX);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
if (position === 'relative') {
|
||||
viewer.scroll({
|
||||
moveY: viewMoveY
|
||||
});
|
||||
data.layout.w = calculator.toGridNum(w + moveX);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
} else {
|
||||
data.layout.y = calculator.toGridNum(y + moveY);
|
||||
data.layout.w = calculator.toGridNum(w + moveX);
|
||||
data.layout.h = calculator.toGridNum(h - moveY);
|
||||
}
|
||||
} else if (layoutControlType === 'bottom-right') {
|
||||
data.layout.w = calculator.toGridNum(w + moveX);
|
||||
data.layout.h = calculator.toGridNum(h + moveY);
|
||||
} else if (layoutControlType === 'bottom-left') {
|
||||
data.layout.x = calculator.toGridNum(x + moveX);
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
data.layout.h = calculator.toGridNum(h + moveY);
|
||||
if (position === 'relative') {
|
||||
viewer.scroll({
|
||||
moveX: viewMoveX
|
||||
});
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
data.layout.h = calculator.toGridNum(h + moveY);
|
||||
} else {
|
||||
data.layout.x = calculator.toGridNum(x + moveX);
|
||||
data.layout.w = calculator.toGridNum(w - moveX);
|
||||
data.layout.h = calculator.toGridNum(h + moveY);
|
||||
}
|
||||
}
|
||||
}
|
||||
prevPoint = e.point;
|
||||
|
|
@ -215,35 +293,44 @@ export const MiddlewareLayoutSelector: BoardMiddleware<LayoutSelectorSharedStora
|
|||
return false;
|
||||
}
|
||||
|
||||
if (['hover', 'resize'].includes(layoutActionType as string)) {
|
||||
if (['resize'].includes(layoutActionType as string)) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
pointEnd: () => {
|
||||
isBusy = false;
|
||||
const layoutActionType = sharer.getSharedStorage(keyLayoutActionType);
|
||||
const layoutControlType = sharer.getSharedStorage(keyLayoutControlType);
|
||||
const data = sharer.getActiveStorage('data');
|
||||
if (data && layoutActionType === 'resize' && layoutControlType && !isDisbaledControl(layoutControlType)) {
|
||||
if (data && layoutActionType === 'resize' && layoutControlType) {
|
||||
eventHub.trigger(eventChange, {
|
||||
type: 'changeLayout',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
clear();
|
||||
},
|
||||
beforeDrawFrame: ({ snapshot }) => {
|
||||
if (isInElementAction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { sharedStore, activeStore } = snapshot;
|
||||
const layoutActionType = sharedStore[keyLayoutActionType];
|
||||
const layoutControlType = sharedStore[keyLayoutControlType];
|
||||
const layoutIsHover = sharedStore[keyLayoutIsHover];
|
||||
const layoutIsSelected = sharedStore[keyLayoutIsSelected];
|
||||
|
||||
if (activeStore.data?.layout && layoutActionType && layoutControlType) {
|
||||
if (['hover', 'resize'].includes(layoutActionType)) {
|
||||
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);
|
||||
const { x, y, w, h } = activeStore.data.layout;
|
||||
const size = { x, y, w, h };
|
||||
const controller = calcLayoutSizeController(size, { viewScaleInfo, controllerSize: 10 });
|
||||
if (activeStore.data?.layout) {
|
||||
const { x, y, w, h } = activeStore.data.layout;
|
||||
const viewScaleInfo = getViewScaleInfoFromSnapshot(snapshot);
|
||||
const size = { x, y, w, h };
|
||||
const controller = calcLayoutSizeController(size, { viewScaleInfo, controllerSize });
|
||||
|
||||
if (layoutIsHover === true) {
|
||||
const viewSize = calcViewElementSize(size, { viewScaleInfo });
|
||||
drawLayoutHover(overlayContext, { layoutSize: viewSize });
|
||||
}
|
||||
|
||||
if ((layoutActionType && ['resize'].includes(layoutActionType)) || layoutIsSelected === true) {
|
||||
drawLayoutController(overlayContext, { controller, operations: activeStore.data.layout.operations || {} });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import type { LayoutSizeController } from '@idraw/types';
|
||||
import { keyLayoutActionType, keyLayoutControlType, keyLayoutController } from './config';
|
||||
import { keyActionType as keyElementActionType } from '../selector';
|
||||
import type { LayoutSizeController, Element } from '@idraw/types';
|
||||
import { keyLayoutActionType, keyLayoutControlType, keyLayoutController, keyLayoutIsHover, keyLayoutIsSelected } from './config';
|
||||
import { keyActionType as keyElementActionType, keyHoverElement } from '../selector';
|
||||
import type { ActionType as ElementActionType } from '../selector';
|
||||
|
||||
export type ActionType = 'hover' | 'resize' | null;
|
||||
export type ActionType = 'resize' | null;
|
||||
|
||||
export type ControlType = 'left' | 'right' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
||||
|
||||
|
|
@ -12,4 +12,7 @@ export type LayoutSelectorSharedStorage = {
|
|||
[keyLayoutControlType]: ControlType | null;
|
||||
[keyLayoutController]: LayoutSizeController | null;
|
||||
[keyElementActionType]: ElementActionType | null;
|
||||
[keyHoverElement]: Element | null;
|
||||
[keyLayoutIsHover]: boolean | null;
|
||||
[keyLayoutIsSelected]: boolean | null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { ViewContext2D, LayoutSizeController, DataLayout, ViewRectVertexes, PointSize } from '@idraw/types';
|
||||
import type { ViewContext2D, LayoutSizeController, DataLayout, ViewRectVertexes, PointSize, ElementSize } from '@idraw/types';
|
||||
import { selectColor, disableColor } from './config';
|
||||
|
||||
function drawControllerBox(ctx: ViewContext2D, boxVertexes: ViewRectVertexes) {
|
||||
|
|
@ -109,3 +109,24 @@ export function drawLayoutController(
|
|||
drawControllerBox(ctx, bottomLeft.vertexes);
|
||||
}
|
||||
}
|
||||
|
||||
export function drawLayoutHover(
|
||||
ctx: ViewContext2D,
|
||||
opts: {
|
||||
layoutSize: ElementSize;
|
||||
}
|
||||
) {
|
||||
const { layoutSize } = opts;
|
||||
const { x, y, w, h } = layoutSize;
|
||||
ctx.setLineDash([]);
|
||||
ctx.strokeStyle = selectColor;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + w, y);
|
||||
ctx.lineTo(x + w, y + h);
|
||||
ctx.lineTo(x, y + h);
|
||||
ctx.lineTo(x, y);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
export const key = 'SCROLL';
|
||||
export const keyXThumbRect = Symbol(`${key}_xThumbRect`);
|
||||
export const keyYThumbRect = Symbol(`${key}_yThumbRect`);
|
||||
export const keyHoverXThumbRect = Symbol(`${key}_hoverXThumbRect`);
|
||||
export const keyHoverYThumbRect = Symbol(`${key}_hoverYThumbRect`);
|
||||
export const keyPrevPoint = Symbol(`${key}_prevPoint`);
|
||||
export const keyActivePoint = Symbol(`${key}_activePoint`);
|
||||
export const keyActiveThumbType = Symbol(`${key}_activeThumbType`);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
import type { Point, BoardMiddleware, PointWatcherEvent, BoardWatherWheelEvent } from '@idraw/types';
|
||||
import { drawScroller, isPointInScrollThumb } from './util';
|
||||
// import type { ScrollbarThumbType } from './util';
|
||||
import { keyXThumbRect, keyYThumbRect, keyPrevPoint, keyActivePoint, keyActiveThumbType } from './config';
|
||||
import { keyXThumbRect, keyYThumbRect, keyPrevPoint, keyActivePoint, keyActiveThumbType, keyHoverXThumbRect, keyHoverYThumbRect } from './config';
|
||||
import type { DeepScrollerSharedStorage } from './types';
|
||||
|
||||
export const MiddlewareScroller: BoardMiddleware<DeepScrollerSharedStorage> = (opts) => {
|
||||
const { viewer, boardContent, sharer } = opts;
|
||||
const { viewer, boardContent, sharer, eventHub } = opts;
|
||||
const { overlayContext } = boardContent;
|
||||
sharer.setSharedStorage(keyXThumbRect, null); // null | ElementSize
|
||||
sharer.setSharedStorage(keyYThumbRect, null); // null | ElementSize
|
||||
let isBusy: boolean = false;
|
||||
|
||||
// viewer.drawFrame();
|
||||
const clear = () => {
|
||||
sharer.setSharedStorage(keyPrevPoint, null); // null | Point;
|
||||
sharer.setSharedStorage(keyActivePoint, null); // null | Point;
|
||||
sharer.setSharedStorage(keyActiveThumbType, null); // null | 'X' | 'Y'
|
||||
sharer.setSharedStorage(keyHoverXThumbRect, null); // null | boolean
|
||||
sharer.setSharedStorage(keyHoverYThumbRect, null); // null | boolean
|
||||
isBusy = false;
|
||||
};
|
||||
|
||||
clear();
|
||||
|
|
@ -64,10 +68,33 @@ export const MiddlewareScroller: BoardMiddleware<DeepScrollerSharedStorage> = (o
|
|||
viewer.drawFrame();
|
||||
},
|
||||
|
||||
hover: (e: PointWatcherEvent) => {
|
||||
if (isBusy === true) {
|
||||
return false;
|
||||
}
|
||||
const { point } = e;
|
||||
const thumbType = getThumbType(point);
|
||||
if (thumbType === 'X' || thumbType === 'Y') {
|
||||
if (thumbType === 'X') {
|
||||
sharer.setSharedStorage(keyHoverXThumbRect, true);
|
||||
sharer.setSharedStorage(keyHoverYThumbRect, false);
|
||||
} else {
|
||||
sharer.setSharedStorage(keyHoverXThumbRect, false);
|
||||
sharer.setSharedStorage(keyHoverYThumbRect, true);
|
||||
}
|
||||
eventHub.trigger('cursor', { type: 'default' });
|
||||
return false;
|
||||
}
|
||||
|
||||
sharer.setSharedStorage(keyHoverXThumbRect, false);
|
||||
sharer.setSharedStorage(keyHoverYThumbRect, false);
|
||||
},
|
||||
|
||||
pointStart: (e: PointWatcherEvent) => {
|
||||
const { point } = e;
|
||||
const thumbType = getThumbType(point);
|
||||
if (thumbType === 'X' || thumbType === 'Y') {
|
||||
isBusy = true;
|
||||
sharer.setSharedStorage(keyActiveThumbType, thumbType);
|
||||
sharer.setSharedStorage(keyPrevPoint, point);
|
||||
return false;
|
||||
|
|
@ -88,6 +115,7 @@ export const MiddlewareScroller: BoardMiddleware<DeepScrollerSharedStorage> = (o
|
|||
}
|
||||
},
|
||||
pointEnd: () => {
|
||||
isBusy = false;
|
||||
const activeThumbType = sharer.getSharedStorage(keyActiveThumbType);
|
||||
clear();
|
||||
if (activeThumbType === 'X' || activeThumbType === 'Y') {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import type { Point, ElementSize } from '@idraw/types';
|
||||
import { keyXThumbRect, keyYThumbRect, keyPrevPoint, keyActivePoint, keyActiveThumbType } from './config';
|
||||
import { keyXThumbRect, keyYThumbRect, keyPrevPoint, keyActivePoint, keyActiveThumbType, keyHoverXThumbRect, keyHoverYThumbRect } from './config';
|
||||
|
||||
export type DeepScrollerSharedStorage = {
|
||||
[keyXThumbRect]: null | ElementSize;
|
||||
[keyYThumbRect]: null | ElementSize;
|
||||
[keyHoverXThumbRect]: boolean | null;
|
||||
[keyHoverYThumbRect]: boolean | null;
|
||||
[keyPrevPoint]: null | Point;
|
||||
[keyActivePoint]: null | Point;
|
||||
[keyActiveThumbType]: null | 'X' | 'Y';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Point, BoardViewerFrameSnapshot, ViewScaleInfo, ViewSizeInfo, ViewContext2D, ElementSize } from '@idraw/types';
|
||||
import { getViewScaleInfoFromSnapshot, getViewSizeInfoFromSnapshot } from '@idraw/util';
|
||||
import { keyActivePoint, keyActiveThumbType, keyPrevPoint, keyXThumbRect, keyYThumbRect } from './config';
|
||||
import { keyActivePoint, keyActiveThumbType, keyPrevPoint, keyXThumbRect, keyYThumbRect, keyHoverXThumbRect, keyHoverYThumbRect } from './config';
|
||||
|
||||
const minScrollerWidth = 12;
|
||||
const scrollerLineWidth = 16;
|
||||
|
|
@ -10,7 +10,8 @@ export type ScrollbarThumbType = 'X' | 'Y';
|
|||
|
||||
const scrollConfig = {
|
||||
width: minScrollerWidth,
|
||||
thumbColor: '#000000AA',
|
||||
thumbColor: '#0000008A',
|
||||
thumbHoverColor: '#000000EE',
|
||||
scrollBarColor: '#FFFFFF60',
|
||||
showScrollBar: false
|
||||
};
|
||||
|
|
@ -51,6 +52,8 @@ interface ScrollInfo {
|
|||
activeThumbType: ScrollbarThumbType | null;
|
||||
xThumbRect: ElementSize | null;
|
||||
yThumbRect: ElementSize | null;
|
||||
hoverXThumb: boolean | null;
|
||||
hoverYThumb: boolean | null;
|
||||
}
|
||||
function getScrollInfoFromSnapshot(snapshot: BoardViewerFrameSnapshot): ScrollInfo {
|
||||
const { sharedStore } = snapshot;
|
||||
|
|
@ -59,12 +62,15 @@ function getScrollInfoFromSnapshot(snapshot: BoardViewerFrameSnapshot): ScrollIn
|
|||
prevPoint: sharedStore[keyPrevPoint] || null,
|
||||
activeThumbType: sharedStore[keyActiveThumbType] || null,
|
||||
xThumbRect: sharedStore[keyXThumbRect] || null,
|
||||
yThumbRect: sharedStore[keyYThumbRect] || null
|
||||
yThumbRect: sharedStore[keyYThumbRect] || null,
|
||||
hoverXThumb: sharedStore[keyHoverXThumbRect],
|
||||
hoverYThumb: sharedStore[keyHoverYThumbRect]
|
||||
};
|
||||
return info;
|
||||
}
|
||||
|
||||
function calcScrollerInfo(viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeInfo) {
|
||||
function calcScrollerInfo(opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; hoverXThumb: boolean | null; hoverYThumb: boolean | null }) {
|
||||
const { viewScaleInfo, viewSizeInfo, hoverXThumb, hoverYThumb } = opts;
|
||||
const { width, height } = viewSizeInfo;
|
||||
const { offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
|
||||
const sliderMinSize = scrollerLineWidth * 2.5;
|
||||
|
|
@ -125,7 +131,8 @@ function calcScrollerInfo(viewScaleInfo: ViewScaleInfo, viewSizeInfo: ViewSizeIn
|
|||
ySize,
|
||||
translateY,
|
||||
translateX,
|
||||
thumbColor: scrollConfig.thumbColor,
|
||||
xThumbColor: hoverXThumb ? scrollConfig.thumbHoverColor : scrollConfig.thumbColor,
|
||||
yThumbColor: hoverYThumb ? scrollConfig.thumbHoverColor : scrollConfig.thumbColor,
|
||||
scrollBarColor: scrollConfig.scrollBarColor,
|
||||
xThumbRect,
|
||||
yThumbRect
|
||||
|
|
@ -197,9 +204,9 @@ function drawScrollerThumb(
|
|||
function drawScrollerInfo(overlayContext: ViewContext2D, opts: { viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo; scrollInfo: ScrollInfo }) {
|
||||
const ctx = overlayContext;
|
||||
const { viewScaleInfo, viewSizeInfo, scrollInfo } = opts;
|
||||
const { activeThumbType, prevPoint, activePoint } = scrollInfo;
|
||||
const { activeThumbType, prevPoint, activePoint, hoverXThumb, hoverYThumb } = scrollInfo;
|
||||
const { width, height } = viewSizeInfo;
|
||||
const wrapper = calcScrollerInfo(viewScaleInfo, viewSizeInfo);
|
||||
const wrapper = calcScrollerInfo({ viewScaleInfo, viewSizeInfo, hoverXThumb, hoverYThumb });
|
||||
let xThumbRect: ElementSize = { ...wrapper.xThumbRect };
|
||||
let yThumbRect: ElementSize = { ...wrapper.yThumbRect };
|
||||
|
||||
|
|
@ -225,7 +232,7 @@ function drawScrollerInfo(overlayContext: ViewContext2D, opts: { viewScaleInfo:
|
|||
axis: 'X',
|
||||
...xThumbRect,
|
||||
r: wrapper.lineSize / 2,
|
||||
color: wrapper.thumbColor
|
||||
color: wrapper.xThumbColor
|
||||
});
|
||||
|
||||
// y-bar
|
||||
|
|
@ -240,7 +247,7 @@ function drawScrollerInfo(overlayContext: ViewContext2D, opts: { viewScaleInfo:
|
|||
axis: 'Y',
|
||||
...yThumbRect,
|
||||
r: wrapper.lineSize / 2,
|
||||
color: wrapper.thumbColor
|
||||
color: wrapper.yThumbColor
|
||||
});
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
|
|
|
|||
|
|
@ -75,8 +75,9 @@ import {
|
|||
import { calcReferenceInfo } from './reference';
|
||||
import { middlewareEventTextEdit } from '../text-editor';
|
||||
import { eventChange } from '../../config';
|
||||
import { keyLayoutIsSelected } from '../layout-selector';
|
||||
|
||||
export { keySelectedElementList, keyActionType, keyResizeType, keyGroupQueue };
|
||||
export { keySelectedElementList, keyHoverElement, keyActionType, keyResizeType, keyGroupQueue };
|
||||
export type { DeepSelectorSharedStorage, ActionType };
|
||||
|
||||
export { middlewareEventSelect, middlewareEventSelectClear, middlewareEventSelectInGroup, middlewareEventSnapToGrid };
|
||||
|
|
@ -237,10 +238,15 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
|
|||
},
|
||||
|
||||
hover: (e: PointWatcherEvent) => {
|
||||
const layoutIsSelected = sharer.getSharedStorage(keyLayoutIsSelected);
|
||||
|
||||
const resizeType = sharer.getSharedStorage(keyResizeType);
|
||||
const actionType = sharer.getSharedStorage(keyActionType);
|
||||
const groupQueue = sharer.getSharedStorage(keyGroupQueue);
|
||||
const triggerCursor = (target: PointTarget) => {
|
||||
if (layoutIsSelected === true) {
|
||||
return;
|
||||
}
|
||||
const cursor: string | null = target.type;
|
||||
if (inBusyMode === null) {
|
||||
eventHub.trigger('cursor', {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import {
|
|||
keyDebugStartHorizontal,
|
||||
keyDebugStartVertical
|
||||
} from './config';
|
||||
import { keyLayoutIsSelected } from '../layout-selector';
|
||||
|
||||
export {
|
||||
Data,
|
||||
|
|
@ -112,4 +113,7 @@ export type DeepSelectorSharedStorage = {
|
|||
[keyDebugEndVertical]: PointSize | null;
|
||||
[keyDebugStartHorizontal]: PointSize | null;
|
||||
[keyDebugStartVertical]: PointSize | null;
|
||||
|
||||
// layout-selector
|
||||
[keyLayoutIsSelected]: boolean | null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -174,9 +174,8 @@ export const MiddlewareTextEditor: BoardMiddleware<ExtendEventMap, CoreEventMap
|
|||
textarea.style.resize = 'none';
|
||||
textarea.style.overflow = 'hidden';
|
||||
textarea.style.wordBreak = 'break-all';
|
||||
// textarea.style.background = '#FFFFFF';
|
||||
textarea.style.background = 'transparent';
|
||||
// textarea.style.color = '#333333';
|
||||
textarea.style.borderRadius = `${(typeof detail.borderRadius === 'number' ? detail.borderRadius : 0) * scale}px`;
|
||||
textarea.style.background = `${detail.background || 'transparent'}`;
|
||||
textarea.style.color = `${detail.color || '#333333'}`;
|
||||
textarea.style.fontSize = `${detail.fontSize * scale}px`;
|
||||
textarea.style.lineHeight = `${(detail.lineHeight || detail.fontSize) * scale}px`;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export function drawBox(
|
|||
originElem: Element;
|
||||
calcElemSize: ElementSize;
|
||||
pattern?: string | CanvasPattern | null;
|
||||
renderContent: () => void;
|
||||
renderContent?: () => void;
|
||||
viewScaleInfo: ViewScaleInfo;
|
||||
viewSizeInfo: ViewSizeInfo;
|
||||
parentOpacity: number;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
|
||||
import { rotateElement, calcViewElementSize, enhanceFontFamliy } from '@idraw/util';
|
||||
import { is, isColorStr, getDefaultElementDetailConfig } from '@idraw/util';
|
||||
import { drawBox } from './box';
|
||||
import { drawBox, drawBoxShadow } from './box';
|
||||
|
||||
const detailConfig = getDefaultElementDetailConfig();
|
||||
|
||||
|
|
@ -20,172 +20,178 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render
|
|||
const { x, y, w, h, angle } = calcViewElementSize(elem, { viewScaleInfo }) || elem;
|
||||
const viewElem = { ...elem, ...{ x, y, w, h, angle } };
|
||||
rotateElement(ctx, { x, y, w, h, angle }, () => {
|
||||
drawBox(ctx, viewElem, {
|
||||
originElem: elem,
|
||||
calcElemSize: { x, y, w, h, angle },
|
||||
drawBoxShadow(ctx, viewElem, {
|
||||
viewScaleInfo,
|
||||
viewSizeInfo,
|
||||
parentOpacity,
|
||||
renderContent: () => {
|
||||
const detail: Element<'text'>['detail'] = {
|
||||
...detailConfig,
|
||||
...elem.detail
|
||||
};
|
||||
const originFontSize = detail.fontSize || detailConfig.fontSize;
|
||||
const fontSize = originFontSize * viewScaleInfo.scale;
|
||||
|
||||
if (fontSize < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originLineHeight = detail.lineHeight || originFontSize;
|
||||
const lineHeight = originLineHeight * viewScaleInfo.scale;
|
||||
|
||||
ctx.fillStyle = elem.detail.color || detailConfig.color;
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.$setFont({
|
||||
fontWeight: detail.fontWeight,
|
||||
fontSize: fontSize,
|
||||
fontFamily: enhanceFontFamliy(detail.fontFamily)
|
||||
drawBox(ctx, viewElem, {
|
||||
originElem: elem,
|
||||
calcElemSize: { x, y, w, h, angle },
|
||||
viewScaleInfo,
|
||||
viewSizeInfo,
|
||||
parentOpacity
|
||||
});
|
||||
let detailText = detail.text.replace(/\r\n/gi, '\n');
|
||||
if (detail.textTransform === 'lowercase') {
|
||||
detailText = detailText.toLowerCase();
|
||||
} else if (detail.textTransform === 'uppercase') {
|
||||
detailText = detailText.toUpperCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
{
|
||||
const detail: Element<'text'>['detail'] = {
|
||||
...detailConfig,
|
||||
...elem.detail
|
||||
};
|
||||
const originFontSize = detail.fontSize || detailConfig.fontSize;
|
||||
const fontSize = originFontSize * viewScaleInfo.scale;
|
||||
|
||||
const fontHeight = lineHeight;
|
||||
const detailTextList = detailText.split('\n');
|
||||
const lines: { text: string; width: number }[] = [];
|
||||
if (fontSize < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
let lineNum = 0;
|
||||
detailTextList.forEach((itemText: string, idx: number) => {
|
||||
if (detail.minInlineSize === 'maxContent') {
|
||||
lines.push({
|
||||
text: itemText,
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(itemText).width)
|
||||
const originLineHeight = detail.lineHeight || originFontSize;
|
||||
const lineHeight = originLineHeight * viewScaleInfo.scale;
|
||||
|
||||
ctx.fillStyle = elem.detail.color || detailConfig.color;
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.$setFont({
|
||||
fontWeight: detail.fontWeight,
|
||||
fontSize: fontSize,
|
||||
fontFamily: enhanceFontFamliy(detail.fontFamily)
|
||||
});
|
||||
let detailText = detail.text.replace(/\r\n/gi, '\n');
|
||||
if (detail.textTransform === 'lowercase') {
|
||||
detailText = detailText.toLowerCase();
|
||||
} else if (detail.textTransform === 'uppercase') {
|
||||
detailText = detailText.toUpperCase();
|
||||
}
|
||||
|
||||
const fontHeight = lineHeight;
|
||||
const detailTextList = detailText.split('\n');
|
||||
const lines: { text: string; width: number }[] = [];
|
||||
|
||||
let lineNum = 0;
|
||||
detailTextList.forEach((itemText: string, idx: number) => {
|
||||
if (detail.minInlineSize === 'maxContent') {
|
||||
lines.push({
|
||||
text: itemText,
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(itemText).width)
|
||||
});
|
||||
} else {
|
||||
let lineText = '';
|
||||
let splitStr = '';
|
||||
let tempStrList: string[] = itemText.split(splitStr);
|
||||
if (detail.wordBreak === 'normal') {
|
||||
const splitStr = ' ';
|
||||
const wordList = itemText.split(splitStr);
|
||||
tempStrList = [];
|
||||
wordList.forEach((word: string, idx: number) => {
|
||||
tempStrList.push(word);
|
||||
if (idx < wordList.length - 1) {
|
||||
tempStrList.push(splitStr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let lineText = '';
|
||||
let splitStr = '';
|
||||
let tempStrList: string[] = itemText.split(splitStr);
|
||||
if (detail.wordBreak === 'normal') {
|
||||
const splitStr = ' ';
|
||||
const wordList = itemText.split(splitStr);
|
||||
tempStrList = [];
|
||||
wordList.forEach((word: string, idx: number) => {
|
||||
tempStrList.push(word);
|
||||
if (idx < wordList.length - 1) {
|
||||
tempStrList.push(splitStr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (tempStrList.length === 1 && detail.overflow === 'visible') {
|
||||
lines.push({
|
||||
text: tempStrList[0],
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(tempStrList[0]).width)
|
||||
});
|
||||
} else if (tempStrList.length > 0) {
|
||||
for (let i = 0; i < tempStrList.length; i++) {
|
||||
if (isTextWidthWithinErrorRange(ctx.$doPixelRatio(w), ctx.measureText(lineText + tempStrList[i]).width, viewScaleInfo.scale)) {
|
||||
lineText += tempStrList[i] || '';
|
||||
} else {
|
||||
if (tempStrList.length === 1 && detail.overflow === 'visible') {
|
||||
lines.push({
|
||||
text: tempStrList[0],
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(tempStrList[0]).width)
|
||||
});
|
||||
} else if (tempStrList.length > 0) {
|
||||
for (let i = 0; i < tempStrList.length; i++) {
|
||||
if (isTextWidthWithinErrorRange(ctx.$doPixelRatio(w), ctx.measureText(lineText + tempStrList[i]).width, viewScaleInfo.scale)) {
|
||||
lineText += tempStrList[i] || '';
|
||||
} else {
|
||||
lines.push({
|
||||
text: lineText,
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
|
||||
});
|
||||
lineText = tempStrList[i] || '';
|
||||
lineNum++;
|
||||
}
|
||||
if ((lineNum + 1) * fontHeight > h && detail.overflow === 'hidden') {
|
||||
break;
|
||||
}
|
||||
if (tempStrList.length - 1 === i) {
|
||||
if ((lineNum + 1) * fontHeight <= h) {
|
||||
lines.push({
|
||||
text: lineText,
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
|
||||
});
|
||||
lineText = tempStrList[i] || '';
|
||||
lineNum++;
|
||||
}
|
||||
if ((lineNum + 1) * fontHeight > h && detail.overflow === 'hidden') {
|
||||
if (idx < detailTextList.length - 1) {
|
||||
lineNum++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (tempStrList.length - 1 === i) {
|
||||
if ((lineNum + 1) * fontHeight <= h) {
|
||||
lines.push({
|
||||
text: lineText,
|
||||
width: ctx.$undoPixelRatio(ctx.measureText(lineText).width)
|
||||
});
|
||||
if (idx < detailTextList.length - 1) {
|
||||
lineNum++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lines.push({
|
||||
text: '',
|
||||
width: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let startY = 0;
|
||||
let eachLineStartY = 0;
|
||||
if (fontHeight > fontSize) {
|
||||
eachLineStartY = (fontHeight - fontSize) / 2;
|
||||
}
|
||||
if (lines.length * fontHeight < h) {
|
||||
if (elem.detail.verticalAlign === 'top') {
|
||||
startY = 0;
|
||||
} else if (elem.detail.verticalAlign === 'bottom') {
|
||||
startY += h - lines.length * fontHeight;
|
||||
} else {
|
||||
// middle and default
|
||||
startY += (h - lines.length * fontHeight) / 2;
|
||||
lines.push({
|
||||
text: '',
|
||||
width: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// draw text lines
|
||||
{
|
||||
const _y = y + startY;
|
||||
if (detail.textShadowColor !== undefined && isColorStr(detail.textShadowColor)) {
|
||||
ctx.shadowColor = detail.textShadowColor;
|
||||
}
|
||||
if (detail.textShadowOffsetX !== undefined && is.number(detail.textShadowOffsetX)) {
|
||||
ctx.shadowOffsetX = detail.textShadowOffsetX;
|
||||
}
|
||||
if (detail.textShadowOffsetY !== undefined && is.number(detail.textShadowOffsetY)) {
|
||||
ctx.shadowOffsetY = detail.textShadowOffsetY;
|
||||
}
|
||||
if (detail.textShadowBlur !== undefined && is.number(detail.textShadowBlur)) {
|
||||
ctx.shadowBlur = detail.textShadowBlur;
|
||||
}
|
||||
lines.forEach((line, i) => {
|
||||
let _x = x;
|
||||
if (detail.textAlign === 'center') {
|
||||
_x = x + (w - line.width) / 2;
|
||||
} else if (detail.textAlign === 'right') {
|
||||
_x = x + (w - line.width);
|
||||
}
|
||||
ctx.fillText(line.text, _x, _y + fontHeight * i + eachLineStartY);
|
||||
});
|
||||
}
|
||||
|
||||
// // draw text stroke
|
||||
// if (isColorStr(detail.strokeColor) && detail.strokeWidth !== undefined && detail.strokeWidth > 0) {
|
||||
// const _y = y + startY;
|
||||
// lines.forEach((line, i) => {
|
||||
// let _x = x;
|
||||
// if (detail.textAlign === 'center') {
|
||||
// _x = x + (w - line.width) / 2;
|
||||
// } else if (detail.textAlign === 'right') {
|
||||
// _x = x + (w - line.width);
|
||||
// }
|
||||
// if (detail.strokeColor !== undefined) {
|
||||
// ctx.strokeStyle = detail.strokeColor;
|
||||
// }
|
||||
// if (detail.strokeWidth !== undefined && detail.strokeWidth > 0) {
|
||||
// ctx.lineWidth = detail.strokeWidth;
|
||||
// }
|
||||
// ctx.strokeText(line.text, _x, _y + fontHeight * i);
|
||||
// });
|
||||
// }
|
||||
let startY = 0;
|
||||
let eachLineStartY = 0;
|
||||
if (fontHeight > fontSize) {
|
||||
eachLineStartY = (fontHeight - fontSize) / 2;
|
||||
}
|
||||
});
|
||||
if (lines.length * fontHeight < h) {
|
||||
if (elem.detail.verticalAlign === 'top') {
|
||||
startY = 0;
|
||||
} else if (elem.detail.verticalAlign === 'bottom') {
|
||||
startY += h - lines.length * fontHeight;
|
||||
} else {
|
||||
// middle and default
|
||||
startY += (h - lines.length * fontHeight) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// draw text lines
|
||||
{
|
||||
const _y = y + startY;
|
||||
if (detail.textShadowColor !== undefined && isColorStr(detail.textShadowColor)) {
|
||||
ctx.shadowColor = detail.textShadowColor;
|
||||
}
|
||||
if (detail.textShadowOffsetX !== undefined && is.number(detail.textShadowOffsetX)) {
|
||||
ctx.shadowOffsetX = detail.textShadowOffsetX;
|
||||
}
|
||||
if (detail.textShadowOffsetY !== undefined && is.number(detail.textShadowOffsetY)) {
|
||||
ctx.shadowOffsetY = detail.textShadowOffsetY;
|
||||
}
|
||||
if (detail.textShadowBlur !== undefined && is.number(detail.textShadowBlur)) {
|
||||
ctx.shadowBlur = detail.textShadowBlur;
|
||||
}
|
||||
lines.forEach((line, i) => {
|
||||
let _x = x;
|
||||
if (detail.textAlign === 'center') {
|
||||
_x = x + (w - line.width) / 2;
|
||||
} else if (detail.textAlign === 'right') {
|
||||
_x = x + (w - line.width);
|
||||
}
|
||||
ctx.fillText(line.text, _x, _y + fontHeight * i + eachLineStartY);
|
||||
});
|
||||
}
|
||||
|
||||
// // draw text stroke
|
||||
// if (isColorStr(detail.strokeColor) && detail.strokeWidth !== undefined && detail.strokeWidth > 0) {
|
||||
// const _y = y + startY;
|
||||
// lines.forEach((line, i) => {
|
||||
// let _x = x;
|
||||
// if (detail.textAlign === 'center') {
|
||||
// _x = x + (w - line.width) / 2;
|
||||
// } else if (detail.textAlign === 'right') {
|
||||
// _x = x + (w - line.width);
|
||||
// }
|
||||
// if (detail.strokeColor !== undefined) {
|
||||
// ctx.strokeStyle = detail.strokeColor;
|
||||
// }
|
||||
// if (detail.strokeWidth !== undefined && detail.strokeWidth > 0) {
|
||||
// ctx.lineWidth = detail.strokeWidth;
|
||||
// }
|
||||
// ctx.strokeText(line.text, _x, _y + fontHeight * i);
|
||||
// });
|
||||
// }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,7 @@ export type DataLayout = Pick<ElementSize, 'x' | 'y' | 'w' | 'h'> & {
|
|||
'background' | 'borderWidth' | 'overflow' | 'borderColor' | 'borderDash' | 'borderRadius' | 'shadowBlur' | 'shadowColor' | 'shadowOffsetX' | 'shadowOffsetY'
|
||||
>;
|
||||
operations?: {
|
||||
disabledLeft?: boolean;
|
||||
disabledTop?: boolean;
|
||||
disabledRight?: boolean;
|
||||
disabledBottom?: boolean;
|
||||
disabledTopLeft?: boolean;
|
||||
disabledTopRight?: boolean;
|
||||
disabledBottomLeft?: boolean;
|
||||
disabledBottomRight?: boolean;
|
||||
position?: 'absolute' | 'relative';
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue