μ§λλ₯Ό λ λλ§νλ μΉ μ ν리μΌμ΄μ μμ λ§μ°μ€ μ΄λ²€νΈλ₯Ό νμ©ν΄ μμ°μ€λ¬μ΄ λλκ·Έ μ΄λκ³Ό μ€ μΈ/μ€ μμμ ꡬννλ κ²μ΄ λͺ©νμμ΅λλ€.
μ¬μ©μ κ²½ν(UX)μ λμ΄κΈ° μν΄ λ€μν λ§μ°μ€ λμμ μ ννκ³ μμ°μ€λ½κ² μ²λ¦¬νλ λ° μ€μ μ λμλλ°,
μλλ ꡬν κ³Όμ μμμ μλμ λ¬Έμ ν΄κ²° λ°©μμ μ 리ν λ΄μ©μ λλ€.
μ§λμ μΊλ²μ€λ₯Ό μ°λνλ κ³Όμ μ λν ν¬μ€ν μ μ¬κΈ° μμ νμΈν μ μμ΅λλ€!!!!
μ²μμλ mousedown
, mousemove
, mouseup
μ΄λ²€νΈλ₯Ό μ¬μ©ν΄ λλκ·Έλ₯Ό ꡬννμ΅λλ€. λλκ·Έ μμ μ μμΉλ₯Ό μ μ₯νκ³ , mousemove
μμ μ’νλ₯Ό μ
λ°μ΄νΈνλλ‘ νμ΅λλ€.
const handleMouseDown = (e: React.MouseEvent) => {
const rect = canvasRef.current?.getBoundingClientRect();
setDragStartPos({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
});
};
const handleMouseMove = (e: React.MouseEvent) => {
if (!dragStartTime) return;
const timeElapsed = Date.now() - dragStartTime;
if (timeElapsed > 300 && !isDragging) setIsDragging(true);
if (isDragging) {
// λλκ·Έμ λ°λ₯Έ μ§λ μ΄λ μ²λ¦¬
}
};
μ€ μΈ/μ€ μμμ wheel
μ΄λ²€νΈλ₯Ό νμ©νμ΅λλ€. μ΄λ²€νΈμμ deltaY
κ°μ μ½μ΄ μ€μ μ‘°μ νμ΅λλ€.
const handleWheel = (e: React.WheelEvent) => {
const zoomChange = e.deltaY < 0 ? 1 : -1;
map.setZoom(map.getZoom() + zoomChange);
redrawCanvas();
};
λλκ·Έμ μ§μ° λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μκ° κΈ°λ° μ‘°κ±΄μ μΆκ°νμ΅λλ€. ν΄λ¦ν μ§ 0.3μ΄ μ΄μ κ²½κ³Ό ν isDragging
μνλ₯Ό true
λ‘ μ€μ ν΄ λλκ·Έλ‘ κ°μ£Όνμ΅λλ€.
const handleMouseDown = (e: React.MouseEvent) => {
setDragStartTime(Date.now());
setDragStartPos({ x: e.clientX, y: e.clientY });
};
const handleMouseMove = (e: React.MouseEvent) => {
if (!dragStartTime) return;
const timeElapsed = Date.now() - dragStartTime;
if (timeElapsed > 300 && !isDragging) setIsDragging(true);
if (isDragging) {
// λλκ·Έ μ΄λ μ²λ¦¬
map.panBy(new naver.maps.Point(dragDeltaX, dragDeltaY));
}
};
μ€ μΈ/μ€ μμμ μ€μ¬ μ’ν λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ ν μ΄λ²€νΈ λ°μ μμΉλ₯Ό κΈ°μ€μΌλ‘ μ€μ¬μ μ¬κ³μ°νμ΅λλ€.
const handleWheel = (e: React.WheelEvent) => {
const { offsetX, offsetY } = e.nativeEvent;
// ν λ°©ν₯μ λ°λ₯Έ μ€ λ³κ²½
const zoomChange = e.deltaY < 0 ? 1 : -1;
const zoom = map.getZoom() + zoomChange;
// μ΄λ²€νΈ μ’νλ₯Ό μ€μ¬μΌλ‘ 보μ
const latLng = projection.fromOffsetToCoord(new naver.maps.Point(offsetX, offsetY));
map.setCenter(latLng);
map.setZoom(zoom);
redrawCanvas();
};
μΊλ²μ€ μμμ λλκ·Έ λμμ κ°μ§ν΄ μ§λλ₯Ό μ΄λμν€κ±°λ, νΉμ λμμ ꡬννλ €κ³ ν λ λ€μκ³Ό κ°μ λ¬Έμ κ° λ°μνμ΅λλ€
λλκΉ
μ κ°μ§νκΈ° μν΄ isDragging
μνλ₯Ό λμ
νμ΅λλ€.
const [isDragging, setIsDragging] = useState(false);
// λ§μ°μ€ νΈλ€λ¬
const handleMouseDown = () => {
setTimeout(() => setIsDragging(true), 300); // 0.3μ΄ λμ ν΄λ¦μ μ μ§νλ©΄ λλκΉ
μνλ‘ μ ν
};
const handleMouseUp = () => setIsDragging(false);
// μ€νμΌ λ³κ²½
useEffect(() => {
canvasRef.current.style.pointerEvents = isDragging ? 'none' : 'auto';
}, [isDragging]);
λ¬Έμ μ :
isDragging
μνκ° λ³κ²½λλλΌλ μ΄λ―Έ μμλ λ§μ°μ€ λλκ·Έ λμμ μ¦μ μν₯μ λ°μ§ λͺ»ν¨.Reactμ μν κ΄λ¦¬ λΉλκΈ°μ±μ νΌνκΈ° μν΄ useRef
λ₯Ό μ¬μ©νμ¬ isDragging
μνλ₯Ό κ΄λ¦¬νκ³ , DOM μ‘°μμ μ§μ μ²λ¦¬νλ λ°©μμΌλ‘ λ³κ²½νμ΅λλ€.
const isDraggingRef = useRef(false);
const handleMouseDown = () => {
isDraggingRef.current = true;
canvasRef.current.style.pointerEvents = 'none';
};
const handleMouseUp = () => {
isDraggingRef.current = false;
canvasRef.current.style.pointerEvents = 'auto';
};
λ¬Έμ μ :
isDraggingRef
λ₯Ό νμ©ν΄λ λλκ·Έκ° μλλλ‘ κ°μ§λμ§ μλ κ²½μ°κ° λ°μ.λλκ·Έ λ¬Έμ λ₯Ό λ°λλ‘ μ κ·Όνμ¬, κΈ°λ³Έμ μΌλ‘ μΊλ²μ€μ pointer-events
λ₯Ό 'none'
μΌλ‘ μ€μ νκ³ ν΄λ¦ μ 'auto'
λ‘ λ³κ²½νλ λ°©μμ μλνμ΅λλ€.
canvasRef.current.style.pointerEvents = 'none';
const handleClick = () => {
canvasRef.current.style.pointerEvents = 'auto';
};
λ¬Έμ μ :
λ€μ΄λ² μ§λ APIμ κΈ°λ³Έ UI μμκ° λλκ·Έ μ΄λ²€νΈλ₯Ό λ°©ν΄νλ λ¬Έμ λ₯Ό λ°κ²¬νμ΅λλ€.
μ΄ μμλ€μ div
νκ·Έ λ΄λΆμ μλ span
, a
, img
λ‘ κ΅¬μ±λμ΄ μμΌλ©°, ν΄λμ€λͺ
μ΄λ IDκ° μμ΄μ μ ννκΈ° μ΄λ €μ μ΅λλ€.
CSSλ₯Ό ν΅ν΄ κ°μ λ‘ λλκΉ μ λ§μμ΅λλ€.
span, a, img {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
λ¬Έμ μ :
μμ μλλ€μ λ°νμΌλ‘ κ°μ₯ μμ μ μ΄κ³ ν¨μ¨μ μΈ λ°©μμ λμΆνμ΅λλ€.
pointer-events
λ₯Ό React μνμ λΆλ¦¬νμ¬ μ§μ DOM μ‘°μμΌλ‘ κ΄λ¦¬.user-select: none
)λ‘ λ체.μ΅μ’ μ μΌλ‘ μλ μ½λλ‘ λ§μ°μ€ μ΄λ²€νΈλ₯Ό ꡬννμ΅λλ€. μ¬λ¬ μλλ₯Ό ν΅ν΄ μμ°μ€λ¬μ΄ UXλ₯Ό μ 곡νλ λ° μ±κ³΅νμ΅λλ€.
const handleMouseDown = (e: React.MouseEvent) => {
setDragStartTime(Date.now());
const rect = canvasRef.current!.getBoundingClientRect();
setDragStartPos({
x: e.clientX - rect.left,
y: e.clientY - rect.top,
});
};
const handleMouseMove = (e: React.MouseEvent) => {
if (!dragStartTime) return;
const timeElapsed = Date.now() - dragStartTime;
if (timeElapsed > 300 && !isDragging) setIsDragging(true);
if (isDragging) {
const rect = canvasRef.current!.getBoundingClientRect();
const dragEndPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };
// μ§λ μ΄λ μ²λ¦¬
const deltaX = dragStartPos.x - dragEndPos.x;
const deltaY = dragStartPos.y - dragEndPos.y;
map.panBy(new naver.maps.Point(deltaX, deltaY));
}
};
const handleWheel = (e: React.WheelEvent) => {
const zoomChange = e.deltaY < 0 ? 1 : -1;
map.setZoom(map.getZoom() + zoomChange);
redrawCanvas();
};
μλλ μ€(λ§μ°μ€ ν )κ³Ό λλκ·Έλ₯Ό ꡬννμ λμ λͺ¨μ΅μ
λλ€!
(gif μΊ‘μ² κ³Όμ μμ μ‘°κΈ.... λλ¦¬κ² μΊ‘μ²λ μ μν΄ λΆνλ립λλ€.....γ
γ
)
(λ§μ½ μ΄λ―Έμ§κ° λ©μΆ°μλ€λ©΄, μ΄λ―Έμ§μμ μ€λ₯Έμͺ½ λ§μ°μ€ ν΄λ¦ ν μ νμμ μ΄λ―Έμ§ μ΄κΈ°λ‘ λ€μ΄κ°μ£ΌμΈμ... 벨λ‘κ·Έκ° gifλ₯Ό μ§μνμ§ μλκ°λ΄μ....)