Skip to content

Commit

Permalink
Merge pull request #231 from idrawjs/dev-v0.4
Browse files Browse the repository at this point in the history
feat: optimize render of image and svg, controller of selector
  • Loading branch information
chenshenhai authored Nov 18, 2023
2 parents 4e030ee + fa9af28 commit 2000672
Show file tree
Hide file tree
Showing 18 changed files with 186 additions and 67 deletions.
4 changes: 4 additions & 0 deletions packages/board/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ export class Board<T extends BoardExtendEvent = BoardExtendEvent> {
return this._sharer;
}

getViewer() {
return this._viewer;
}

setData(data: Data): { viewSizeInfo: ViewSizeInfo } {
const sharer = this._sharer;
this._sharer.setActiveStorage('data', data);
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export class Core {

scale(opts: { scale: number; point: PointSize }) {
this._board.scale(opts);
const viewer = this._board.getViewer();
viewer.drawFrame();
}

resize(newViewSize: Partial<ViewSizeInfo>) {
Expand Down
10 changes: 7 additions & 3 deletions packages/core/src/middleware/scaler/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { PointSize, BoardMiddleware, ViewScaleInfo, ViewSizeInfo } from '@idraw/types';
import type { BoardMiddleware, CoreEvent } from '@idraw/types';
import { formatNumber } from '@idraw/util';

export const MiddlewareScaler: BoardMiddleware = (opts) => {
export const MiddlewareScaler: BoardMiddleware<Record<string, any>, CoreEvent> = (opts) => {
const key = 'SCALE';
const { viewer, sharer } = opts;
const { viewer, sharer, eventHub } = opts;

return {
mode: key,
isDefault: true,
Expand All @@ -18,6 +20,8 @@ export const MiddlewareScaler: BoardMiddleware = (opts) => {
const { moveX, moveY } = viewer.scale({ scale: newScaleNum, point });
viewer.scroll({ moveX, moveY });
viewer.drawFrame();
const scaleNum = formatNumber(scale);
eventHub.trigger('scale', { scale: scaleNum });
}
};
};
8 changes: 4 additions & 4 deletions packages/core/src/middleware/selector/draw-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ export function drawSelectedElementControllersVertexes(
const ctrlOpts = { ...wrapperOpts, borderWidth: resizeControllerBorderWidth, background: '#FFFFFF' };

drawVertexes(ctx, calcViewVertexes(elementWrapper, opts), wrapperOpts);
drawVertexes(ctx, calcViewVertexes(left.vertexes, opts), ctrlOpts);
drawVertexes(ctx, calcViewVertexes(right.vertexes, opts), ctrlOpts);
drawVertexes(ctx, calcViewVertexes(top.vertexes, opts), ctrlOpts);
drawVertexes(ctx, calcViewVertexes(bottom.vertexes, opts), ctrlOpts);
// drawVertexes(ctx, calcViewVertexes(left.vertexes, opts), ctrlOpts);
// drawVertexes(ctx, calcViewVertexes(right.vertexes, opts), ctrlOpts);
// drawVertexes(ctx, calcViewVertexes(top.vertexes, opts), ctrlOpts);
// drawVertexes(ctx, calcViewVertexes(bottom.vertexes, opts), ctrlOpts);
drawVertexes(ctx, calcViewVertexes(topLeft.vertexes, opts), ctrlOpts);
drawVertexes(ctx, calcViewVertexes(topRight.vertexes, opts), ctrlOpts);
drawVertexes(ctx, calcViewVertexes(bottomLeft.vertexes, opts), ctrlOpts);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ViewContext2D, Element, ElementType, ElementSize, ViewScaleInfo, ViewSizeInfo, TransformAction } from '@idraw/types';
import { istype, isColorStr, generateSVGPath, rotateElement, is, getDefaultElementDetailConfig } from '@idraw/util';
import { istype, isColorStr, generateSVGPath, rotateElement, is, getDefaultElementDetailConfig, calcViewBoxSize } from '@idraw/util';
import { createColorStyle } from './color';

const defaultElemConfig = getDefaultElementDetailConfig();
Expand Down Expand Up @@ -87,43 +87,18 @@ function drawBoxBackground(
viewElem: Element<ElementType>,
opts: { pattern?: string | CanvasPattern | null; viewScaleInfo: ViewScaleInfo; viewSizeInfo: ViewSizeInfo }
): void {
const { pattern, viewScaleInfo } = opts;
const { scale } = viewScaleInfo;
const { pattern, viewScaleInfo, viewSizeInfo } = opts;
let transform: TransformAction[] = [];
let { borderRadius, boxSizing = defaultElemConfig.boxSizing, borderWidth } = viewElem.detail;
let { borderRadius, borderWidth } = viewElem.detail;
if (typeof borderWidth !== 'number') {
// TODO: If borderWidth is an array, borderRadius will not take effect and will become 0.
borderRadius = 0;
}
if (viewElem.detail.background || pattern) {
let { x, y, w, h } = viewElem;
let radiusList: [number, number, number, number] = [0, 0, 0, 0];
if (typeof borderRadius === 'number') {
const br = borderRadius * scale;
radiusList = [br, br, br, br];
} else if (Array.isArray(borderRadius) && borderRadius?.length === 4) {
radiusList = [borderRadius[0] * scale, borderRadius[1] * scale, borderRadius[2] * scale, borderRadius[3] * scale];
}
let bw: number = 0;
if (typeof borderWidth === 'number') {
bw = (borderWidth || 1) * scale;
}
if (boxSizing === 'border-box') {
x = viewElem.x + bw / 2;
y = viewElem.y + bw / 2;
w = viewElem.w - bw;
h = viewElem.h - bw;
} else if (boxSizing === 'content-box') {
x = viewElem.x - bw / 2;
y = viewElem.y - bw / 2;
w = viewElem.w + bw;
h = viewElem.h + bw;
} else {
x = viewElem.x;
y = viewElem.y;
w = viewElem.w;
h = viewElem.h;
}
const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
viewScaleInfo,
viewSizeInfo
});

// r = Math.min(r, w / 2, h / 2);
// if (w < r * 2 || h < r * 2) {
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/src/draw/circle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement } from '@idraw/util';
import { createColorStyle } from './color';
import { drawBoxShadow } from './base';
import { drawBoxShadow } from './box';

export function drawCircle(ctx: ViewContext2D, elem: Element<'circle'>, opts: RendererDrawElementOptions) {
const { detail, angle } = elem;
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/src/draw/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { drawImage } from './image';
import { drawText } from './text';
import { drawSVG } from './svg';
import { drawHTML } from './html';
import { drawBox } from './base';
import { drawBox } from './box';
import { drawPath } from './path';

export function drawElement(ctx: ViewContext2D, elem: Element<ElementType>, opts: RendererDrawElementOptions) {
Expand Down
7 changes: 5 additions & 2 deletions packages/renderer/src/draw/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/
import { rotateElement } from '@idraw/util';

export function drawHTML(ctx: ViewContext2D, elem: Element<'html'>, opts: RendererDrawElementOptions) {
const content = opts.loader.getContent(elem.uuid);
const content = opts.loader.getContent(elem);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
if (!content) {
opts.loader.load(elem as Element<'html'>);
opts.loader.load(elem as Element<'html'>, opts.elementAssets || {});
}
if (elem.type === 'html' && content) {
const { opacity } = elem.detail;
ctx.globalAlpha = opacity ? opacity : 1;
ctx.drawImage(content, x, y, w, h);
ctx.globalAlpha = 1;
}
});
}
52 changes: 45 additions & 7 deletions packages/renderer/src/draw/image.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,54 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement } from '@idraw/util';
import { rotateElement, calcViewBoxSize } from '@idraw/util';
import { drawBox, drawBoxShadow } from './box';

export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, opts: RendererDrawElementOptions) {
const content = opts.loader.getContent(elem);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);

const viewElem = { ...elem, ...{ x, y, w, h, angle } };
rotateElement(ctx, { x, y, w, h, angle }, () => {
if (!content) {
opts.loader.load(elem as Element<'image'>, opts.elementAssets || {});
}
if (elem.type === 'image' && content) {
ctx.drawImage(content, x, y, w, h);
}
drawBoxShadow(ctx, viewElem, {
viewScaleInfo,
viewSizeInfo,
renderContent: () => {
drawBox(ctx, viewElem, {
originElem: elem,
calcElemSize: { x, y, w, h, angle },
viewScaleInfo,
viewSizeInfo,
renderContent: () => {
if (!content) {
opts.loader.load(elem as Element<'image'>, opts.elementAssets || {});
}
if (elem.type === 'image' && content) {
const { opacity } = elem.detail;
ctx.globalAlpha = opacity ? opacity : 1;
const { x, y, w, h, radiusList } = calcViewBoxSize(viewElem, {
viewScaleInfo,
viewSizeInfo
});

ctx.save();

ctx.beginPath();
ctx.moveTo(x + radiusList[0], y);
ctx.arcTo(x + w, y, x + w, y + h, radiusList[1]);
ctx.arcTo(x + w, y + h, x, y + h, radiusList[2]);
ctx.arcTo(x, y + h, x, y, radiusList[3]);
ctx.arcTo(x, y, x + w, y, radiusList[0]);
ctx.closePath();
ctx.fill();
ctx.clip();
ctx.drawImage(content, x, y, w, h);
ctx.globalAlpha = 1;

ctx.restore();
}
}
});
}
});
});
}
2 changes: 1 addition & 1 deletion packages/renderer/src/draw/path.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement, generateSVGPath } from '@idraw/util';
import { drawBox, drawBoxShadow } from './base';
import { drawBox, drawBoxShadow } from './box';

