SVG图像缩放及拖动

svg引入

方法一:通过embed标签引入

<embed id="svgPic" name="svgPic" text-rendering="geometricPrecision" pluginspage="http://www.adobe.com/svg/viewer/install/" align="top" src="/static/svg/svgPic.svg" type="image/svg+xml" wmode="transparent">

方法二:直接引入

<svg version="1.1" id="svgPic" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100%" height="100%" viewBox="0 0 1920 1080" enable-background="new 0 0 1920 1080" xml:space="preserve">
	<rect x="-1" y="0.128" fill="transparent" width="1920" height="1080"/>
	<line fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" x1="27.865" y1="138.277" x2="1039.588" y2="138.277"/>
	……
</svg>

svg图像缩放,从调用Init开始

let oDiv = null // svg对应的dom对象
let vbCX = 0
let vbCY = 0
let vbCW = 0
let vbCH = 0
let zoomVal = 0 // 放大缩小累计值
let zoomStepSize = 20 // 放大缩小每次改变的步长20
let removeFlag = false // 控制点击拖动,区分未点击时的鼠标移动
let startX = 0 // 起始值x坐标
let startY = 0 // 起始值y坐标
let moveX = 0 // 水平移动量,往左为正
let moveY = 0 // 垂直移动量,往上为正
let endX = 0 // 最终到达的x坐标
let endY = 0 // 最终到达的y坐标
let zoomW = 41 // 初始值 > zoomStepSize * 2 初次滚动后即可得到准确的当前值
let zoomH = 41 // 初始值 > zoomStepSize * 2 初次滚动后即可得到准确的当前值
let zoomX = 0
let zoomY = 0

// 加载SVG图像
export function Init (svgId) {
  oDiv = document.getElementById(svgId)
  getCurrentVB() // svg图层参数初始化
  // 挂载监听鼠标事件,考虑兼容性,兼容火狐DOMMouseScroll事件
  addEvent(oDiv, 'mousewheel', onMouseWheel)
  addEvent(oDiv, 'DOMMouseScroll', onMouseWheel)
  oDiv.addEventListener('mousedown', moveDownMouse, false)
  oDiv.addEventListener('mouseup', moveUpMouse, false)
  oDiv.addEventListener('mousemove', moveMouse, false)
}

// 鼠标滚轮事件
function onMouseWheel (e) {
  let ev = e || window.event
  let down = true
  // ev.wheelDelta已定义,ev.wheelDelta < 0为true表示往下滚动,为false表示往上滚动
  // ev.wheelDelta未定义,ev.detail > 0为true表示往下滚动,为false表示往上滚动
  // wheelDelta和detail正好相反,火狐中wheelDelta未定义只能使用detail
  down = ev.wheelDelta ? ev.wheelDelta < 0 : ev.detail > 0
  if (down) {
    zoomOut() // 缩小
  } else {
    zoomIn() // 放大
  }
  if (ev.preventDefault) {
    ev.preventDefault()
  }
  return false
}
function zoomIn () {
  if (zoomW > zoomStepSize * 2 && zoomH > zoomStepSize * 2) {
    zoomVal += zoomStepSize
    zoomTo('in')
  }
}
function zoomOut () {
  zoomVal -= zoomStepSize
  if (zoomVal >= -zoomStepSize * 11) {
    zoomTo('out')
  } else {
    zoomVal = -zoomStepSize * 11 // 最小缩至-220不能再缩了
  }
}
function zoomTo (flag) {
  // 变化之前获取当前viewBox的位置
  getCurrentVB()
  // *********** 放大缩小后的各值的计算 开始 ***********
  if (flag === 'in') {
    zoomX = vbCX + zoomStepSize
    zoomY = vbCY + zoomStepSize
    zoomW = vbCW - zoomStepSize * 2
    zoomH = vbCH - zoomStepSize * 2
  } else {
    zoomX = vbCX - zoomStepSize
    zoomY = vbCY - zoomStepSize
    zoomW = vbCW + zoomStepSize * 2
    zoomH = vbCH + zoomStepSize * 2
  }
  // *********** 放大缩小后的各值的计算 结束 ***********
  // 将计算的结果赋予viewBox刷新当前展示的视图位置
  oDiv.setAttributeNS(null, 'viewBox', zoomX + ' ' + zoomY + ' ' + zoomW + ' ' + zoomH)
  // 变化之后获取当前viewBox的位置 保证了 vbCX vbCY vbCW vbCH始终为当前viewBox的值
  endZoom()
}
function endZoom () {
  getCurrentVB()
  // 视图发生系列缩放改变后最终的(x, y)坐标记录下来,用于放大后拖动
  endX = vbCX
  endY = vbCY
}

