diff --git a/Gemfile.lock b/Gemfile.lock index 3caae77..fd481fa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - rails-mermaid_erd (0.5.1) + rails-mermaid_erd (0.6.0) rails (>= 5.2) GEM diff --git a/RELEASE.md b/RELEASE.md index 3f943b3..701bf83 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -23,7 +23,7 @@ bundle exec rspec cd /workspace/spec/dummy RAILS_ENV=test bundle exec rails mermaid_erd cp -f /workspace/spec/dummy/mermaid_erd/index.html /workspace/docs/example.html -chromium-browser --headless --disable-gpu --no-sandbox --window-size=1200,800 --hide-scrollbars --screenshot="/workspace/docs/screen_shot.png" /workspace/spec/dummy/mermaid_erd/index.html +chromium-browser --headless --disable-gpu --no-sandbox --window-size=1280,800 --hide-scrollbars --screenshot="/workspace/docs/screen_shot.png" /workspace/spec/dummy/mermaid_erd/index.html ``` in host machine: diff --git a/docs/example.html b/docs/example.html index d7fdf19..5e02d42 100644 --- a/docs/example.html +++ b/docs/example.html @@ -277,7 +277,20 @@

{{i18n[language]["models"]["title"]}}
-
+
+
+ +
+
+
+ {{i18n[language]["controls"]["movement"]}}: + {{i18n[language]["controls"]["space_drag"]}} / {{i18n[language]["controls"]["middle_drag"]}} +
+
+ {{i18n[language]["controls"]["zoom"]}}: + {{i18n[language]["controls"]["mouse_wheel"]}} / {{i18n[language]["controls"]["pinch"]}} +
+
@@ -294,7 +307,6 @@

{{i18n[language]["models"]["title"]}}

- @@ -303,7 +315,7 @@

{{i18n[language]["models"]["title"]}} @@ -349,6 +361,14 @@

{{i18n[language]["models"]["title"]}} erd: 'ERD', code: 'Code', }, + controls: { + movement: 'Movement', + zoom: 'Zoom', + space_drag: 'Space + Mouse Drag', + middle_drag: 'Middle Click + Drag', + mouse_wheel: 'Mouse Wheel', + pinch: 'Pinch In/Out', + } }, ja: { actions: { @@ -383,6 +403,14 @@

{{i18n[language]["models"]["title"]}} erd: 'ER図', code: 'コード', }, + controls: { + movement: '移動方法', + zoom: '拡大/縮小', + space_drag: 'スペースキー + マウスドラッグ', + middle_drag: '中クリック + ドラッグ', + mouse_wheel: 'マウスホイール', + pinch: 'ピンチイン/アウト', + } } } @@ -409,6 +437,155 @@

{{i18n[language]["models"]["title"]}} const posX = Vue.ref(0) const posY = Vue.ref(0) const zoomArea = Vue.ref(null) + // Manage space key press state + const isSpacePressed = Vue.ref(false) + // Manage dragging state + const isDragging = Vue.ref(false) + let startX = 0 + let startY = 0 + // Record distance between two touch points + let lastTouchDistance = 0 + // Record mouse position + let lastMouseX = 0 + let lastMouseY = 0 + + // Calculate distance between two touch points + const getDistance = (touches) => { + return Math.hypot( + touches[0].clientX - touches[1].clientX, + touches[0].clientY - touches[1].clientY + ) + } + + // Calculate center point of two touch positions + const getTouchCenter = (touches) => { + return { + x: (touches[0].clientX + touches[1].clientX) / 2, + y: (touches[0].clientY + touches[1].clientY) / 2 + } + } + + // Handle touch start + const handleTouchStart = (e) => { + if (e.touches.length === 2) { + e.preventDefault() + lastTouchDistance = getDistance(e.touches) + } + } + + // Handle touch move (pinch in/out for zoom) + const handleTouchMove = (e) => { + if (e.touches.length === 2) { + e.preventDefault() + const preview = document.getElementById('preview') + if (!preview.contains(e.target)) { + return + } + + const newDistance = getDistance(e.touches) + const delta = (newDistance - lastTouchDistance) * 0.01 + lastTouchDistance = newDistance + + const center = getTouchCenter(e.touches) + const rect = preview.getBoundingClientRect() + const touchX = center.x - rect.left + const touchY = center.y - rect.top + + const x = touchX / scale.value - posX.value + const y = touchY / scale.value - posY.value + + const newScale = Math.min(Math.max(scale.value + delta, 0.5), 3) + if (newScale === scale.value) return + + posX.value = touchX / newScale - x + posY.value = touchY / newScale - y + scale.value = newScale + } + } + + // Handle touch end + const handleTouchEnd = (e) => { + if (e.touches.length < 2) { + lastTouchDistance = 0 + } + } + + // Handle key down (space key for drag mode toggle) + const handleKeyDown = (e) => { + if (e.code === 'Space' && !isSpacePressed.value) { + if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') { + return + } + isSpacePressed.value = true + e.preventDefault() + } + } + + // Handle key up + const handleKeyUp = (e) => { + if (e.code === 'Space') { + isSpacePressed.value = false + isDragging.value = false + } + } + + // Handle mouse down (start dragging) + const handleMouseDown = (e) => { + if (isSpacePressed.value || e.button === 1) { + isDragging.value = true + lastMouseX = e.clientX + lastMouseY = e.clientY + e.preventDefault() + } + } + + // Handle mouse move (movement while dragging) + const handleMouseMove = (e) => { + if (isDragging.value) { + const dx = (e.clientX - lastMouseX) / scale.value + const dy = (e.clientY - lastMouseY) / scale.value + posX.value += dx + posY.value += dy + lastMouseX = e.clientX + lastMouseY = e.clientY + e.preventDefault() + } + } + + // Handle mouse up (end dragging) + const handleMouseUp = (e) => { + if (e.button === 1) { + e.preventDefault() + } + isDragging.value = false + } + + // Handle mouse wheel (zoom) + const handleWheel = (e) => { + const preview = document.getElementById('preview') + if (!preview.contains(e.target)) { + return + } + + e.preventDefault() + + const rect = preview.getBoundingClientRect() + const mouseX = e.clientX - rect.left + const mouseY = e.clientY - rect.top + + // Calculate relative coordinates based on mouse position + const x = mouseX / scale.value - posX.value + const y = mouseY / scale.value - posY.value + + // Change scale + const delta = e.deltaY < 0 ? 0.1 : -0.1 + const newScale = Math.min(Math.max(scale.value + delta, 0.5), 3) + + // Calculate new position with new scale + posX.value = mouseX / newScale - x + posY.value = mouseY / newScale - y + scale.value = newScale + } const zoomStyle = Vue.computed(() => { return { @@ -660,6 +837,28 @@

{{i18n[language]["models"]["title"]}} setLanguage(window.navigator.language) restoreFromHash() reRender() + + window.addEventListener('keydown', handleKeyDown) + window.addEventListener('keyup', handleKeyUp) + window.addEventListener('mousedown', handleMouseDown) + window.addEventListener('mousemove', handleMouseMove) + window.addEventListener('mouseup', handleMouseUp) + window.addEventListener('wheel', handleWheel, { passive: false }) + window.addEventListener('touchstart', handleTouchStart, { passive: false }) + window.addEventListener('touchmove', handleTouchMove, { passive: false }) + window.addEventListener('touchend', handleTouchEnd) + }) + + Vue.onUnmounted(() => { + window.removeEventListener('keydown', handleKeyDown) + window.removeEventListener('keyup', handleKeyUp) + window.removeEventListener('mousedown', handleMouseDown) + window.removeEventListener('mousemove', handleMouseMove) + window.removeEventListener('mouseup', handleMouseUp) + window.removeEventListener('wheel', handleWheel) + window.removeEventListener('touchstart', handleTouchStart) + window.removeEventListener('touchmove', handleTouchMove) + window.removeEventListener('touchend', handleTouchEnd) }) window.addEventListener('hashchange', () => { @@ -703,7 +902,9 @@

{{i18n[language]["models"]["title"]}} moveUp, moveDown, moveLeft, - moveRight + moveRight, + isSpacePressed, + isDragging } } } diff --git a/docs/screen_shot.png b/docs/screen_shot.png index 432fc81..cd581ce 100644 Binary files a/docs/screen_shot.png and b/docs/screen_shot.png differ diff --git a/lib/rails-mermaid_erd/version.rb b/lib/rails-mermaid_erd/version.rb index 3eee736..df68779 100644 --- a/lib/rails-mermaid_erd/version.rb +++ b/lib/rails-mermaid_erd/version.rb @@ -1,3 +1,3 @@ module RailsMermaidErd - VERSION = "0.5.1" + VERSION = "0.6.0" end