fix(canvas): 画布背景 - 降低点阵密度与亮度并优化缩放显示

This commit is contained in:
ddCat
2026-08-22 18:11:03 +08:00
parent 6b3e22f4e9
commit 5d9986f6c7
3 changed files with 21 additions and 10 deletions

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
import { canvasThemes, type CanvasBackgroundMode } from "@/lib/canvas-theme";
import { applyCanvasLiveViewport, canvasDotPx, subscribeCanvasViewportPreview } from "@/lib/canvas/canvas-live-viewport";
import { applyCanvasLiveViewport, canvasDotGridPx, canvasDotPx, subscribeCanvasViewportPreview } from "@/lib/canvas/canvas-live-viewport";
import { useThemeStore } from "@/stores/use-theme-store";
import type { ViewportTransform } from "@/types/canvas";
@@ -382,6 +382,9 @@ export function InfiniteCanvas({ containerRef, viewport, backgroundMode = "lines
"--canvas-grid-size": `${48 * viewport.k}px`,
"--canvas-grid-x": `${viewport.x % (48 * viewport.k)}px`,
"--canvas-grid-y": `${viewport.y % (48 * viewport.k)}px`,
"--canvas-dot-grid-size": `${canvasDotGridPx(viewport.k)}px`,
"--canvas-dot-grid-x": `${viewport.x % canvasDotGridPx(viewport.k)}px`,
"--canvas-dot-grid-y": `${viewport.y % canvasDotGridPx(viewport.k)}px`,
"--canvas-dot-size": canvasDotPx(viewport.k),
} as React.CSSProperties}
onPointerDown={handlePointerDown}
@@ -422,11 +425,11 @@ function CanvasGrid({ mode }: { mode: CanvasBackgroundMode }) {
data-canvas-grid-layer
className="pointer-events-none absolute"
style={{
inset: "calc(-1 * var(--canvas-grid-size))",
inset: mode === "dots" ? "calc(-1 * var(--canvas-dot-grid-size))" : "calc(-1 * var(--canvas-grid-size))",
backgroundImage,
backgroundSize: "var(--canvas-grid-size) var(--canvas-grid-size)",
transform: "translate3d(var(--canvas-grid-x), var(--canvas-grid-y), 0)",
opacity: 0.46,
backgroundSize: mode === "dots" ? "var(--canvas-dot-grid-size) var(--canvas-dot-grid-size)" : "var(--canvas-grid-size) var(--canvas-grid-size)",
transform: mode === "dots" ? "translate3d(var(--canvas-dot-grid-x), var(--canvas-dot-grid-y), 0)" : "translate3d(var(--canvas-grid-x), var(--canvas-grid-y), 0)",
opacity: mode === "dots" ? 0.34 : 0.46,
willChange: "transform",
}}
/>

View File

@@ -5,7 +5,7 @@ export const canvasThemes = {
light: {
canvas: {
background: "#ffffff",
dot: "rgba(15,23,42,.30)",
dot: "rgba(15,23,42,.20)",
line: "rgba(15,23,42,.15)",
selectionFill: "rgba(17,17,17,.10)",
},
@@ -71,7 +71,7 @@ export const canvasThemes = {
dark: {
canvas: {
background: "#0b0b0b",
dot: "rgba(178,178,178,.27)",
dot: "rgba(178,178,178,.18)",
line: "rgba(178,178,178,.14)",
selectionFill: "rgba(255,255,255,.12)",
},

View File

@@ -4,15 +4,20 @@ export const CANVAS_VIEWPORT_PREVIEW_EVENT = "canvas:viewport-preview";
export const CANVAS_GRAPHICS_VIEWPORT_PREVIEW_EVENT = "canvas:graphics-viewport-preview";
export const CANVAS_SELECTION_PREVIEW_EVENT = "canvas:selection-preview";
// 空间网格点模式的点半径(像素单位)。远距(缩放 < 0.12)时用更小半径避免糊成一团。
// 同时被 <CanvasGrid>(infinite-canvas)与滚动同步(applyCanvasLiveViewport)共享,避免两处漂移。
// 空间网格点模式的点半径(像素单位)。远距时使用更小半径,避免点阵糊成一团。
export function canvasDotPx(scale: number): string {
return scale < 0.12 ? "0.8px" : "1.25px";
return scale < 0.12 ? "0.6px" : "0.8px";
}
// 点阵在缩小时不再无限压缩到屏幕像素,避免密集视觉噪声。
export function canvasDotGridPx(scale: number): number {
return Math.max(48 * scale, 32);
}
export function applyCanvasLiveViewport(container: HTMLDivElement | null, viewport: ViewportTransform, notify = true) {
if (!container) return;
const gridSize = 48 * viewport.k;
const dotGridSize = canvasDotGridPx(viewport.k);
const committedScale = Number(container.style.getPropertyValue("--canvas-committed-scale")) || viewport.k;
container.style.setProperty("--canvas-live-x", `${viewport.x}px`);
container.style.setProperty("--canvas-live-y", `${viewport.y}px`);
@@ -23,6 +28,9 @@ export function applyCanvasLiveViewport(container: HTMLDivElement | null, viewpo
container.style.setProperty("--canvas-grid-size", `${gridSize}px`);
container.style.setProperty("--canvas-grid-x", `${viewport.x % gridSize}px`);
container.style.setProperty("--canvas-grid-y", `${viewport.y % gridSize}px`);
container.style.setProperty("--canvas-dot-grid-size", `${dotGridSize}px`);
container.style.setProperty("--canvas-dot-grid-x", `${viewport.x % dotGridSize}px`);
container.style.setProperty("--canvas-dot-grid-y", `${viewport.y % dotGridSize}px`);
container.style.setProperty("--canvas-dot-size", canvasDotPx(viewport.k));
// 图形层必须逐帧跟随 DOM 世界层;浮层和滚动通知仍可按原频率节流。
container.dispatchEvent(new CustomEvent<ViewportTransform>(CANVAS_GRAPHICS_VIEWPORT_PREVIEW_EVENT, { detail: viewport }));