// 鼠标点击事件
function moveDownMouse (evt) {
  removeFlag = true
  startX = parseInt(evt.clientX) // 当前点击的点的横坐标
  startY = parseInt(evt.clientY) // 当前点击的点的纵坐标
}
// 鼠标移动事件
function moveMouse (evt) {
  if (removeFlag) {
    oDiv.setAttributeNS(null, 'style', 'cursor: move')
    moveX = parseInt(evt.clientX) - startX // 当前点-原始点=移动量
    moveY = parseInt(evt.clientY) - startY // 当前点-原始点=移动量
    vbCX = endX - moveX
    vbCY = endY - moveY
    // 刷新当前viewBox展示的视图位置
    oDiv.setAttributeNS(null, 'viewBox', vbCX + ' ' + vbCY + ' ' + vbCW + ' ' + vbCH)
  }
}
// 鼠标点击后松开事件
function moveUpMouse (evt) {
  oDiv.setAttributeNS(null, 'style', 'cursor: default')
  // 视图发生系列移动后最终的(x, y)坐标记录下来,用于放大后拖动
  endX = vbCX
  endY = vbCY
  removeFlag = false
}

// 获取当前视图VB的位置信息
function getCurrentVB () {
  vbCX = parseFloat(oDiv.viewBox.animVal.x)
  vbCY = parseFloat(oDiv.viewBox.animVal.y)
  vbCW = parseFloat(oDiv.viewBox.animVal.width)
  vbCH = parseFloat(oDiv.viewBox.animVal.height)
}
// 绑定事件到dom节点,考虑到兼容性
function addEvent (obj, xEvent, fn) {
  if (obj.attachEvent) {
    obj.attachEvent('on' + xEvent, fn)
  } else {
    obj.addEventListener(xEvent, fn, false)
  }
}

svg缩放与移动【最新2020.12.02】

在之前的代码上进行的优化

let oDiv = null
let vbCX = 0
let vbCY = 0
let vbCW = 0
let vbCH = 0
let zoomVal = 0 // 放大缩小累计值
let zoomStepSize = 20 // 放大缩小每次改变的步长20
let removeFlag = false
let startX = 0 // 起始值x坐标
let startY = 0 // 起始值y坐标
let moveX = 0 // 水平移动量,往左为正
let moveY = 0 // 垂直移动量,往上为正
let endX = 0 // 最终到达的x坐标
let endY = 0 // 最终到达的y坐标
let zoomW = 41 // 初始值 > zoomStepSize * 2 初次滚动后即可得到准确的当前值
let zoomH = 41 // 初始值 > zoomStepSize * 2 初次滚动后即可得到准确的当前值
let zoomX = 0
let zoomY = 0

