优化预览
This commit is contained in:
@@ -8,6 +8,8 @@ import {
|
|||||||
buildPrintablePages,
|
buildPrintablePages,
|
||||||
collectGridCutLinePositions,
|
collectGridCutLinePositions,
|
||||||
getCutLineChannel,
|
getCutLineChannel,
|
||||||
|
formatCutLineSvgDashArray,
|
||||||
|
getCutLineStrokeWidthMm,
|
||||||
loadAutoLayoutMinPageMarginMm,
|
loadAutoLayoutMinPageMarginMm,
|
||||||
saveAutoLayoutMinPageMarginMm,
|
saveAutoLayoutMinPageMarginMm,
|
||||||
type PrintableLabel,
|
type PrintableLabel,
|
||||||
@@ -578,15 +580,12 @@ export const LayoutPreview: React.FC<LayoutPreviewProps> = ({
|
|||||||
const rowGapPx = Math.max(0, paper.rowGap * previewScale);
|
const rowGapPx = Math.max(0, paper.rowGap * previewScale);
|
||||||
const labelWPx = template.width * previewScale;
|
const labelWPx = template.width * previewScale;
|
||||||
const labelHPx = template.height * previewScale;
|
const labelHPx = template.height * previewScale;
|
||||||
const cutStrokeWidth = Math.max(0.5, cutLine.width * previewScale);
|
const cutStrokeWidth = getCutLineStrokeWidthMm(cutLine) * previewScale;
|
||||||
const cutHalfStroke = cutStrokeWidth / 2;
|
const cutHalfStroke = cutStrokeWidth / 2;
|
||||||
const cutChannel = getCutLineChannel(paper.columnGap, paper.rowGap, cutLine);
|
const cutChannel = getCutLineChannel(paper.columnGap, paper.rowGap, cutLine);
|
||||||
const cutChannelXPx = cutChannel.x * previewScale;
|
const cutChannelXPx = cutChannel.x * previewScale;
|
||||||
const cutChannelYPx = cutChannel.y * previewScale;
|
const cutChannelYPx = cutChannel.y * previewScale;
|
||||||
const cutDash =
|
const cutDash = formatCutLineSvgDashArray(cutLine, previewScale);
|
||||||
cutLine.style === 'dashed'
|
|
||||||
? `${Math.max(2, cutStrokeWidth * 4)} ${Math.max(2, cutStrokeWidth * 4)}`
|
|
||||||
: undefined;
|
|
||||||
const pageCutLines = useMemo(
|
const pageCutLines = useMemo(
|
||||||
() =>
|
() =>
|
||||||
collectGridCutLinePositions(
|
collectGridCutLinePositions(
|
||||||
@@ -770,7 +769,6 @@ export const LayoutPreview: React.FC<LayoutPreviewProps> = ({
|
|||||||
strokeWidth={cutStrokeWidth}
|
strokeWidth={cutStrokeWidth}
|
||||||
strokeDasharray={cutDash}
|
strokeDasharray={cutDash}
|
||||||
strokeLinecap="butt"
|
strokeLinecap="butt"
|
||||||
shapeRendering="crispEdges"
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{pageCutLines.xs.map((x) => (
|
{pageCutLines.xs.map((x) => (
|
||||||
@@ -784,7 +782,6 @@ export const LayoutPreview: React.FC<LayoutPreviewProps> = ({
|
|||||||
strokeWidth={cutStrokeWidth}
|
strokeWidth={cutStrokeWidth}
|
||||||
strokeDasharray={cutDash}
|
strokeDasharray={cutDash}
|
||||||
strokeLinecap="butt"
|
strokeLinecap="butt"
|
||||||
shapeRendering="crispEdges"
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</svg>
|
</svg>
|
||||||
@@ -794,7 +791,7 @@ export const LayoutPreview: React.FC<LayoutPreviewProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={cellIdx}
|
key={cellIdx}
|
||||||
className="bg-white border border-dashed border-gray-200 flex items-center justify-center text-gray-300 font-mono text-[9px] box-border"
|
className="bg-white flex items-center justify-center text-gray-300 font-mono text-[9px]"
|
||||||
style={{
|
style={{
|
||||||
width: `${template.width * previewScale}px`,
|
width: `${template.width * previewScale}px`,
|
||||||
height: `${template.height * previewScale}px`,
|
height: `${template.height * previewScale}px`,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { jsPDF } from 'jspdf';
|
import { jsPDF } from 'jspdf';
|
||||||
import type { PaperConfig, LabelTemplate, CutLineConfig } from './types';
|
import type { PaperConfig, LabelTemplate, CutLineConfig } from './types';
|
||||||
import { collectGridCutLinePositions, getCutLineChannel, type PrintableLabel } from './utils';
|
import { collectGridCutLinePositions, getCutLineChannel, getCutLineDashSegmentMm, getCutLineStrokeWidthMm, type PrintableLabel } from './utils';
|
||||||
|
|
||||||
export interface PdfExportProgress {
|
export interface PdfExportProgress {
|
||||||
done: number;
|
done: number;
|
||||||
@@ -51,9 +51,9 @@ function parseColorToRgb(color: string): [number, number, number] {
|
|||||||
function setupCutLinePen(pdf: jsPDF, cutLine: CutLineConfig) {
|
function setupCutLinePen(pdf: jsPDF, cutLine: CutLineConfig) {
|
||||||
const [r, g, b] = parseColorToRgb(cutLine.color);
|
const [r, g, b] = parseColorToRgb(cutLine.color);
|
||||||
pdf.setDrawColor(r, g, b);
|
pdf.setDrawColor(r, g, b);
|
||||||
pdf.setLineWidth(cutLine.width);
|
pdf.setLineWidth(getCutLineStrokeWidthMm(cutLine));
|
||||||
if (cutLine.style === 'dashed') {
|
if (cutLine.style === 'dashed') {
|
||||||
const dash = Math.max(0.5, cutLine.width * 4);
|
const dash = getCutLineDashSegmentMm(cutLine);
|
||||||
pdf.setLineDashPattern([dash, dash], 0);
|
pdf.setLineDashPattern([dash, dash], 0);
|
||||||
} else {
|
} else {
|
||||||
pdf.setLineDashPattern([], 0);
|
pdf.setLineDashPattern([], 0);
|
||||||
@@ -71,7 +71,7 @@ function drawPageGridCutLines(
|
|||||||
) {
|
) {
|
||||||
const originX = paper.marginLeft;
|
const originX = paper.marginLeft;
|
||||||
const originY = paper.marginTop;
|
const originY = paper.marginTop;
|
||||||
const lineW = Math.max(0.02, cutLine.width);
|
const lineW = getCutLineStrokeWidthMm(cutLine);
|
||||||
const { xs, ys, gridW, gridH } = collectGridCutLinePositions(
|
const { xs, ys, gridW, gridH } = collectGridCutLinePositions(
|
||||||
originX,
|
originX,
|
||||||
originY,
|
originY,
|
||||||
|
|||||||
21
src/utils.ts
21
src/utils.ts
@@ -152,6 +152,27 @@ export const DEFAULT_CUT_LINE_CONFIG: CutLineConfig = {
|
|||||||
color: '#cccccc',
|
color: '#cccccc',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 裁切线有效线宽 (mm),预览与 PDF 共用 */
|
||||||
|
export function getCutLineStrokeWidthMm(cutLine: Pick<CutLineConfig, 'width'>): number {
|
||||||
|
return Math.max(0.02, cutLine.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 虚线单段长度 (mm),预览与 PDF 共用 */
|
||||||
|
export function getCutLineDashSegmentMm(cutLine: Pick<CutLineConfig, 'style' | 'width'>): number {
|
||||||
|
if (cutLine.style !== 'dashed') return 0;
|
||||||
|
return Math.max(0.5, cutLine.width * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 预览 SVG strokeDasharray,scale 为 mm→px 比例 */
|
||||||
|
export function formatCutLineSvgDashArray(
|
||||||
|
cutLine: Pick<CutLineConfig, 'style' | 'width'>,
|
||||||
|
scale: number
|
||||||
|
): string | undefined {
|
||||||
|
if (cutLine.style !== 'dashed') return undefined;
|
||||||
|
const seg = getCutLineDashSegmentMm(cutLine) * scale;
|
||||||
|
return `${seg} ${seg}`;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GridCutLinePositions {
|
export interface GridCutLinePositions {
|
||||||
xs: number[];
|
xs: number[];
|
||||||
ys: number[];
|
ys: number[];
|
||||||
|
|||||||
Reference in New Issue
Block a user