Skip to content

Commit

Permalink
feat: drawing range optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
WindRunnerMax committed Sep 17, 2024
1 parent 2dc4b98 commit 643295e
Show file tree
Hide file tree
Showing 14 changed files with 100 additions and 44 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"dev": "pnpm --filter sketching-react run dev",
"dev:react": "pnpm --filter sketching-react run dev",
"build:react": "pnpm --filter sketching-react run build",
"build:workspace": "pnpm --filter '*' run build"
"build:workspace": "pnpm --filter '*' run build",
"lint:ts": "pnpm --filter '*' run lint:ts"
},
"repository": {
"type": "git",
Expand Down
3 changes: 2 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"build": "tsc -p tsconfig.build.json",
"release": "./publish.sh",
"test": "jest"
"test": "jest",
"lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
},
"keywords": [],
"author": "",
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/canvas/dom/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import { Shape } from "../utils/shape";
import { Node } from "./node";

export class ElementNode extends Node {
private readonly id: string;
/** 节点 id */
public readonly id: string;
/** Hover 状态 */
private isHovering: boolean;

constructor(private editor: Editor, state: DeltaState) {
Expand Down Expand Up @@ -56,6 +58,8 @@ export class ElementNode extends Node {
public drawingMask = (ctx: CanvasRenderingContext2D) => {
if (
this.isHovering &&
// FIX: 避免全选删除后的 Hover 绘制
this.editor.deltaSet.has(this.id) &&
!this.editor.selection.has(this.id) &&
!this.editor.state.get(EDITOR_STATE.MOUSE_DOWN)
) {
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/canvas/dom/frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ export class FrameNode extends Node {
if (latest.intersect(state.toRange())) effects.push(state.id);
});
this.editor.selection.setActiveDelta(...effects);
// 重绘拖拽过的最大区域
const zoomed = latest.zoom(RESIZE_OFS);
this.dragged = this.dragged ? this.dragged.compose(zoomed) : zoomed;
this.editor.canvas.mask.drawingEffect(this.dragged);
const prev = this.dragged || latest;
const zoomed = latest.compose(prev).zoom(RESIZE_OFS);
this.dragged = latest;
this.editor.canvas.mask.drawingEffect(zoomed);
}
};
private onMouseMoveController = throttle(this.onMouseMoveBridge, ...THE_CONFIG);
Expand Down
19 changes: 15 additions & 4 deletions packages/core/src/canvas/dom/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import type { Range } from "../../selection/modules/range";
import type { MouseEvent } from "../event/mouse";

export class Node {
protected _z: number;
/** 节点 Range */
private _range: Range;
/** 父节点引用 */
private _parent: Node | null;
/** 层级 */
protected _z: number;
/** 忽略事件触发 */
protected _ignoreEvent: boolean;
public readonly children: Node[];
/** 当前树结构的所有子节点 */
protected flatNodes: Node[] | null;
/** 当前节点的直属子节点 */
public readonly children: Node[];

// 尽可能简单地实现事件流
// 直接通过`bubble`来决定捕获/冒泡
Expand Down Expand Up @@ -114,9 +120,14 @@ export class Node {
this.clearFlatNodeOnLink();
}

// ====== Flat Node ======
/**
* 获取当前节点树的所有子节点
* @returns
*/
public getFlatNode() {
if (this.flatNodes) return this.flatNodes;
if (this.flatNodes) {
return this.flatNodes;
}
// 右子树优先后序遍历 保证事件调用的顺序
const nodes: Node[] = [];
const reverse = [...this.children].reverse();
Expand Down
34 changes: 21 additions & 13 deletions packages/core/src/canvas/dom/refer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,14 @@ export class ReferNode extends Node {
this.sortedY = Array.from(yLineMap.keys()).sort((a, b) => a - b);
};

/**
* 拖拽选区的鼠标移动事件
* @param latest 拖拽选区的最新 Range
* @description 作为 SelectNode 的子元素 Node 事件
* 基于父元素的事件调用链执行当前的事件绑定
* 避免多次对父元素的 Range 修改来保证值唯一
*/
public onMouseMoveController = (latest: Range) => {
// COMPAT: 作为`SelectNode`的子元素`Node`事件
// 基于父元素的事件调用链执行当前的事件绑定
// 避免多次对父元素的`Range`修改来保证值唯一
this.clearNodes();
if (!latest || !this.editor.canvas.root.select.isDragging) return void 0;
if (this.sortedX.length === 0 && this.sortedY.length === 0) {
Expand Down Expand Up @@ -121,12 +125,15 @@ export class ReferNode extends Node {
if (isEmptyValue(offsetX) && isEmptyValue(offsetY)) {
// 未命中参考线需要清理
this.dragged && this.editor.canvas.mask.drawingEffect(this.dragged);
this.dragged = null;
return void 0;
}
const nextSelection = latest.move(offsetX || 0, offsetY || 0).normalize();
// 参考线绘制
const composeNodeRange = (range: Range) => {
this.dragged = nextSelection.compose(this.dragged).compose(range);
const prevPaintRange = this.dragged || nextSelection;
let nextPaintRange = nextSelection.compose(prevPaintRange);
// 构建参考线节点
const createReferNode = (range: Range) => {
nextPaintRange = nextPaintRange.compose(range);
const node = new Node(range);
node.setIgnoreEvent(true);
node.drawingMask = this.drawingMaskDispatch;
Expand All @@ -143,21 +150,21 @@ export class ReferNode extends Node {
const minY = Math.min(...ys, next.start.y);
const maxY = Math.max(...ys, next.end.y);
const range = Range.from(next.start.x, minY, next.start.x, maxY);
composeNodeRange(range);
createReferNode(range);
}
if (this.isNear(offsetX, closestMidX - midX) && this.xLineMap.has(closestMidX)) {
const ys = this.xLineMap.get(closestMidX) || [-1];
const minY = Math.min(...ys, next.start.y);
const maxY = Math.max(...ys, next.end.y);
const range = Range.from(nextMid.x, minY, nextMid.x, maxY);
composeNodeRange(range);
createReferNode(range);
}
if (this.isNear(offsetX, closestMaxX - endX) && this.xLineMap.has(closestMaxX)) {
const ys = this.xLineMap.get(closestMaxX) || [-1];
const minY = Math.min(...ys, next.start.y);
const maxY = Math.max(...ys, next.end.y);
const range = Range.from(next.end.x, minY, next.end.x, maxY);
composeNodeRange(range);
createReferNode(range);
}
}
if (!isEmptyValue(offsetY)) {
Expand All @@ -167,24 +174,25 @@ export class ReferNode extends Node {
const minX = Math.min(...xs, next.start.x);
const maxX = Math.max(...xs, next.end.x);
const range = Range.from(minX, next.start.y, maxX, next.start.y);
composeNodeRange(range);
createReferNode(range);
}
if (this.isNear(offsetY, closestMidY - midY) && this.yLineMap.has(closestMidY)) {
const xs = this.yLineMap.get(closestMidY) || [-1];
const minX = Math.min(...xs, next.start.x);
const maxX = Math.max(...xs, next.end.x);
const range = Range.from(minX, nextMid.y, maxX, nextMid.y);
composeNodeRange(range);
createReferNode(range);
}
if (this.isNear(offsetY, closestMaxY - endY) && this.yLineMap.has(closestMaxY)) {
const xs = this.yLineMap.get(closestMaxY) || [-1];
const minX = Math.min(...xs, next.start.x);
const maxX = Math.max(...xs, next.end.x);
const range = Range.from(minX, next.end.y, maxX, next.end.y);
composeNodeRange(range);
createReferNode(range);
}
}
this.dragged && this.editor.canvas.mask.drawingEffect(this.dragged);
this.dragged = nextPaintRange;
nextPaintRange && this.editor.canvas.mask.drawingEffect(nextPaintRange);
return { x: offsetX || 0, y: offsetY || 0 };
};

Expand Down
12 changes: 7 additions & 5 deletions packages/core/src/canvas/dom/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,18 @@ export class SelectNode extends Node {
if (!this.landing || !selection) return void 0;
const point = Point.from(e.clientX, e.clientY);
const { x, y } = this.landing.diff(point);
// 超过阈值才认为正在触发拖拽
if (!this._isDragging && (Math.abs(x) > SELECT_BIAS || Math.abs(y) > SELECT_BIAS)) {
// 拖拽阈值
this._isDragging = true;
}
if (this._isDragging && selection) {
// 获取上次绘制的选区位置
const prev = this.dragged || selection;
const latest = selection.move(x, y);
const zoomed = latest.zoom(RESIZE_OFS);
// 重绘拖拽过的最大区域
this.dragged = this.dragged ? this.dragged.compose(zoomed) : zoomed;
this.editor.canvas.mask.drawingEffect(this.dragged);
this.dragged = latest;
// 重绘上次绘制到本次绘制的组合区域
const zoomed = latest.compose(prev).zoom(RESIZE_OFS);
this.editor.canvas.mask.drawingEffect(zoomed);
const offset = this.refer.onMouseMoveController(latest);
this.setRange(offset ? latest.move(offset.x, offset.y) : latest);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/canvas/state/insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ export class Insert {
endX: this.landing.x + x,
endY: this.landing.y + y,
}).normalize();
const prev = this.range || latest;
this.range = latest;
// 重绘拖拽过的最大区域
this.dragged = this.dragged ? this.dragged.compose(latest) : latest;
this.dragged = prev.compose(latest);
this.drawingMask();
};
private onMouseMoveController = throttle(this.onMouseMoveBasic, ...THE_CONFIG);
Expand Down Expand Up @@ -128,6 +128,7 @@ export class Insert {

public drawingMask(finish = false) {
if (this.dragged) {
// 清空当前区域内的绘制 相当于避免上次绘制的内容留存
this.engine.mask.clear(this.dragged.zoom(this.engine.devicePixelRatio));
}
if (this.range && this.delta) {
Expand Down
18 changes: 12 additions & 6 deletions packages/core/src/selection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ export class Selection {
}

public destroy() {
// Placeholder
// placeholder
}

// ====== Selection ======
public has(id: string) {
return this.active.has(id);
}
Expand All @@ -41,7 +40,6 @@ export class Selection {
return this;
}

// ====== Active ======
public getActiveDeltaIds() {
return this.active;
}
Expand All @@ -64,8 +62,14 @@ export class Selection {
this.compose();
}

/**
* 清理选区内容
* @returns
*/
public clearActiveDeltas() {
if (this.active.size === 0) return void 0;
if (this.active.size === 0) {
return void 0;
}
this.active.clear();
this.set(null);
}
Expand All @@ -76,9 +80,11 @@ export class Selection {
this.setActiveDelta(...keys);
}

// ====== Range ======
/**
* 组合当前选区节点的 Range
* @returns
*/
public compose() {
// Multiple to be combined
const active = this.active;
if (active.size === 0) {
this.set(null);
Expand Down
3 changes: 2 additions & 1 deletion packages/delta/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"build": "tsc -p tsconfig.build.json",
"release": "./publish.sh",
"test": "jest"
"test": "jest",
"lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
},
"keywords": [],
"author": "",
Expand Down
24 changes: 21 additions & 3 deletions packages/delta/src/delta-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,30 @@ export class DeltaSet {
);
}

/**
* 通过 key 获取 delta
* @param key
* @returns
*/
public get(key: string) {
// TODO: Limit Return Types With Interface Extensions
if (!this.deltas[key]) return null;
return this.deltas[key];
return this.deltas[key] || null;
}

/**
* 判断是否存在目标 key
* @param key
* @returns
*/
public has(key: string) {
return !!this.deltas[key];
}

/**
* 添加目标 Delta 到 DeltaSet
* @param delta 目标 Delta
* @param to 目标 Delta 的父 Delta Id
* @returns
*/
public add(delta: Delta, to?: string) {
this.deltas[delta.id] = delta;
delta.getDeltaSet = () => this;
Expand Down
3 changes: 2 additions & 1 deletion packages/plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"dev": "rspack serve --config ./rspack.config.js",
"build": "tsc -p tsconfig.build.json",
"release": "./publish.sh"
"release": "./publish.sh",
"lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
},
"keywords": [],
"author": "",
Expand Down
3 changes: 2 additions & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"scripts": {
"dev": "rspack serve --config ./rspack.config.js",
"build": "rspack build --config ./rspack.config.js",
"analyze": "rspack build --config ./rspack.config.js --analyze"
"analyze": "rspack build --config ./rspack.config.js --analyze",
"lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
},
"keywords": [],
"author": "",
Expand Down
3 changes: 2 additions & 1 deletion packages/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"scripts": {
"build": "tsc -p tsconfig.build.json",
"release": "./publish.sh",
"test": "jest"
"test": "jest",
"lint:ts": "../../node_modules/typescript/bin/tsc --noEmit"
},
"keywords": [],
"author": "",
Expand Down

0 comments on commit 643295e

Please sign in to comment.