From 8c5970f8c1c7b7354359b510c74c3c6367f6bf6f Mon Sep 17 00:00:00 2001 From: cole Date: Tue, 16 Apr 2024 18:19:02 +0800 Subject: [PATCH] refactor: backmoji rendering logic --- packages/core/src/index.ts | 18 ++++++++++--- packages/react/src/index.ts | 44 +++++++++++++++++-------------- packages/vue/src/index.ts | 52 +++++++++++++++++++++++++++---------- 3 files changed, 78 insertions(+), 36 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e7e5e73..5b298de 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -8,8 +8,6 @@ export * from "./utils/shared"; export * from "./utils/math"; export interface BackmojiOptions { - width?: number; - height?: number; degree?: number; rowGap?: number; columnGap?: number; @@ -38,7 +36,9 @@ export function backmoji(canvas: Awaitable, renderer: Awaitab const _canvas = await canvas; const ctx = _canvas.getContext("2d"); assert(ctx, "Current environment does not support 2d canvas rendering"); - const { width = 300, height = 150, degree = 0, rowGap = 0, columnGap = 0 } = _options || {}; + const { degree = 0, rowGap = 0, columnGap = 0 } = _options || {}; + const width = _canvas.width; + const height = _canvas.height; let _degree = degree % 360; if (_degree < 0) { _degree = 360 + _degree; @@ -84,9 +84,21 @@ export function backmoji(canvas: Awaitable, renderer: Awaitab } } + async function setSize(width: number | undefined, height: number | undefined) { + const _canvas = await canvas; + const ratio = window.devicePixelRatio; + const w = width || _canvas.width; + const h = height || _canvas.height; + _canvas.width = w * ratio; + _canvas.height = h * ratio; + _canvas.style.width = `${w}px`; + _canvas.style.height = `${h}px`; + } + return { render, setOptions, + setSize, }; } diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 8d31fe7..86c5a51 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -1,39 +1,44 @@ -import { type BackmojiOptions, type CreateImageRendererOptions, type CreateTextRendererOptions, type Renderer, backmoji, createImageRenderer, createTextRenderer } from "backmoji"; +import type { BackmojiOptions, CreateImageRendererOptions, CreateTextRendererOptions, Renderer } from "backmoji"; +import { backmoji, createImageRenderer, createTextRenderer } from "backmoji"; import { type RefObject, useEffect, useMemo, useState } from "react"; export type BackmojiResult = ReturnType; -export function useBackmoji(renderer: Renderer | null, canvas: RefObject, options?: Omit, deps?: any[]) { - const [backmojiResult, setBackmojiResult] = useState>({}); +export function useBackmoji(canvas: RefObject | HTMLCanvasElement, renderer: Renderer | undefined, options?: BackmojiOptions, deps?: any[]) { + const [backmojiResult, setBackmojiResult] = useState({ + render: async () => {}, + setOptions: () => {}, + setSize: async () => {}, + }); useEffect(() => { - if (!renderer || !canvas.current) { + let _canvas: HTMLCanvasElement | null; + if ("current" in canvas) { + _canvas = canvas.current; + } else { + _canvas = canvas; + } + if (!_canvas || !renderer) { return; } - setBackmojiResult(backmoji(renderer, { ...options, canvas: canvas.current })); + setBackmojiResult(backmoji(_canvas, renderer, options)); return () => { - if (backmojiResult?.canvas) { - backmojiResult.canvas.remove(); - } + _canvas?.remove(); }; - }, [renderer, canvas, ...(deps || [])]); + }, [canvas, renderer, ...(deps || [])]); return backmojiResult; } -export function useImageLoader(img: HTMLImageElement | string) { - const [image, setImage] = useState(null); +export function useImageLoader(img: string) { + const [image, setImage] = useState(); useEffect(() => { - if (typeof img === "string") { - loadImage(img).then((image) => { - setImage(image); - }); - } else { - setImage(img); - } + loadImage(img).then((image) => { + setImage(image); + }); }, [img]); function loadImage(img: string) { @@ -49,12 +54,11 @@ export function useImageLoader(img: HTMLImageElement | string) { return image; } -export function useImageRenderer(img: HTMLImageElement | null, options?: CreateImageRendererOptions) { +export function useImageRenderer(img: HTMLImageElement | undefined, options?: CreateImageRendererOptions) { const renderer = useMemo(() => { if (img) { return createImageRenderer(img, options); } - return null; }, [img]); return renderer; diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 5e3e00f..acd1397 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -1,33 +1,51 @@ import { type BackmojiOptions, type CreateImageRendererOptions, type CreateTextRendererOptions, type Renderer, backmoji, createImageRenderer, createTextRenderer } from "backmoji"; -import { type ComputedRef, type MaybeRefOrGetter, computed, onMounted, ref, toValue } from "vue"; +import { type MaybeRefOrGetter, computed, onMounted, ref, toValue } from "vue"; export type BackmojiResult = ReturnType; -export function useBackmoji(renderer: MaybeRefOrGetter, canvas: MaybeRefOrGetter, options?: MaybeRefOrGetter | undefined>) { - return computed(() => { +export function useBackmoji(canvas: MaybeRefOrGetter, renderer: MaybeRefOrGetter, options?: MaybeRefOrGetter | undefined>) { + const backmojiResult = computed(() => { const _renderer = toValue(renderer); const _options = toValue(options); const _canvas = toValue(canvas); if (!_canvas || !_renderer) { return undefined; } - return backmoji(_renderer, { + return backmoji(_canvas, _renderer, { ..._options, - canvas: _canvas, }); }); -} -export function useTextRenderer(text: MaybeRefOrGetter, options?: MaybeRefOrGetter) { - return computed(() => { - const _text = toValue(text); - const _options = toValue(options); - return createTextRenderer(_text, _options); - }); + function render() { + if (backmojiResult.value) { + return backmojiResult.value.render(); + } + return Promise.resolve(); + } + + function setOptions(options: BackmojiOptions, combine?: boolean) { + if (backmojiResult.value) { + backmojiResult.value.setOptions(options, combine); + } + } + + function setSize(width: number | undefined, height: number | undefined) { + if (backmojiResult.value) { + return backmojiResult.value.setSize(width, height); + } + return Promise.resolve(); + } + + return { + render, + + setOptions, + setSize, + }; } export function useImageLoader(src: MaybeRefOrGetter) { - const img = ref(); + const img = ref(); const load = async () => { const _src = toValue(src); @@ -54,3 +72,11 @@ export function useImageRenderer(image: MaybeRefOrGetter, options?: MaybeRefOrGetter) { + return computed(() => { + const _text = toValue(text); + const _options = toValue(options); + return createTextRenderer(_text, _options); + }); +}