export function drawPath(ctx: ViewContext2D, elem: Element<'path'>, opts: RendererDrawElementOptions) {
const { detail } = elem;
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer/src/draw/rect.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement } from '@idraw/util';
import { drawBox, drawBoxShadow } from './base';
import { drawBox, drawBoxShadow } from './box';

export function drawRect(ctx: ViewContext2D, elem: Element<'rect'>, opts: RendererDrawElementOptions) {
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
Expand Down
5 changes: 4 additions & 1 deletion packages/renderer/src/draw/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/
import { rotateElement } from '@idraw/util';

export function drawSVG(ctx: ViewContext2D, elem: Element<'svg'>, opts: RendererDrawElementOptions) {
const content = opts.loader.getContent(elem.uuid);
const content = opts.loader.getContent(elem);
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
rotateElement(ctx, { x, y, w, h, angle }, () => {
if (!content) {
opts.loader.load(elem as Element<'svg'>, opts.elementAssets || {});
}
if (elem.type === 'svg' && content) {
const { opacity } = elem.detail;
ctx.globalAlpha = opacity ? opacity : 1;
ctx.drawImage(content, x, y, w, h);
ctx.globalAlpha = 1;
}
});
}
2 changes: 1 addition & 1 deletion packages/renderer/src/draw/text.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement } from '@idraw/util';
import { is, isColorStr, getDefaultElementDetailConfig } from '@idraw/util';
import { drawBox } from './base';
import { drawBox } from './box';

