feat: Improve canvas resizing and animation handling

- EditorCanvas:
  - 컨테이너 크기 측정 로직을 ResizeObserver를 사용하여 개선했습니다.
  - 초기 크기 설정 및 크기 변경 감지 기능을 추가했습니다.
  - 컨테이너의 width, height 스타일을 '100%'로 변경하여 부모 요소에 맞게 조절되도록 했습니다.
- ImageDistortion:
  - isPlaying prop을 제거하고 애니메이션을 항상 실행하도록 변경했습니다.
  - useAnimationFrame의 실행 조건을 항상 true로 설정하여 애니메이션 루프가 안정적으로 동작하도록 했습니다.
- package.json:
  - 버전 정보를 1.2.1에서 1.2.6으로 업데이트했습니다.
This commit is contained in:
BaekRyang 2025-11-28 16:37:20 +09:00
parent 6b6c8d8fd0
commit 031230bc36
9 changed files with 56 additions and 32 deletions

2
dist/index.d.mts vendored
View File

@ -205,8 +205,6 @@ interface ImageDistortionProps {
vertexShaderPath?: string; vertexShaderPath?: string;
/** 프래그먼트 셰이더 경로 (선택사항) */ /** 프래그먼트 셰이더 경로 (선택사항) */
fragmentShaderPath?: string; fragmentShaderPath?: string;
/** 애니메이션 재생 여부 */
isPlaying?: boolean;
/** 컨테이너 스타일 */ /** 컨테이너 스타일 */
style?: React$1.CSSProperties; style?: React$1.CSSProperties;
/** 컨테이너 클래스명 */ /** 컨테이너 클래스명 */

2
dist/index.d.ts vendored
View File

@ -205,8 +205,6 @@ interface ImageDistortionProps {
vertexShaderPath?: string; vertexShaderPath?: string;
/** 프래그먼트 셰이더 경로 (선택사항) */ /** 프래그먼트 셰이더 경로 (선택사항) */
fragmentShaderPath?: string; fragmentShaderPath?: string;
/** 애니메이션 재생 여부 */
isPlaying?: boolean;
/** 컨테이너 스타일 */ /** 컨테이너 스타일 */
style?: React$1.CSSProperties; style?: React$1.CSSProperties;
/** 컨테이너 클래스명 */ /** 컨테이너 클래스명 */

18
dist/index.js vendored
View File

@ -836,7 +836,6 @@ var ImageDistortion = ({
areas, areas,
vertexShaderPath, vertexShaderPath,
fragmentShaderPath, fragmentShaderPath,
isPlaying = true,
style, style,
className, className,
mouseInteraction mouseInteraction
@ -990,7 +989,7 @@ var ImageDistortion = ({
return updatedAreas; return updatedAreas;
}); });
}, [isReady, mouseInteraction, mouseInteractionHook]); }, [isReady, mouseInteraction, mouseInteractionHook]);
useAnimationFrame(animationCallback, isPlaying || mouseInteraction?.enabled || false); useAnimationFrame(animationCallback, true);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div", "div",
{ {
@ -1341,10 +1340,19 @@ var EditorCanvas = ({
} }
}), [customStyle]); }), [customStyle]);
(0, import_react6.useEffect)(() => { (0, import_react6.useEffect)(() => {
if (!containerRef.current) return;
const updateSize = () => {
if (!containerRef.current) return; if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect(); const rect = containerRef.current.getBoundingClientRect();
setCanvasSize({ width: rect.width, height: rect.height }); setCanvasSize({ width: rect.width, height: rect.height });
}, [width, height]); };
updateSize();
const resizeObserver = new ResizeObserver(updateSize);
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, []);
const selectedArea = areas.find((a) => a.id === selectedAreaId); const selectedArea = areas.find((a) => a.id === selectedAreaId);
const isPointInPolygon2 = (0, import_react6.useCallback)((point, polygon) => { const isPointInPolygon2 = (0, import_react6.useCallback)((point, polygon) => {
let inside = false; let inside = false;
@ -1530,8 +1538,8 @@ var EditorCanvas = ({
ref: containerRef, ref: containerRef,
className: "editor-canvas", className: "editor-canvas",
style: { style: {
width, width: "100%",
height, height: "100%",
position: "relative", position: "relative",
cursor: showEditor ? getCursorStyle() : "default", cursor: showEditor ? getCursorStyle() : "default",
pointerEvents: showEditor ? "auto" : "none", pointerEvents: showEditor ? "auto" : "none",

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

18
dist/index.mjs vendored
View File

@ -776,7 +776,6 @@ var ImageDistortion = ({
areas, areas,
vertexShaderPath, vertexShaderPath,
fragmentShaderPath, fragmentShaderPath,
isPlaying = true,
style, style,
className, className,
mouseInteraction mouseInteraction
@ -930,7 +929,7 @@ var ImageDistortion = ({
return updatedAreas; return updatedAreas;
}); });
}, [isReady, mouseInteraction, mouseInteractionHook]); }, [isReady, mouseInteraction, mouseInteractionHook]);
useAnimationFrame(animationCallback, isPlaying || mouseInteraction?.enabled || false); useAnimationFrame(animationCallback, true);
return /* @__PURE__ */ jsx( return /* @__PURE__ */ jsx(
"div", "div",
{ {
@ -1281,10 +1280,19 @@ var EditorCanvas = ({
} }
}), [customStyle]); }), [customStyle]);
useEffect4(() => { useEffect4(() => {
if (!containerRef.current) return;
const updateSize = () => {
if (!containerRef.current) return; if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect(); const rect = containerRef.current.getBoundingClientRect();
setCanvasSize({ width: rect.width, height: rect.height }); setCanvasSize({ width: rect.width, height: rect.height });
}, [width, height]); };
updateSize();
const resizeObserver = new ResizeObserver(updateSize);
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, []);
const selectedArea = areas.find((a) => a.id === selectedAreaId); const selectedArea = areas.find((a) => a.id === selectedAreaId);
const isPointInPolygon2 = useCallback5((point, polygon) => { const isPointInPolygon2 = useCallback5((point, polygon) => {
let inside = false; let inside = false;
@ -1470,8 +1478,8 @@ var EditorCanvas = ({
ref: containerRef, ref: containerRef,
className: "editor-canvas", className: "editor-canvas",
style: { style: {
width, width: "100%",
height, height: "100%",
position: "relative", position: "relative",
cursor: showEditor ? getCursorStyle() : "default", cursor: showEditor ? getCursorStyle() : "default",
pointerEvents: showEditor ? "auto" : "none", pointerEvents: showEditor ? "auto" : "none",

2
dist/index.mjs.map vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "@baekryang/responsive-image-canvas", "name": "@baekryang/responsive-image-canvas",
"version": "1.2.1", "version": "1.2.6",
"publishConfig": { "publishConfig": {
"registry": "https://git.bnovalab.com/api/packages/baekryang/npm/" "registry": "https://git.bnovalab.com/api/packages/baekryang/npm/"
}, },

View File

@ -21,8 +21,6 @@ export interface ImageDistortionProps {
vertexShaderPath?: string; vertexShaderPath?: string;
/** 프래그먼트 셰이더 경로 (선택사항) */ /** 프래그먼트 셰이더 경로 (선택사항) */
fragmentShaderPath?: string; fragmentShaderPath?: string;
/** 애니메이션 재생 여부 */
isPlaying?: boolean;
/** 컨테이너 스타일 */ /** 컨테이너 스타일 */
style?: React.CSSProperties; style?: React.CSSProperties;
/** 컨테이너 클래스명 */ /** 컨테이너 클래스명 */
@ -40,7 +38,6 @@ export const ImageDistortion: React.FC<ImageDistortionProps> = ({
areas, areas,
vertexShaderPath, vertexShaderPath,
fragmentShaderPath, fragmentShaderPath,
isPlaying = true,
style, style,
className, className,
mouseInteraction, mouseInteraction,
@ -243,8 +240,8 @@ export const ImageDistortion: React.FC<ImageDistortionProps> = ({
}); });
}, [isReady, mouseInteraction, mouseInteractionHook]); }, [isReady, mouseInteraction, mouseInteractionHook]);
// 애니메이션은 항상 실행 (마우스 인터랙션 포함) // 애니메이션 루프 실행
useAnimationFrame(animationCallback, isPlaying || mouseInteraction?.enabled || false); useAnimationFrame(animationCallback, true);
return ( return (
<div <div

View File

@ -62,12 +62,27 @@ export const EditorCanvas: React.FC<EditorCanvasProps> = ({
}, },
}), [customStyle]); }), [customStyle]);
// 컨테이너 크기 측정 // 컨테이너 크기 측정 (ResizeObserver 사용)
useEffect(() => { useEffect(() => {
if (!containerRef.current) return; if (!containerRef.current) return;
const updateSize = () => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect(); const rect = containerRef.current.getBoundingClientRect();
setCanvasSize({width: rect.width, height: rect.height}); setCanvasSize({width: rect.width, height: rect.height});
}, [width, height]); };
// 초기 크기 설정
updateSize();
// ResizeObserver로 크기 변경 감지
const resizeObserver = new ResizeObserver(updateSize);
resizeObserver.observe(containerRef.current);
return () => {
resizeObserver.disconnect();
};
}, []);
// 선택된 영역 찾기 // 선택된 영역 찾기
const selectedArea = areas.find((a) => a.id === selectedAreaId); const selectedArea = areas.find((a) => a.id === selectedAreaId);
@ -330,8 +345,8 @@ export const EditorCanvas: React.FC<EditorCanvasProps> = ({
ref={containerRef} ref={containerRef}
className="editor-canvas" className="editor-canvas"
style={{ style={{
width, width: '100%',
height, height: '100%',
position: 'relative', position: 'relative',
cursor: showEditor ? getCursorStyle() : 'default', cursor: showEditor ? getCursorStyle() : 'default',
pointerEvents: showEditor ? 'auto' : 'none', pointerEvents: showEditor ? 'auto' : 'none',