From 711e58f31f3266ba33854de6881297e3b5e0a1ad Mon Sep 17 00:00:00 2001 From: inottn Date: Wed, 20 Sep 2023 16:53:02 +0800 Subject: [PATCH] feat: the left and top support passing function --- src/index.ts | 27 +++++++++++++++++---------- src/types.ts | 14 +++++++++++--- src/utils.ts | 26 +++++++++++++++++++++----- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/index.ts b/src/index.ts index 4d61a74..f0367bb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,18 @@ import { isNonEmptyArray, withResolvers } from '@inottn/fp-utils'; -import { binarySearch, calculateLeftOffset, mergePosition } from './utils'; +import { + binarySearch, + calculateLeftOffset, + mergePosition, + normalizeConfig, +} from './utils'; import type { Canvas, Config, ContainerConfig, - Element, + ElementConfig, ExportOptions, ImageConfig, + NormalizedConfig, Options, Radius, TextConfig, @@ -51,19 +57,20 @@ export class MiniPoster { }); } - async draw(data: Element | Element[]) { + async draw(data: ElementConfig | ElementConfig[]) { if (Array.isArray(data)) { for (const item of data) { await this.draw(item); } } else { - if (data.type === 'container') await this.renderContainer(data); - if (data.type === 'image') await this.renderImage(data); - if (data.type === 'text') await this.renderText(data); + if (data.type === 'container') + await this.renderContainer(normalizeConfig(data)); + if (data.type === 'image') await this.renderImage(normalizeConfig(data)); + if (data.type === 'text') await this.renderText(normalizeConfig(data)); } } - async renderContainer(data: ContainerConfig) { + async renderContainer(data: NormalizedConfig) { const { context } = this; const { left, @@ -103,7 +110,7 @@ export class MiniPoster { } } - async renderImage(data: ImageConfig) { + async renderImage(data: NormalizedConfig) { const { context } = this; const { src, backgroundColor, borderRadius = 0, objectFit = 'fill' } = data; const [img, loadPromise] = this.images.get(src); @@ -146,7 +153,7 @@ export class MiniPoster { context.restore(); } - async renderText(data: TextConfig) { + async renderText(data: NormalizedConfig) { const { context } = this; const { id, @@ -283,7 +290,7 @@ export class MiniPoster { context.restore(); } - loadAssets(data: Element[]) { + loadAssets(data: ElementConfig[]) { data.forEach((item) => { const { type } = item; diff --git a/src/types.ts b/src/types.ts index 911e36d..628c359 100644 --- a/src/types.ts +++ b/src/types.ts @@ -30,16 +30,21 @@ export type Radius = | [number, number, number] | [number, number, number, number]; -export type Element = ContainerConfig | ImageConfig | TextConfig; +export type ElementConfig = ContainerConfig | ImageConfig | TextConfig; export type Config = { backgroundColor?: string; borderRadius?: Radius; overflow?: 'visible' | 'hidden'; - children?: Element[]; + children?: ElementConfig[]; }; export type PositionConfig = { + left: number | (() => number); + top: number | (() => number); +}; + +type NormalizedPositionConfig = { left: number; top: number; }; @@ -55,13 +60,16 @@ export type TextDecoration = 'none' | 'line-through'; export type ObjectFit = 'fill' | 'contain' | 'cover'; +export type NormalizedConfig = Omit & + NormalizedPositionConfig; + export type ContainerConfig = PositionConfig & SizeConfig & { type: 'container'; backgroundColor?: string; borderRadius?: Radius; overflow?: 'visible' | 'hidden'; - children?: Element[]; + children?: ElementConfig[]; }; export type ImageConfig = PositionConfig & diff --git a/src/utils.ts b/src/utils.ts index 68ebd48..05a59e2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,10 @@ -import { isUndefined } from '@inottn/fp-utils'; -import { PositionConfig, TextAlign } from './types'; +import { isFunction, isUndefined } from '@inottn/fp-utils'; +import { + ElementConfig, + NormalizedConfig, + PositionConfig, + TextAlign, +} from './types'; type BinarySearchValidate = (index: number) => boolean; @@ -50,13 +55,24 @@ export const calculateLeftOffset = function ({ export const mergePosition = function ( value1: T, - value2?: PositionConfig, + value2?: NormalizedConfig, ): T { if (isUndefined(value2)) return value1; + const left = isFunction(value1.left) ? value1.left() : value1.left; + const top = isFunction(value1.top) ? value1.top() : value1.top; + return { ...value1, - left: value1.left + value2.left, - top: value1.top + value2.top, + left: value2.left + left, + top: value2.top + top, }; }; + +export const normalizeConfig = function (config: T) { + const normalizedConfig = { ...config }; + if (isFunction(config.left)) normalizedConfig.left = config.left(); + if (isFunction(config.top)) normalizedConfig.top = config.top(); + + return normalizedConfig as NormalizedConfig; +};