PJCHENder
3/17/2017 - 2:10 AM

function to Zoom and Drag SVG

function to Zoom and Drag SVG


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)