// 加载SVG地图
export function Init (svgId, svgDoc) {
  if (svgId === null) {
    oDiv = svgDoc // 外部引入直接传入svg对象
  } else {
    oDiv = document.getElementById(svgId) // 代码嵌入,通过svg标签的ID获取svg对象
  }
  // 参数初始化
  initBasicParam()
  addEvent(oDiv, 'mousewheel', onMouseWheel)
  addEvent(oDiv, 'DOMMouseScroll', onMouseWheel) // 兼容火狐使用DOMMouseScroll事件
  oDiv.addEventListener('mousedown', moveDownMouse, false)
  oDiv.addEventListener('mouseup', moveUpMouse, false)
  oDiv.addEventListener('mousemove', moveMouse, false)
}
// svg图层参数初始化
function initBasicParam () {
  getCurrentVB()
}
// 以下是鼠标事件 放大缩小地图 移动地图
function onMouseWheel (e) {
  let ev = e || window.event
  let down = true
  // ev.wheelDelta已定义,ev.wheelDelta < 0为true表示往下滚动,为false表示往上滚动
  // ev.wheelDelta未定义,ev.detail > 0为true表示往下滚动,为false表示往上滚动
  // wheelDelta和detail正好相反,火狐中wheelDelta未定义只能使用detail
  down = ev.wheelDelta ? ev.wheelDelta < 0 : ev.detail > 0
  if (down) {
    zoomOut()
  } else {
    zoomIn()
  }
  if (ev.preventDefault) {
    ev.preventDefault()
  }
  return false
}
// zoom in 放大
function zoomIn () {
  if (zoomW > zoomStepSize * 2 && zoomH > zoomStepSize * 2) {
    zoomVal += zoomStepSize
    zoomTo('in')
  }
}
// zoom out 缩小
function zoomOut () {
  zoomVal -= zoomStepSize
  if (zoomVal >= -zoomStepSize * 11) {
    zoomTo('out')
  } else {
    zoomVal = -zoomStepSize * 11 // 最小缩至-220不能再缩了
  }
}
function zoomTo (flag) {
  // 变化之前获取当前viewBox的位置
  getCurrentVB()
  // *********** 放大缩小后的各值的计算 开始 ***********
  if (flag === 'in') {
    zoomX = vbCX + zoomStepSize
    zoomY = vbCY + zoomStepSize
    zoomW = vbCW - zoomStepSize * 2
    zoomH = vbCH - zoomStepSize * 2
  } else {
    zoomX = vbCX - zoomStepSize
    zoomY = vbCY - zoomStepSize
    zoomW = vbCW + zoomStepSize * 2
    zoomH = vbCH + zoomStepSize * 2
  }
  // *********** 放大缩小后的各值的计算 结束 ***********
  // 将计算的结果赋予viewBox刷新当前展示的视图位置
  oDiv.setAttributeNS(null, 'viewBox', zoomX + ' ' + zoomY + ' ' + zoomW + ' ' + zoomH)
  // 变化之后获取当前viewBox的位置 保证了 vbCX vbCY vbCW vbCH始终为当前viewBox的值
  endZoom()
}
function endZoom () {
  getCurrentVB()
  // 视图发生系列缩放改变后最终的(x, y)坐标记录下来,用于放大后拖动
  endX = vbCX
  endY = vbCY
}
function moveDownMouse (evt) {
  // 移动点击时,初次先确认最终的坐标点,因为viewBox前两个参数可能不是0 0
  endZoom()
  removeFlag = true
  startX = parseInt(evt.clientX) // 当前点击的点的横坐标
  startY = parseInt(evt.clientY) // 当前点击的点的纵坐标
}
function moveMouse (evt) {
  if (removeFlag) {
    oDiv.setAttributeNS(null, 'style', 'cursor: move')
    moveX = parseInt(evt.clientX) - startX // 当前点-原始点=移动量
    moveY = parseInt(evt.clientY) - startY // 当前点-原始点=移动量
    vbCX = endX - moveX
    vbCY = endY - moveY
    // 刷新当前viewBox展示的视图位置
    oDiv.setAttributeNS(null, 'viewBox', vbCX + ' ' + vbCY + ' ' + vbCW + ' ' + vbCH)
  }
}
function moveUpMouse (evt) {
  oDiv.setAttributeNS(null, 'style', 'cursor: default')
  // 视图发生系列移动后最终的(x, y)坐标记录下来,用于放大后拖动
  endX = vbCX
  endY = vbCY
  removeFlag = false
}
function getCurrentVB () {
  vbCX = parseFloat(oDiv.viewBox.animVal.x)
  vbCY = parseFloat(oDiv.viewBox.animVal.y)
  vbCW = parseFloat(oDiv.viewBox.animVal.width)
  vbCH = parseFloat(oDiv.viewBox.animVal.height)
}
function addEvent (obj, xEvent, fn) {
  if (obj.attachEvent) {
    obj.attachEvent('on' + xEvent, fn)
  } else {
    // 解决e.preventDefault()报错 第三个参数由false改为 {passive: false}
    obj.addEventListener(xEvent, fn, { passive: false })
  }
}

遗留问题:

1、360等浏览器 SVG 放大倍数有问题
2、Microsoft edge SVG缩放闪屏
解决后更新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值