Skip to content

Commit

Permalink
Merge pull request #230 from idrawjs/dev-v0.4
Browse files Browse the repository at this point in the history
feat: improve image render
  • Loading branch information
chenshenhai authored Nov 12, 2023
2 parents 0d748da + 166c3e8 commit 4e030ee
Show file tree
Hide file tree
Showing 12 changed files with 268 additions and 91 deletions.
71 changes: 40 additions & 31 deletions packages/renderer/src/draw/circle.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,57 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement } from '@idraw/util';
import { createColorStyle } from './color';
import { drawBoxShadow } from './base';

export function drawCircle(ctx: ViewContext2D, elem: Element<'circle'>, opts: RendererDrawElementOptions) {
const { detail, angle } = elem;
const { background = '#000000', borderColor = '#000000', borderWidth = 0 } = detail;
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
// const { scale, offsetTop, offsetBottom, offsetLeft, offsetRight } = viewScaleInfo;
const { x, y, w, h } = calculator.elementSize({ x: elem.x, y: elem.y, w: elem.w, h: elem.h }, viewScaleInfo, viewSizeInfo);
const viewElem = { ...elem, ...{ x, y, w, h, angle } };

rotateElement(ctx, { x, y, w, h, angle }, () => {
const a = w / 2;
const b = h / 2;
const centerX = x + a;
const centerY = y + b;
drawBoxShadow(ctx, viewElem, {
viewScaleInfo,
viewSizeInfo,
renderContent: () => {
const a = w / 2;
const b = h / 2;
const centerX = x + a;
const centerY = y + b;

if (elem?.detail?.opacity !== undefined && elem?.detail?.opacity >= 0) {
ctx.globalAlpha = elem.detail.opacity;
} else {
ctx.globalAlpha = 1;
}
if (elem?.detail?.opacity !== undefined && elem?.detail?.opacity >= 0) {
ctx.globalAlpha = elem.detail.opacity;
} else {
ctx.globalAlpha = 1;
}

// draw border
if (typeof borderWidth === 'number' && borderWidth > 0) {
const ba = borderWidth / 2 + a;
const bb = borderWidth / 2 + b;
ctx.beginPath();
ctx.strokeStyle = borderColor;
ctx.lineWidth = borderWidth;
ctx.circle(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
}
// draw border
if (typeof borderWidth === 'number' && borderWidth > 0) {
const ba = borderWidth / 2 + a;
const bb = borderWidth / 2 + b;
ctx.beginPath();
ctx.strokeStyle = borderColor;
ctx.lineWidth = borderWidth;
ctx.circle(centerX, centerY, ba, bb, 0, 0, 2 * Math.PI);
ctx.closePath();
ctx.stroke();
}

// draw content
ctx.beginPath();
const fillStyle = createColorStyle(ctx, background, {
viewElementSize: { x, y, w, h },
viewScaleInfo,
opacity: ctx.globalAlpha
// draw content
ctx.beginPath();
const fillStyle = createColorStyle(ctx, background, {
viewElementSize: { x, y, w, h },
viewScaleInfo,
opacity: ctx.globalAlpha
});
ctx.fillStyle = fillStyle;
ctx.circle(centerX, centerY, a, b, 0, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1;
}
});
ctx.fillStyle = fillStyle;
ctx.circle(centerX, centerY, a, b, 0, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.globalAlpha = 1;
});
}
2 changes: 1 addition & 1 deletion packages/renderer/src/draw/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/
import { rotateElement } from '@idraw/util';

export function drawImage(ctx: ViewContext2D, elem: Element<'image'>, 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 }, () => {
Expand Down
14 changes: 6 additions & 8 deletions packages/renderer/src/draw/text.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { Element, RendererDrawElementOptions, ViewContext2D } from '@idraw/types';
import { rotateElement } from '@idraw/util';
import { is, isColorStr } from '@idraw/util';
import { is, isColorStr, getDefaultElementDetailConfig } from '@idraw/util';
import { drawBox } from './base';

const detailConfig = getDefaultElementDetailConfig();

export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: RendererDrawElementOptions) {
const { calculator, viewScaleInfo, viewSizeInfo } = opts;
const { x, y, w, h, angle } = calculator.elementSize(elem, viewScaleInfo, viewSizeInfo);
Expand All @@ -15,17 +17,13 @@ export function drawText(ctx: ViewContext2D, elem: Element<'text'>, opts: Render
viewSizeInfo,
renderContent: () => {
const detail: Element<'text'>['detail'] = {
...{
fontSize: 12,
fontFamily: 'sans-serif',
textAlign: 'center'
},
...detailConfig,
...elem.detail
};
const fontSize = detail.fontSize * viewScaleInfo.scale;
const fontSize = (detail.fontSize || detailConfig.fontSize) * viewScaleInfo.scale;
const lineHeight = detail.lineHeight ? detail.lineHeight * viewScaleInfo.scale : fontSize;

ctx.fillStyle = elem.detail.color;
ctx.fillStyle = elem.detail.color || detailConfig.color;
ctx.textBaseline = 'top';
ctx.$setFont({
fontWeight: detail.fontWeight,
Expand Down
53 changes: 37 additions & 16 deletions packages/renderer/src/loader.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import type { RendererLoader, LoaderEventMap, LoadFunc, LoadContent, LoadItem, LoadElementType, Element, ElementAssets } from '@idraw/types';
import { loadImage, loadHTML, loadSVG, EventEmitter, deepClone } from '@idraw/util';
import { loadImage, loadHTML, loadSVG, EventEmitter, createAssetId, isAssetId, createUUID } from '@idraw/util';

interface LoadItemMap {
[uuid: string]: LoadItem;
[assetId: string]: LoadItem;
}

const supportElementTypes: LoadElementType[] = ['image', 'svg', 'html'];

const getAssetIdFromElement = (element: Element<'image' | 'svg' | 'html'>) => {
let source: string | null = null;
if (element.type === 'image') {
source = (element as Element<'image'>)?.detail?.src || null;
} else if (element.type === 'svg') {
source = (element as Element<'svg'>)?.detail?.svg || null;
} else if (element.type === 'html') {
source = (element as Element<'html'>)?.detail?.html || null;
}
if (typeof source === 'string' && source) {
if (isAssetId(source)) {
return source;
}
return createAssetId(source);
}
return createAssetId(`${createUUID()}-${element.uuid}-${createUUID()}-${createUUID()}`);
};

export class Loader extends EventEmitter<LoaderEventMap> implements RendererLoader {
private _loadFuncMap: Record<LoadElementType | string, LoadFunc<LoadElementType, LoadContent>> = {};
private _currentLoadItemMap: LoadItemMap = {};
Expand Down Expand Up @@ -76,37 +94,38 @@ export class Loader extends EventEmitter<LoaderEventMap> implements RendererLoad
}

private _emitLoad(item: LoadItem) {
const uuid = item.element.uuid;
const storageItem = this._storageLoadItemMap[uuid];
const assetId = getAssetIdFromElement(item.element);
const storageItem = this._storageLoadItemMap[assetId];
if (storageItem) {
if (storageItem.startTime < item.startTime) {
this._storageLoadItemMap[uuid] = item;
this._storageLoadItemMap[assetId] = item;
this.trigger('load', { ...item, countTime: item.endTime - item.startTime });
}
} else {
this._storageLoadItemMap[uuid] = item;
this._storageLoadItemMap[assetId] = item;
this.trigger('load', { ...item, countTime: item.endTime - item.startTime });
}
}

private _emitError(item: LoadItem) {
const uuid = item.element.uuid;
const storageItem = this._storageLoadItemMap[uuid];
const assetId = getAssetIdFromElement(item.element);
const storageItem = this._storageLoadItemMap[assetId];
if (storageItem) {
if (storageItem.startTime < item.startTime) {
this._storageLoadItemMap[uuid] = item;
this._storageLoadItemMap[assetId] = item;
this.trigger('error', { ...item, countTime: item.endTime - item.startTime });
}
} else {
this._storageLoadItemMap[uuid] = item;
this._storageLoadItemMap[assetId] = item;
this.trigger('error', { ...item, countTime: item.endTime - item.startTime });
}
}

private _loadResource(element: Element<LoadElementType>, assets: ElementAssets) {
const item = this._createLoadItem(element);
const assetId = getAssetIdFromElement(element);

this._currentLoadItemMap[element.uuid] = item;
this._currentLoadItemMap[assetId] = item;
const loadFunc = this._loadFuncMap[element.type];
if (typeof loadFunc === 'function') {
item.startTime = Date.now();
Expand All @@ -128,7 +147,8 @@ export class Loader extends EventEmitter<LoaderEventMap> implements RendererLoad
}

private _isExistingErrorStorage(element: Element<LoadElementType>) {
const existItem = this._currentLoadItemMap?.[element?.uuid];
const assetId = getAssetIdFromElement(element);
const existItem = this._currentLoadItemMap?.[assetId];
if (existItem && existItem.status === 'error' && existItem.source && existItem.source === this._getLoadElementSource(element)) {
return true;
}
Expand All @@ -140,12 +160,13 @@ export class Loader extends EventEmitter<LoaderEventMap> implements RendererLoad
return;
}
if (supportElementTypes.includes(element.type)) {
const elem = deepClone(element);
this._loadResource(elem, assets);
// const elem = deepClone(element);
this._loadResource(element, assets);
}
}

getContent(uuid: string): LoadContent | null {
return this._storageLoadItemMap?.[uuid]?.content || null;
getContent(element: Element<LoadElementType>): LoadContent | null {
const assetId = getAssetIdFromElement(element);
return this._storageLoadItemMap?.[assetId]?.content || null;
}
}
5 changes: 3 additions & 2 deletions packages/types/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ElementBaseDetail } from './element';
import type { ElementBaseDetail, ElementTextDetail } from './element';

export type DefaultElementDetailConfig = Required<Omit<ElementBaseDetail, 'clipPath' | 'background'>>;
export type DefaultElementDetailConfig = Required<Omit<ElementBaseDetail, 'clipPath' | 'background'>> &
Required<Pick<ElementTextDetail, 'color' | 'textAlign' | 'verticalAlign' | 'fontSize' | 'fontFamily' | 'fontWeight' | 'lineHeight'>>;
27 changes: 13 additions & 14 deletions packages/types/src/lib/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface TransformMatrix {
}

export interface ElementAssetsItem {
type: 'svg' | 'image';
type: 'svg' | 'image' | 'html';
value: string;
}

Expand Down Expand Up @@ -79,7 +79,6 @@ export interface ElementBaseDetail {
shadowOffsetX?: number;
shadowOffsetY?: number;
shadowBlur?: number;
// color?: string;
background?: string | LinearGradientColor | RadialGradientColor;
opacity?: number;
clipPath?: ElementClipPath;
Expand All @@ -90,12 +89,12 @@ export interface ElementBaseDetail {
// // background?: string;
// }

interface ElementRectDetail extends ElementBaseDetail {}
export interface ElementRectDetail extends ElementBaseDetail {}

interface ElemenTextDetail extends ElementBaseDetail {
export interface ElementTextDetail extends ElementBaseDetail {
text: string;
color: string;
fontSize: number;
color?: string;
fontSize?: number;
lineHeight?: number;
fontWeight?: 'bold' | string | number;
fontFamily?: string;
Expand All @@ -107,32 +106,32 @@ interface ElemenTextDetail extends ElementBaseDetail {
textShadowBlur?: number;
}

interface ElementCircleDetail extends ElementBaseDetail {
export interface ElementCircleDetail extends ElementBaseDetail {
radius: number;
background?: string;
}

interface ElementHTMLDetail extends ElementBaseDetail {
export interface ElementHTMLDetail extends ElementBaseDetail {
html: string;
width?: number;
height?: number;
}

interface ElementImageDetail extends ElementBaseDetail {
export interface ElementImageDetail extends ElementBaseDetail {
src: string;
}

interface ElementSVGDetail extends ElementBaseDetail {
export interface ElementSVGDetail extends ElementBaseDetail {
svg: string;
}

interface ElementGroupDetail extends ElementBaseDetail {
export interface ElementGroupDetail extends ElementBaseDetail {
children: Element<ElementType>[];
overflow?: 'hidden';
assets?: ElementAssets;
}

interface ElementPathDetail extends ElementBaseDetail {
export interface ElementPathDetail extends ElementBaseDetail {
// path: string;
commands: SVGPathCommand[];
originX: number;
Expand All @@ -145,10 +144,10 @@ interface ElementPathDetail extends ElementBaseDetail {
strokeLineCap?: 'butt' | 'round' | 'square';
}

interface ElementDetailMap {
export interface ElementDetailMap {
rect: ElementRectDetail;
circle: ElementCircleDetail;
text: ElemenTextDetail;
text: ElementTextDetail;
image: ElementImageDetail;
html: ElementHTMLDetail;
svg: ElementSVGDetail;
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/lib/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export interface RendererEventMap {
export interface RendererLoader extends UtilEventEmitter<LoaderEventMap> {
// load(element: Element<LoadElementType>): void;
load(element: Element<LoadElementType>, assets: ElementAssets): void;
getContent(uuid: string): LoadContent | null;
getContent(element: Element<LoadElementType>): LoadContent | null;
}

export interface RendererDrawOptions {
Expand Down
7 changes: 5 additions & 2 deletions 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 } from './lib/file';
export { downloadImageFromCanvas, parseFileToBase64, pickFile } 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 @@ -34,7 +34,10 @@ export {
findElementsFromList,
updateElementInList,
getGroupQueueFromList,
getElementSize
getElementSize,
mergeElementAsset,
filterElementAsset,
isResourceElement
} from './lib/element';
export { checkRectIntersect } from './lib/rect';
export {
Expand Down
9 changes: 8 additions & 1 deletion packages/util/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ export function getDefaultElementDetailConfig(): DefaultElementDetailConfig {
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 0,
opacity: 1
opacity: 1,
color: '#000000',
textAlign: 'left',
verticalAlign: 'top',
fontSize: 16,
lineHeight: 20,
fontFamily: 'sans-serif',
fontWeight: 400
};
return config;
}
Loading

0 comments on commit 4e030ee

Please sign in to comment.