Files
label-designer/src/components/CanvasLabelImage.tsx
2026-06-14 03:59:45 +08:00

127 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect, useMemo } from 'react';
import { TemplateElement } from '../types';
import { ContentResolveMode } from '../utils';
import { renderLabelToDataUrl } from '../labelRenderer';
interface CanvasLabelImageProps {
widthMm: number;
heightMm: number;
elements: TemplateElement[];
rowData: any;
rowIndex: number;
showBorder?: boolean;
transparentBackground?: boolean;
variableDefaults?: Record<string, string> | null;
/** design=设计预览空变量显示占位output=排版/打印(空值隐藏图形元素) */
mode?: ContentResolveMode;
referenceBackground?: string;
referenceBackgroundOpacity?: number;
referenceBackgroundFit?: 'contain' | 'cover' | 'fill';
/** 渲染倍率,设计画布应传 MM_TO_PX * zoom 与显示尺寸 1:1 对齐 */
renderScale?: number;
}
export const CanvasLabelImage: React.FC<CanvasLabelImageProps> = ({
widthMm,
heightMm,
elements,
rowData,
rowIndex,
showBorder = false,
transparentBackground = false,
variableDefaults = null,
mode = 'design' as ContentResolveMode,
referenceBackground,
referenceBackgroundOpacity,
referenceBackgroundFit,
renderScale = 16,
}) => {
const [dataUrl, setDataUrl] = useState<string>('');
const [initialLoading, setInitialLoading] = useState<boolean>(true);
const elementsKey = useMemo(() => JSON.stringify(elements), [elements]);
const rowDataKey = useMemo(() => JSON.stringify(rowData), [rowData]);
const variableDefaultsKey = useMemo(
() => JSON.stringify(variableDefaults),
[variableDefaults]
);
useEffect(() => {
let active = true;
renderLabelToDataUrl({
widthMm,
heightMm,
elements,
rowData,
rowIndex,
showBorder,
transparentBackground,
variableDefaults,
mode,
scale: renderScale,
referenceBackground,
referenceBackgroundOpacity,
referenceBackgroundFit,
})
.then((url) => {
if (!active) return;
const img = new Image();
img.onload = () => {
if (active) {
setDataUrl(url);
setInitialLoading(false);
}
};
img.onerror = () => {
if (active) setInitialLoading(false);
};
img.src = url;
})
.catch((err) => {
console.error('Label graphics rendering error:', err);
if (active) setInitialLoading(false);
});
return () => {
active = false;
};
}, [
widthMm,
heightMm,
elementsKey,
rowDataKey,
variableDefaultsKey,
rowIndex,
showBorder,
transparentBackground,
mode,
renderScale,
referenceBackground,
referenceBackgroundOpacity,
referenceBackgroundFit,
]);
if (initialLoading && !dataUrl) {
return (
<div
className="flex items-center justify-center animate-pulse text-gray-400 font-medium text-[10px] bg-transparent"
style={{ width: '100%', height: '100%', minHeight: '30px' }}
>
<span></span>
</div>
);
}
return (
<img
src={dataUrl}
alt="Label Preview"
className="block w-full h-full pointer-events-none select-none"
style={{
imageRendering: 'auto',
}}
/>
);
};