Last active
March 17, 2017 08:45
-
-
Save pjchender/dcaf9b0e6829b5a8fd3b76b135082c30 to your computer and use it in GitHub Desktop.
function to Zoom and Drag SVG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function reportMouseCoordinates (evt) { | |
const offsetXY = document.getElementById('offsetXY') | |
const clientXY = document.getElementById('clientXY') | |
const svgXY = document.getElementById('svgXY') | |
const svgElement = document.getElementById('svgElement') | |
offsetXY.textContent = `Offset:(${evt.offsetX}, ${evt.offsetY})` | |
clientXY.textContent = `Client(screen): (${evt.clientX}, ${evt.clientY})` | |
const screenPoint = svgElement.createSVGPoint() | |
screenPoint.x = evt.clientX | |
screenPoint.y = evt.clientY | |
let CTM = svgElement.getScreenCTM() | |
let svgPoint = screenPoint.matrixTransform(CTM.inverse()) | |
svgXY.textContent = `SVGPoint(viewbox): (${svgPoint.x.toFixed(0)}, ${svgPoint.y.toFixed(0)})` | |
} | |
let select | |
function startDrag () { | |
select = true | |
} | |
function drag (evt) { | |
if (select) { | |
const svgElement = document.getElementById('svgElement') | |
const screenPoint = svgElement.createSVGPoint() | |
let viewBox | |
let CTM | |
console.group() | |
console.log('一開始的viewBox', svgElement.getAttribute('viewBox')) | |
// 取得滑鼠當前點擊的座標 | |
let clientXY = { | |
x: evt.clientX, | |
y: evt.clientY | |
} | |
console.log('clientXY', clientXY) | |
// 轉換為滑鼠當前點擊 SVG 座標 | |
screenPoint.x = clientXY.x | |
screenPoint.y = clientXY.y | |
console.log('screePoint', screenPoint) | |
CTM = svgElement.getScreenCTM() | |
let svgPoint = screenPoint.matrixTransform(CTM.inverse()) | |
console.log('svgPoint', svgPoint) | |
// 取得滑鼠後來的座標 | |
let clientXYAfterDrag = { | |
x: evt.clientX + evt.movementX, | |
y: evt.clientY + evt.movementY | |
} | |
console.log('clientXYAfterDrag', clientXYAfterDrag) | |
// 轉換為滑鼠後來的 SVG 座標 | |
screenPoint.x = clientXYAfterDrag.x | |
screenPoint.y = clientXYAfterDrag.y | |
let svgPointAfterDrag = screenPoint.matrixTransform(CTM.inverse()) | |
console.log('svgPointAfterDrag', svgPointAfterDrag) | |
// 計算位移量 | |
viewBox = svgElement.getAttribute('viewBox').split(' ').map(n => parseFloat(n)) | |
let viewBoxAfterTranslate = { | |
x: viewBox[0] + (svgPoint.x - svgPointAfterDrag.x), | |
y: viewBox[1] + (svgPoint.y - svgPointAfterDrag.y) | |
} | |
svgElement.setAttribute('viewBox', `${viewBoxAfterTranslate.x} ${viewBoxAfterTranslate.y} ${viewBox[2]} ${viewBox[3]}`) | |
console.log('最後的 viewBox', svgElement.getAttribute('viewBox')) | |
console.groupEnd() | |
} | |
} | |
function endDrag () { | |
select = false | |
} | |
function zoom (evt) { | |
console.groupCollapsed() | |
const svgElement = document.getElementById('svgElement') | |
let viewBox | |
let r = 0.95 // ratio to scale | |
let CTM | |
if (evt.deltaY > 0) { | |
r = 0.9 | |
} else if (evt.deltaY < 0) { | |
r = 1.1 | |
} else { | |
r = 1 | |
} | |
console.log('r', r) | |
// 取得滑鼠滾動螢幕座標 | |
let clientXY = { | |
x: evt.clientX, | |
y: evt.clientY | |
} | |
// 轉換為滑鼠滾動 SVG 座標 | |
const screenPoint = svgElement.createSVGPoint() | |
screenPoint.x = clientXY.x // evt.clientX | |
screenPoint.y = clientXY.y // evt.clientY | |
console.log('screePoint', screenPoint) | |
CTM = svgElement.getScreenCTM() | |
let svgPoint = screenPoint.matrixTransform(CTM.inverse()) | |
console.log('svgPoint', svgPoint) | |
// 將滑鼠滾動 SVG 座標移動中心點,並放大 | |
viewBox = svgElement.getAttribute('viewBox').split(' ').map(n => parseFloat(n)) | |
console.log('原始viweBox', viewBox) | |
svgElement.setAttribute('viewBox', `${viewBox[0] + svgPoint.x} ${viewBox[1] + svgPoint.y} ${viewBox[2] * r} ${viewBox[3] * r}`) | |
// 將 SVG 座標從中心點移回原本的 ClientXY 的 SVG 位移 | |
CTM = svgElement.getScreenCTM() | |
let svgPointAfterWheel = screenPoint.matrixTransform(CTM.inverse()) | |
console.log('後來的 svgPointAfterWheel', svgPointAfterWheel) | |
viewBox = svgElement.getAttribute('viewBox').split(' ').map(n => parseFloat(n)) | |
console.log('置中與放大的 viweBox', viewBox) | |
let viewBoxAfterTranslate = { | |
x: viewBox[0] + (svgPoint.x - svgPointAfterWheel.x), // viewBox[0] + (svgPointAfterWheel.x - svgPoint.x) | |
y: viewBox[1] + (svgPoint.y - svgPointAfterWheel.y) // viewBox[1] + (svgPointAfterWheel.y - svgPoint.y) | |
} | |
svgElement.setAttribute('viewBox', `${viewBoxAfterTranslate.x} ${viewBoxAfterTranslate.y} ${viewBox[2]} ${viewBox[3]}`) | |
console.log('最後的 viewBox', svgElement.getAttribute('viewBox')) | |
console.groupEnd() | |
} | |
function init () { | |
const svgElement = document.getElementById('svgElement') | |
svgElement.addEventListener('mousemove', reportMouseCoordinates, false) | |
svgElement.addEventListener('wheel', zoom, false) | |
svgElement.addEventListener('mousedown', startDrag, false) | |
svgElement.addEventListener('mousemove', drag, false) | |
svgElement.addEventListener('mouseup', endDrag, false) | |
} | |
window.addEventListener('load', init, false) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment