mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 10:23:41 +00:00
fix: Add memoization to PatternCanvas expensive computations
Extract inline calculations to useMemo hooks to prevent unnecessary recalculations on every render. Memoized displayPattern selection and pattern dimensions calculation improve performance with large patterns. Fixes #34 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
89bc55b822
commit
65275c0557
1 changed files with 52 additions and 56 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { useRef } from "react";
|
import { useRef, useMemo } from "react";
|
||||||
import { useShallow } from "zustand/react/shallow";
|
import { useShallow } from "zustand/react/shallow";
|
||||||
import {
|
import {
|
||||||
useMachineStore,
|
useMachineStore,
|
||||||
|
|
@ -109,6 +109,26 @@ export function PatternCanvas() {
|
||||||
? "text-tertiary-600 dark:text-tertiary-400"
|
? "text-tertiary-600 dark:text-tertiary-400"
|
||||||
: "text-gray-600 dark:text-gray-400";
|
: "text-gray-600 dark:text-gray-400";
|
||||||
|
|
||||||
|
// Memoize the display pattern to avoid recalculation
|
||||||
|
const displayPattern = useMemo(
|
||||||
|
() => uploadedPesData || pesData,
|
||||||
|
[uploadedPesData, pesData],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Memoize pattern dimensions calculation
|
||||||
|
const patternDimensions = useMemo(() => {
|
||||||
|
if (!displayPattern) return null;
|
||||||
|
const width = (
|
||||||
|
(displayPattern.bounds.maxX - displayPattern.bounds.minX) /
|
||||||
|
10
|
||||||
|
).toFixed(1);
|
||||||
|
const height = (
|
||||||
|
(displayPattern.bounds.maxY - displayPattern.bounds.minY) /
|
||||||
|
10
|
||||||
|
).toFixed(1);
|
||||||
|
return `${width} × ${height} mm`;
|
||||||
|
}, [displayPattern]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={`p-0 gap-0 lg:h-full flex flex-col border-l-4 ${borderColor}`}
|
className={`p-0 gap-0 lg:h-full flex flex-col border-l-4 ${borderColor}`}
|
||||||
|
|
@ -120,25 +140,7 @@ export function PatternCanvas() {
|
||||||
<CardTitle className="text-sm">Pattern Preview</CardTitle>
|
<CardTitle className="text-sm">Pattern Preview</CardTitle>
|
||||||
{hasPattern ? (
|
{hasPattern ? (
|
||||||
<CardDescription className="text-xs">
|
<CardDescription className="text-xs">
|
||||||
{(() => {
|
{patternDimensions}
|
||||||
const displayPattern = uploadedPesData || pesData;
|
|
||||||
return displayPattern ? (
|
|
||||||
<>
|
|
||||||
{(
|
|
||||||
(displayPattern.bounds.maxX -
|
|
||||||
displayPattern.bounds.minX) /
|
|
||||||
10
|
|
||||||
).toFixed(1)}{" "}
|
|
||||||
×{" "}
|
|
||||||
{(
|
|
||||||
(displayPattern.bounds.maxY -
|
|
||||||
displayPattern.bounds.minY) /
|
|
||||||
10
|
|
||||||
).toFixed(1)}{" "}
|
|
||||||
mm
|
|
||||||
</>
|
|
||||||
) : null;
|
|
||||||
})()}
|
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
) : (
|
) : (
|
||||||
<CardDescription className="text-xs">
|
<CardDescription className="text-xs">
|
||||||
|
|
@ -182,11 +184,11 @@ export function PatternCanvas() {
|
||||||
>
|
>
|
||||||
{/* Background layer: grid, origin, hoop */}
|
{/* Background layer: grid, origin, hoop */}
|
||||||
<Layer>
|
<Layer>
|
||||||
{hasPattern && (
|
{displayPattern && (
|
||||||
<>
|
<>
|
||||||
<Grid
|
<Grid
|
||||||
gridSize={100}
|
gridSize={100}
|
||||||
bounds={(uploadedPesData || pesData)!.bounds}
|
bounds={displayPattern.bounds}
|
||||||
machineInfo={machineInfo}
|
machineInfo={machineInfo}
|
||||||
/>
|
/>
|
||||||
<Origin />
|
<Origin />
|
||||||
|
|
@ -241,42 +243,36 @@ export function PatternCanvas() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Pattern info overlays */}
|
{/* Pattern info overlays */}
|
||||||
{hasPattern &&
|
{displayPattern && (
|
||||||
(() => {
|
<>
|
||||||
const displayPattern = uploadedPesData || pesData;
|
<ThreadLegend colors={displayPattern.uniqueColors} />
|
||||||
return (
|
|
||||||
displayPattern && (
|
|
||||||
<>
|
|
||||||
<ThreadLegend colors={displayPattern.uniqueColors} />
|
|
||||||
|
|
||||||
<PatternPositionIndicator
|
<PatternPositionIndicator
|
||||||
offset={
|
offset={
|
||||||
isUploading || patternUploaded || uploadedPesData
|
isUploading || patternUploaded || uploadedPesData
|
||||||
? initialUploadedPatternOffset
|
? initialUploadedPatternOffset
|
||||||
: localPatternOffset
|
: localPatternOffset
|
||||||
}
|
}
|
||||||
rotation={localPatternRotation}
|
rotation={localPatternRotation}
|
||||||
isLocked={patternUploaded || !!uploadedPesData}
|
isLocked={patternUploaded || !!uploadedPesData}
|
||||||
isUploading={isUploading}
|
isUploading={isUploading}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ZoomControls
|
<ZoomControls
|
||||||
scale={stageScale}
|
scale={stageScale}
|
||||||
onZoomIn={handleZoomIn}
|
onZoomIn={handleZoomIn}
|
||||||
onZoomOut={handleZoomOut}
|
onZoomOut={handleZoomOut}
|
||||||
onZoomReset={handleZoomReset}
|
onZoomReset={handleZoomReset}
|
||||||
onCenterPattern={handleCenterPattern}
|
onCenterPattern={handleCenterPattern}
|
||||||
canCenterPattern={
|
canCenterPattern={
|
||||||
!!pesData &&
|
!!pesData &&
|
||||||
!patternUploaded &&
|
!patternUploaded &&
|
||||||
!isUploading &&
|
!isUploading &&
|
||||||
!uploadedPesData
|
!uploadedPesData
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)}
|
||||||
);
|
|
||||||
})()}
|
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue