Fix crop range preview zoom and history saving
This commit is contained in:
+25
-16
@@ -65,6 +65,11 @@ const HISTORY_STORAGE_KEY = "bead-pattern-history";
|
||||
const HISTORY_DB_NAME = "pixel-bead-pattern-history";
|
||||
const HISTORY_STORE_NAME = "patterns";
|
||||
|
||||
function createHistoryId() {
|
||||
if (typeof globalThis.crypto?.randomUUID === "function") return globalThis.crypto.randomUUID();
|
||||
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
||||
}
|
||||
|
||||
function openHistoryDatabase() {
|
||||
return new Promise<IDBDatabase>((resolve, reject) => {
|
||||
const request = indexedDB.open(HISTORY_DB_NAME, 1);
|
||||
@@ -483,10 +488,12 @@ function drawFittedImage(
|
||||
}
|
||||
drawWidth *= cropZoom;
|
||||
drawHeight *= cropZoom;
|
||||
const overflowX = Math.max(0, (drawWidth - width) / 2);
|
||||
const overflowY = Math.max(0, (drawHeight - height) / 2);
|
||||
const drawX = (width - drawWidth) / 2 + cropX * overflowX;
|
||||
const drawY = (height - drawHeight) / 2 + cropY * overflowY;
|
||||
// Allow an object at the source-image edge to be dragged into the crop
|
||||
// center. The exposed area intentionally becomes transparent/no-bead.
|
||||
const panRangeX = drawWidth / 2;
|
||||
const panRangeY = drawHeight / 2;
|
||||
const drawX = (width - drawWidth) / 2 + cropX * panRangeX;
|
||||
const drawY = (height - drawHeight) / 2 + cropY * panRangeY;
|
||||
ctx.drawImage(image, drawX, drawY, drawWidth, drawHeight);
|
||||
}
|
||||
|
||||
@@ -921,18 +928,20 @@ export default function Home() {
|
||||
|
||||
const savePattern = async () => {
|
||||
if (!pixels.length) return;
|
||||
const entry: SavedPattern = {
|
||||
id: crypto.randomUUID(),
|
||||
name: sourceName.replace(/\.[^.]+$/, "") || "未命名图纸",
|
||||
savedAt: new Date().toISOString(),
|
||||
width: gridWidth,
|
||||
height: gridHeight,
|
||||
colorLimit,
|
||||
codes: pixels.map((pixel) => pixel.color?.code ?? null),
|
||||
};
|
||||
try {
|
||||
const entry: SavedPattern = {
|
||||
id: createHistoryId(),
|
||||
name: sourceName.replace(/\.[^.]+$/, "") || "未命名图纸",
|
||||
savedAt: new Date().toISOString(),
|
||||
width: gridWidth,
|
||||
height: gridHeight,
|
||||
colorLimit,
|
||||
codes: pixels.map((pixel) => pixel.color?.code ?? null),
|
||||
};
|
||||
await persistHistory([entry, ...history].slice(0, HISTORY_LIMIT));
|
||||
setHistoryQuery("");
|
||||
setStatus("图纸已保存到本机历史记录");
|
||||
requestAnimationFrame(() => document.getElementById("history-title")?.scrollIntoView({ behavior: "smooth", block: "start" }));
|
||||
} catch {
|
||||
setStatus("保存历史失败,请检查浏览器是否允许本地存储或剩余空间是否充足");
|
||||
}
|
||||
@@ -1029,9 +1038,9 @@ export default function Home() {
|
||||
<div className="pattern-toolbar">
|
||||
<div><p className="section-kicker">02 / 图纸预览</p><h2>点击格子,筛选颜色</h2></div>
|
||||
<div className="zoom-control" aria-label="图纸缩放">
|
||||
<button onClick={() => setZoom((z) => Math.max(8, z - 2))} aria-label="缩小">−</button>
|
||||
<input aria-label="缩放比例" type="range" min="8" max="42" value={zoom} onChange={(e) => setZoom(Number(e.target.value))} />
|
||||
<button onClick={() => setZoom((z) => Math.min(42, z + 2))} aria-label="放大">+</button>
|
||||
<button onClick={() => setZoom((z) => Math.max(3, z - 1))} aria-label="缩小">−</button>
|
||||
<input aria-label="缩放比例" type="range" min="3" max="42" step="1" value={zoom} onChange={(e) => setZoom(Number(e.target.value))} />
|
||||
<button onClick={() => setZoom((z) => Math.min(42, z + 1))} aria-label="放大">+</button>
|
||||
<output>{zoom}px</output>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user