const detailConfig = getDefaultElementDetailConfig();

Expand Down
4 changes: 4 additions & 0 deletions packages/types/src/lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ export interface CoreEventSelect {
export interface CoreEventChange {
data: Data;
}
export interface CoreEventScale {
scale: number;
}

export type CoreEvent = {
cursor: CoreEventCursor;
select: CoreEventSelect;
change: CoreEventChange;
scale: CoreEventScale;
};
8 changes: 8 additions & 0 deletions packages/types/src/lib/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ export interface ViewCalculator {
}

export type ViewRectVertexes = [PointSize, PointSize, PointSize, PointSize];

export interface ViewBoxSize {
x: number;
y: number;
w: number;
h: number;
radiusList: [number, number, number, number];
}
3 changes: 2 additions & 1 deletion packages/util/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { delay, compose, throttle } from './lib/time';
export { downloadImageFromCanvas, parseFileToBase64, pickFile } from './lib/file';
export { downloadImageFromCanvas, parseFileToBase64, pickFile, parseFileToText } from './lib/file';
export { toColorHexStr, toColorHexNum, isColorStr, colorNameToHex, colorToCSS, colorToLinearGradientCSS, mergeHexColorAlpha } from './lib/color';
export { createUUID, isAssetId, createAssetId } from './lib/uuid';
export { deepClone, sortDataAsserts } from './lib/data';
Expand Down Expand Up @@ -59,3 +59,4 @@ export { compressImage } from './lib/image';
export { formatNumber } from './lib/number';
export { matrixToAngle, matrixToRadian } from './lib/matrix';
export { getDefaultElementDetailConfig } from './lib/config';
export { calcViewBoxSize } from './lib/view-box';
39 changes: 27 additions & 12 deletions packages/util/src/lib/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,55 +58,70 @@ export function calcElementSizeController(
const bottomRightCenter = vertexes[2];
const bottomLeftCenter = vertexes[3];

const topSize = createControllerElementSizeFromCenter(topCenter, { size: ctrlSize, angle: totalAngle });
const rightSize = createControllerElementSizeFromCenter(rightCenter, { size: ctrlSize, angle: totalAngle });
const bottomSize = createControllerElementSizeFromCenter(bottomCenter, { size: ctrlSize, angle: totalAngle });
const leftSize = createControllerElementSizeFromCenter(leftCenter, { size: ctrlSize, angle: totalAngle });
// const topSize = createControllerElementSizeFromCenter(topCenter, { size: ctrlSize, angle: totalAngle });
// const rightSize = createControllerElementSizeFromCenter(rightCenter, { size: ctrlSize, angle: totalAngle });
// const bottomSize = createControllerElementSizeFromCenter(bottomCenter, { size: ctrlSize, angle: totalAngle });
// const leftSize = createControllerElementSizeFromCenter(leftCenter, { size: ctrlSize, angle: totalAngle });

const topLeftSize = createControllerElementSizeFromCenter(topLeftCenter, { size: ctrlSize, angle: totalAngle });
const topRightSize = createControllerElementSizeFromCenter(topRightCenter, { size: ctrlSize, angle: totalAngle });
const bottomLeftSize = createControllerElementSizeFromCenter(bottomLeftCenter, { size: ctrlSize, angle: totalAngle });
const bottomRightSize = createControllerElementSizeFromCenter(bottomRightCenter, { size: ctrlSize, angle: totalAngle });

const topLeftVertexes = calcElementVertexes(topLeftSize);
const topRightVertexes = calcElementVertexes(topRightSize);
const bottomLeftVertexes = calcElementVertexes(bottomLeftSize);
const bottomRightVertexes = calcElementVertexes(bottomRightSize);

const topVertexes: ViewRectVertexes = [topLeftVertexes[1], topRightVertexes[0], topRightVertexes[3], topLeftVertexes[2]];
const rightVertexes: ViewRectVertexes = [topRightVertexes[3], topRightVertexes[2], bottomRightVertexes[1], bottomRightVertexes[0]];
const bottomVertexes: ViewRectVertexes = [bottomLeftVertexes[1], bottomRightVertexes[0], bottomRightVertexes[3], bottomLeftVertexes[2]];
const leftVertexes: ViewRectVertexes = [topLeftVertexes[3], topLeftVertexes[2], bottomLeftVertexes[1], bottomLeftVertexes[0]];
// const topVertexes = calcElementVertexes(topSize);
// const rightVertexes = calcElementVertexes(rightSize);
// const bottomVertexes = calcElementVertexes(bottomSize);
// const leftVertexes = calcElementVertexes(leftSize);

const sizeController: ElementSizeController = {
elementWrapper: vertexes,
left: {
type: 'left',
vertexes: calcElementVertexes(leftSize),
vertexes: leftVertexes,
center: leftCenter
},
right: {
type: 'right',
vertexes: calcElementVertexes(rightSize),
vertexes: rightVertexes,
center: rightCenter
},
top: {
type: 'top',
vertexes: calcElementVertexes(topSize),
vertexes: topVertexes,
center: topCenter
},
bottom: {
type: 'bottom',
vertexes: calcElementVertexes(bottomSize),
vertexes: bottomVertexes,
center: bottomCenter
},
topLeft: {
type: 'top-left',
vertexes: calcElementVertexes(topLeftSize),
vertexes: topLeftVertexes,
center: topLeftCenter
},
topRight: {
type: 'top-right',
vertexes: calcElementVertexes(topRightSize),
vertexes: topRightVertexes,
center: topRightCenter
},
bottomLeft: {
type: 'bottom-left',
vertexes: calcElementVertexes(bottomLeftSize),
vertexes: bottomLeftVertexes,
center: bottomLeftCenter
},
bottomRight: {
type: 'bottom-right',
vertexes: calcElementVertexes(bottomRightSize),
vertexes: bottomRightVertexes,
center: bottomRightCenter
}
};
Expand Down
Loading

0 comments on commit 2000672

Please sign in to comment.