Skip to content

Commit

Permalink
Merge pull request #271 from idrawjs/dev-v0.4
Browse files Browse the repository at this point in the history
feat: implement lock status, destroy method and centerContent method
  • Loading branch information
chenshenhai authored Jan 27, 2024
2 parents f4fe748 + fe377ae commit 21afa9b
Show file tree
Hide file tree
Showing 17 changed files with 316 additions and 41 deletions.
1 change: 0 additions & 1 deletion packages/board/src/lib/watcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export class BoardWatcher extends EventEmitter<BoardWatcherEventMap> {
container.removeEventListener('wheel', this.#onWheel);
container.removeEventListener('click', this.#onClick);
container.removeEventListener('contextmenu', this.#onContextMenu);
this.destroy();
}

#onWheel = (e: WheelEvent) => {
Expand Down
10 changes: 6 additions & 4 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@ export { MiddlewareDragger } from './middleware/dragger';
export class Core<E extends CoreEvent = CoreEvent> {
#board: Board<E>;
// #opts: CoreOptions;
// #canvas: HTMLCanvasElement;
#canvas: HTMLCanvasElement;
#container: HTMLDivElement;

constructor(container: HTMLDivElement, opts: CoreOptions) {
const { devicePixelRatio = 1, width, height } = opts;
const { devicePixelRatio = 1, width, height, createCustomContext2D } = opts;

// this.#opts = opts;
// this.#canvas = canvas;
this.#container = container;
const canvas = document.createElement('canvas');
this.#canvas = canvas;
this.#initContainer();
container.appendChild(canvas);

const boardContent = createBoardContent(canvas, { width, height, devicePixelRatio, offscreen: true });
const boardContent = createBoardContent(canvas, { width, height, devicePixelRatio, offscreen: true, createCustomContext2D });
const board = new Board<E>({ boardContent, container });
const sharer = board.getSharer();
sharer.setActiveViewSizeInfo({
Expand All @@ -46,6 +47,7 @@ export class Core<E extends CoreEvent = CoreEvent> {

destroy() {
this.#board.destroy();
this.#canvas.remove();
}

#initContainer() {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/middleware/selector/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ export const selectWrapperBorderWidth = 2;
export const resizeControllerBorderWidth = 4;
export const areaBorderWidth = 1;
export const wrapperColor = '#1973ba';

export const lockColor = '#5b5959b5';
// export const wrapperColor = '#1890ff';
58 changes: 56 additions & 2 deletions packages/core/src/middleware/selector/draw-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
import { rotateElementVertexes, calcViewVertexes } from '@idraw/util';
import type { AreaSize } from './types';

import { resizeControllerBorderWidth, areaBorderWidth, wrapperColor, selectWrapperBorderWidth } from './config';
import { resizeControllerBorderWidth, areaBorderWidth, wrapperColor, selectWrapperBorderWidth, lockColor } from './config';

function drawVertexes(
ctx: ViewContext2D,
Expand Down Expand Up @@ -51,6 +51,61 @@ export function drawHoverVertexesWrapper(
drawVertexes(ctx, calcViewVertexes(vertexes, opts), wrapperOpts);
}

function drawCrossVertexes(
ctx: ViewContext2D,
vertexes: ViewRectVertexes,
opts: { borderColor: string; borderWidth: number; background: string; lineDash: number[] }
) {
const { borderColor, borderWidth, background, lineDash } = opts;
ctx.setLineDash([]);
ctx.lineWidth = borderWidth;
ctx.strokeStyle = borderColor;
ctx.fillStyle = background;
ctx.setLineDash(lineDash);
ctx.beginPath();
ctx.moveTo(vertexes[0].x, vertexes[0].y);
ctx.lineTo(vertexes[2].x, vertexes[2].y);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.moveTo(vertexes[1].x, vertexes[1].y);
ctx.lineTo(vertexes[3].x, vertexes[3].y);
ctx.closePath();
ctx.stroke();
}

export function drawLockVertexesWrapper(
ctx: ViewContext2D,
vertexes: ViewRectVertexes | null,
opts: {
viewScaleInfo: ViewScaleInfo;
viewSizeInfo: ViewSizeInfo;
controller?: ElementSizeController | null;
}
) {
if (!vertexes) {
return;
}
const wrapperOpts = { borderColor: lockColor, borderWidth: 1, background: 'transparent', lineDash: [] };
drawVertexes(ctx, calcViewVertexes(vertexes, opts), wrapperOpts);

const { controller } = opts;
if (controller) {
const { topLeft, topRight, bottomLeft, bottomRight, topMiddle, bottomMiddle, leftMiddle, rightMiddle } = controller;
const ctrlOpts = { ...wrapperOpts, borderWidth: 1, background: lockColor };

drawCrossVertexes(ctx, calcViewVertexes(topMiddle.vertexes, opts), ctrlOpts);
drawCrossVertexes(ctx, calcViewVertexes(bottomMiddle.vertexes, opts), ctrlOpts);
drawCrossVertexes(ctx, calcViewVertexes(leftMiddle.vertexes, opts), ctrlOpts);
drawCrossVertexes(ctx, calcViewVertexes(rightMiddle.vertexes, opts), ctrlOpts);

drawCrossVertexes(ctx, calcViewVertexes(topLeft.vertexes, opts), ctrlOpts);
drawCrossVertexes(ctx, calcViewVertexes(topRight.vertexes, opts), ctrlOpts);
drawCrossVertexes(ctx, calcViewVertexes(bottomLeft.vertexes, opts), ctrlOpts);
drawCrossVertexes(ctx, calcViewVertexes(bottomRight.vertexes, opts), ctrlOpts);
}
}

export function drawSelectedElementControllersVertexes(
ctx: ViewContext2D,
controller: ElementSizeController | null,
Expand All @@ -60,7 +115,6 @@ export function drawSelectedElementControllersVertexes(
return;
}
const { elementWrapper, topLeft, topRight, bottomLeft, bottomRight } = controller;
// const wrapperColor = 'red'; // TODO
const wrapperOpts = { borderColor: wrapperColor, borderWidth: selectWrapperBorderWidth, background: 'transparent', lineDash: [] };
const ctrlOpts = { ...wrapperOpts, borderWidth: resizeControllerBorderWidth, background: '#FFFFFF' };

Expand Down
71 changes: 58 additions & 13 deletions packages/core/src/middleware/selector/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@ import type {
PointWatcherEvent,
BoardMiddleware,
Element,
ElementSize,
ActionType,
ResizeType,
DeepSelectorSharedStorage,
ElementType,
PointTarget
} from './types';
import { drawHoverVertexesWrapper, drawArea, drawListArea, drawGroupQueueVertexesWrappers, drawSelectedElementControllersVertexes } from './draw-wrapper';
import {
drawHoverVertexesWrapper,
drawLockVertexesWrapper,
drawArea,
drawListArea,
drawGroupQueueVertexesWrappers,
drawSelectedElementControllersVertexes
} from './draw-wrapper';
import {
getPointTarget,
resizeElement,
Expand Down Expand Up @@ -198,7 +204,6 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
const resizeType = sharer.getSharedStorage(keyResizeType);
const actionType = sharer.getSharedStorage(keyActionType);
const groupQueue = sharer.getSharedStorage(keyGroupQueue);

const triggerCursor = (target: PointTarget) => {
const cursor: string | null = target.type;
if (inBusyMode === null) {
Expand Down Expand Up @@ -288,7 +293,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
}

if (target.type === 'over-element' && target?.elements?.length === 1) {
sharer.setSharedStorage(keyHoverElement, target.elements[0]);
// sharer.setSharedStorage(keyHoverElement, target.elements[0]);
updateHoverElement(target.elements[0]);
viewer.drawFrame();
return;
Expand All @@ -304,7 +309,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
pointStart: (e: PointWatcherEvent) => {
prevPoint = e.point;

updateHoverElement(null);
// updateHoverElement(null);
const groupQueue = sharer.getSharedStorage(keyGroupQueue);

if (groupQueue?.length > 0) {
Expand All @@ -317,7 +322,12 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
})
) {
const target = getPointTarget(e.point, pointTargetBaseOptions());
updateHoverElement(null);
if (target?.elements?.length === 1 && target.elements[0]?.operations?.lock === true) {
return;
} else {
updateHoverElement(null);
}

if (target.type === 'over-element' && target?.elements?.length === 1) {
updateSelectedElementList([target.elements[0]], { triggerEvent: true });
sharer.setSharedStorage(keyActionType, 'drag');
Expand Down Expand Up @@ -346,6 +356,11 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
areaSize: listAreaSize,
groupQueue: []
});
if (target?.elements?.length === 1 && target.elements[0]?.operations?.lock === true) {
return;
} else {
updateHoverElement(null);
}

if (target.type === 'list-area') {
sharer.setSharedStorage(keyActionType, 'drag-list');
Expand Down Expand Up @@ -382,7 +397,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core

if (actionType === 'drag') {
inBusyMode = 'drag';
if (data && elems?.length === 1 && start && end) {
if (data && elems?.length === 1 && start && end && elems[0]?.operations?.lock !== true) {
const { moveX, moveY } = calcMoveInGroup(start, end, groupQueue);
elems[0].x += moveX / scale;
elems[0].y += moveY / scale;
Expand All @@ -395,7 +410,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
const moveX = (end.x - start.x) / scale;
const moveY = (end.y - start.y) / scale;
elems.forEach((elem: Element<ElementType>) => {
if (elem) {
if (elem && elem?.operations?.lock !== true) {
elem.x += moveX;
elem.y += moveY;
}
Expand Down Expand Up @@ -540,6 +555,12 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core

doubleClick(e: PointWatcherEvent) {
const target = getPointTarget(e.point, pointTargetBaseOptions());
sharer.setSharedStorage(keySelectedElementController, null);
sharer.setSharedStorage(keySelectedElementList, []);

if (target.elements.length === 1 && target.elements[0]?.operations?.lock === true) {
return;
}

if (target.elements.length === 1 && target.elements[0]?.type === 'group') {
const pushResult = pushGroupQueue(target.elements[0] as Element<'group'>);
Expand Down Expand Up @@ -567,7 +588,7 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
const viewSizeInfo = { width, height, contextHeight, contextWidth, devicePixelRatio };
const selectedElements = sharedStore[keySelectedElementList];
const elem = selectedElements[0];
const hoverElement: ElementSize = sharedStore[keyHoverElement] as ElementSize;
const hoverElement: Element = sharedStore[keyHoverElement] as Element;
const hoverElementVertexes: ViewRectVertexes | null = sharedStore[keyHoverElementVertexes];
const actionType: ActionType = sharedStore[keyActionType] as ActionType;
const areaStart: Point | null = sharedStore[keyAreaStart];
Expand All @@ -585,21 +606,45 @@ export const MiddlewareSelector: BoardMiddleware<DeepSelectorSharedStorage, Core
})
: null;

const isLock: boolean = !!hoverElement?.operations?.lock;

if (groupQueue?.length > 0) {
// in group
drawGroupQueueVertexesWrappers(helperContext, groupQueueVertexesList, drawBaseOpts);
if (hoverElement && actionType !== 'drag') {
drawHoverVertexesWrapper(helperContext, hoverElementVertexes, drawBaseOpts);
if (isLock) {
drawLockVertexesWrapper(helperContext, hoverElementVertexes, {
...drawBaseOpts,
controller: calcElementSizeController(hoverElement, {
groupQueue,
controllerSize: 10,
viewScaleInfo
})
});
} else {
drawHoverVertexesWrapper(helperContext, hoverElementVertexes, drawBaseOpts);
}
}
if (elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
if (!isLock && elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
drawSelectedElementControllersVertexes(helperContext, selectedElementController, { ...drawBaseOpts });
}
} else {
// in root
if (hoverElement && actionType !== 'drag') {
drawHoverVertexesWrapper(helperContext, hoverElementVertexes, drawBaseOpts);
if (isLock) {
drawLockVertexesWrapper(helperContext, hoverElementVertexes, {
...drawBaseOpts,
controller: calcElementSizeController(hoverElement, {
groupQueue,
controllerSize: 10,
viewScaleInfo
})
});
} else {
drawHoverVertexesWrapper(helperContext, hoverElementVertexes, drawBaseOpts);
}
}
if (elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
if (!isLock && elem && (['select', 'drag', 'resize'] as ActionType[]).includes(actionType)) {
drawSelectedElementControllersVertexes(helperContext, selectedElementController, { ...drawBaseOpts });
} else if (actionType === 'area' && areaStart && areaEnd) {
drawArea(helperContext, { start: areaStart, end: areaEnd });
Expand Down
9 changes: 7 additions & 2 deletions packages/core/src/middleware/selector/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,11 @@ export function getSelectedListArea(
const startY = Math.min(start.y, end.y);
const endY = Math.max(start.y, end.y);

data.elements.forEach((elem, idx) => {
for (let idx = 0; idx < data.elements.length; idx++) {
const elem = data.elements[idx];
if (elem?.operations?.lock === true) {
continue;
}
const elemSize = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);

const center = calcElementCenter(elemSize);
Expand All @@ -862,7 +866,8 @@ export function getSelectedListArea(
}
}
}
});
}

return { indexes, uuids, elements };
}

Expand Down
21 changes: 18 additions & 3 deletions packages/idraw/src/idraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import {
moveElementPosition,
getElementPositionFromList,
calcElementListSize,
filterCompactData
filterCompactData,
calcViewCenterContent
} from '@idraw/util';
import { defaultSettings } from './config';
import { exportImageFileBlobURL } from './file';
Expand All @@ -41,8 +42,8 @@ export class iDraw {

constructor(mount: HTMLDivElement, options: IDrawOptions) {
const opts = { ...defaultSettings, ...options };
const { width, height, devicePixelRatio } = opts;
const core = new Core<IDrawEvent>(mount, { width, height, devicePixelRatio });
const { width, height, devicePixelRatio, createCustomContext2D } = opts;
const core = new Core<IDrawEvent>(mount, { width, height, devicePixelRatio, createCustomContext2D });
this.#core = core;
this.#opts = opts;
this.#init();
Expand Down Expand Up @@ -139,6 +140,15 @@ export class iDraw {
core.refresh();
}

centerContent(opts?: { data?: Data }) {
const data = opts?.data || this.#core.getData();
const { viewSizeInfo } = this.getViewInfo();
if (data) {
const result = calcViewCenterContent(data, { viewSizeInfo });
this.setViewScale(result);
}
}

resize(opts: Partial<ViewSizeInfo>) {
this.#core.resize(opts);
}
Expand Down Expand Up @@ -263,4 +273,9 @@ export class iDraw {
loadItemMap: this.#core.getLoadItemMap()
});
}

destroy() {
const core = this.#core;
core.destroy();
}
}
3 changes: 2 additions & 1 deletion packages/idraw/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ export {
deleteElementInListByPosition,
deleteElementInList,
deepResizeGroupElement,
deepCloneElement
deepCloneElement,
calcViewCenterContent
} from '@idraw/util';
export { iDraw } from './idraw';
export type { IDrawEvent, IDrawEventKeys } from './event';
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class Loader extends EventEmitter<LoaderEventMap> implements RendererLoad

#emitError(item: LoadItem) {
const assetId = getAssetIdFromElement(item.element);
const storageItem = this.#storageLoadItemMap[assetId];
const storageItem = this.#storageLoadItemMap?.[assetId];
if (storageItem) {
if (storageItem.startTime < item.startTime) {
this.#storageLoadItemMap[assetId] = item;
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/lib/context2d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface ViewContext2D {

// extend API
$getContext(): CanvasRenderingContext2D;
$setContext(ctx: CanvasRenderingContext2D): void;
$setFont(opts: { fontSize: number; fontFamily?: string; fontWeight?: string | number }): void;
$resize(opts: { width: number; height: number; devicePixelRatio: number }): void;
$getSize(): { width: number; height: number; devicePixelRatio: number };
Expand Down
Loading

0 comments on commit 21afa9b

Please sign in to comment.