65 lines
1.9 KiB
JavaScript
65 lines
1.9 KiB
JavaScript
|
|
(function () {
|
||
|
|
const EXTREME_ZOOM_MIN = 1e-4;
|
||
|
|
const EXTREME_ZOOM_MAX = 1e4;
|
||
|
|
|
||
|
|
function applyCustomZoomHandling(cy) {
|
||
|
|
let zoomFramePending = false;
|
||
|
|
|
||
|
|
if (!cy || typeof cy.zoom !== 'function') {
|
||
|
|
console.warn('🚫 유효하지 않은 Cytoscape 인스턴스입니다.');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
cy.userZoomingEnabled(false); // Cytoscape 기본 줌 비활성화
|
||
|
|
|
||
|
|
const container = cy.container();
|
||
|
|
if (!container) {
|
||
|
|
console.warn('🚫 Cytoscape container를 찾을 수 없습니다.');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
container.addEventListener(
|
||
|
|
'wheel',
|
||
|
|
(event) => {
|
||
|
|
event.preventDefault();
|
||
|
|
|
||
|
|
if (zoomFramePending) return;
|
||
|
|
zoomFramePending = true;
|
||
|
|
|
||
|
|
requestAnimationFrame(() => {
|
||
|
|
const currentZoom = cy.zoom();
|
||
|
|
|
||
|
|
const clampedDelta = Math.max(-100, Math.min(100, event.deltaY));
|
||
|
|
const zoomFactor = 1 + (clampedDelta > 0 ? -0.05 : 0.05);
|
||
|
|
const nextZoom = currentZoom * zoomFactor;
|
||
|
|
|
||
|
|
const isValid =
|
||
|
|
isFinite(nextZoom) &&
|
||
|
|
nextZoom >= EXTREME_ZOOM_MIN &&
|
||
|
|
nextZoom <= EXTREME_ZOOM_MAX;
|
||
|
|
|
||
|
|
if (isValid) {
|
||
|
|
const rect = container.getBoundingClientRect();
|
||
|
|
const renderedPosition = {
|
||
|
|
x: event.clientX - rect.left,
|
||
|
|
y: event.clientY - rect.top
|
||
|
|
};
|
||
|
|
cy.zoom({
|
||
|
|
level: nextZoom,
|
||
|
|
renderedPosition
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
console.warn("🚫 휠 줌 비정상 값 차단:", nextZoom);
|
||
|
|
}
|
||
|
|
|
||
|
|
zoomFramePending = false;
|
||
|
|
});
|
||
|
|
},
|
||
|
|
{ passive: false }
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ✅ 전역(window)으로 함수 등록
|
||
|
|
window.applyCustomZoomHandling = applyCustomZoomHandling;
|
||
|
|
})();
|
||
|
|
|