index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import Hammer from 'hammerjs' // 引用hammerjs
  2. // 定义缩放方法,接收一个element参数:使用export暴露该方法
  3. export function zoomElement(el) {
  4. function point2D(x, y) {
  5. return { x: x, y: y }
  6. }
  7. // 判断 正数,负数,不是数字
  8. function checkNumType(num) {
  9. var reg = new RegExp('^-?[0-9]*.?[0-9]*$')
  10. if (reg.test(num)) {
  11. // 用于检测一个字符串是否匹配某个模式
  12. var absVal = Math.abs(num) // 如果参数是非负数,则返回该参数;如果参数是负数,则返回该参数的相反数。
  13. return num == absVal ? true : false
  14. } else {
  15. console.log('this is not number')
  16. }
  17. }
  18. function exChangeNum(num, reNum) {
  19. let flag = checkNumType(num)
  20. let reFlag = checkNumType(reNum)
  21. let realNum = 0
  22. if (!flag && reFlag) {
  23. realNum = Number('-' + reNum)
  24. } else {
  25. realNum = Number(reNum)
  26. }
  27. return realNum
  28. }
  29. var reqAnimationFrame = (function () {
  30. return (
  31. window[Hammer.prefixed(window, 'requestAnimationFrame')] ||
  32. function (callback) {
  33. window.setTimeout(callback, 1000 / 60)
  34. }
  35. )
  36. })()
  37. var ticking = false
  38. var tMatrix = [1, 0, 0, 1, 0, 0] //x缩放,无,无,y缩放,x平移,y平移
  39. var initScale = 1 //初始化scale
  40. el.addEventListener('touchmove', function (e) {
  41. e.preventDefault()
  42. })
  43. var mc = new Hammer.Manager(el)
  44. var nowScale = 0
  45. var poscenter = point2D(0, 0) // 缓存双指的中心坐标
  46. var duration = '' // 设置过渡效果,用于双击缩放效果
  47. var lastTranslate = point2D(0, 0) // 记录上次的偏移值
  48. var lastcenter = point2D(el.offsetWidth / 2, el.offsetHeight / 2) // 图像的中心点,用于对比双指中心点
  49. var center = lastcenter // 初始化为图片中心点
  50. // 添加缩放事件
  51. mc.add(new Hammer.Pan({ threshold: 0, pointers: 1 }))
  52. mc.add(new Hammer.Pinch({ threshold: 0 }))
  53. mc.add(new Hammer.Tap({ event: 'doubletap', taps: 2 }))
  54. mc.on('pinchstart', onPinchStart) // 双指缩放
  55. mc.on('pinchmove', onPinch) // 双指移动
  56. mc.on('panmove', onPan)
  57. mc.on('panstart', onPanStart)
  58. // 缩放开始
  59. function onPinchStart(ev) {
  60. duration = ''
  61. lastTranslate = point2D(tMatrix[4], tMatrix[5]) //记录上一次的偏移值 0 0
  62. initScale = tMatrix[0] || 1
  63. // 手势中心点
  64. poscenter = point2D(ev.center.x, ev.center.y)
  65. // 图像中心点 = 初始化图像中心点 + 上一次偏移量的中心点
  66. lastcenter = point2D(center.x + lastTranslate.x, center.y + lastTranslate.y) //重新计算放大后的中心坐标
  67. // 手势中心点 = 缩放中心点 - 图像中心点
  68. poscenter = point2D(ev.center.x - lastcenter.x, ev.center.y - lastcenter.y)
  69. requestElementUpdate('onpinchStart')
  70. }
  71. // 缩放途中
  72. function onPinch(ev) {
  73. // 缩放倍数 这里的缩放倍数
  74. nowScale = initScale * ev.scale
  75. // 如果倍数小于1 则等于1
  76. if (nowScale < 1) {
  77. nowScale = 1
  78. }
  79. // 缩放倍数
  80. tMatrix[0] = tMatrix[3] = nowScale
  81. let x = Number((1 - ev.scale) * poscenter.x + lastTranslate.x)
  82. let y = Number((1 - ev.scale) * poscenter.y + lastTranslate.y)
  83. let tempPosX = el.getBoundingClientRect().width / 2 - point2D(el.offsetWidth / 2, el.offsetHeight / 2).x
  84. let tempPosY = el.getBoundingClientRect().height / 2 - point2D(el.offsetWidth / 2, el.offsetHeight / 2).y
  85. if (Math.abs(x) > Math.abs(tempPosX)) {
  86. x = exChangeNum(x, tempPosX)
  87. }
  88. if (Math.abs(y) > Math.abs(tempPosY)) {
  89. y = exChangeNum(y, tempPosY)
  90. }
  91. tMatrix[4] = x
  92. tMatrix[5] = y
  93. requestElementUpdate('onpinch')
  94. }
  95. // 开始拖动
  96. function onPanStart() {
  97. lastTranslate = point2D(tMatrix[4], tMatrix[5]) // 缓存上一次的偏移值
  98. }
  99. // 拖动过程
  100. function onPan(ev) {
  101. tMatrix[0] = tMatrix[3] = nowScale || initScale
  102. // 拖动的动画 1.6
  103. duration = '1.6'
  104. let x = Number(lastTranslate.x + ev.deltaX)
  105. let y = Number(lastTranslate.y + ev.deltaY)
  106. let tempPosX = el.getBoundingClientRect().width / 2 - point2D(el.offsetWidth / 2, el.offsetHeight / 2).x
  107. let tempPosY = el.getBoundingClientRect().height / 2 - point2D(el.offsetWidth / 2, el.offsetHeight / 2).y
  108. if (Math.abs(x) > Math.abs(tempPosX)) {
  109. x = exChangeNum(x, tempPosX)
  110. }
  111. if (Math.abs(y) > Math.abs(tempPosY)) {
  112. y = exChangeNum(y, tempPosY)
  113. }
  114. tMatrix[4] = x
  115. tMatrix[5] = y
  116. requestElementUpdate('onpan')
  117. }
  118. // 每次都会·更新 因为是在移动端 所以都采用rem 否则可以直接用matrix
  119. function updateElementTransform() {
  120. el.style.transition = duration
  121. let x = tMatrix[4] + 'px'
  122. let y = tMatrix[5] + 'px'
  123. el.style.transform = 'translate(' + x + ',' + y + ') ' + 'scale(' + tMatrix[0] + ',' + tMatrix[3] + ')'
  124. el.style.WebkitTransform = 'translate(' + x + ',' + y + ') ' + 'scale(' + tMatrix[0] + ',' + tMatrix[3] + ')'
  125. el.style.msTransform = 'translate(' + x + ',' + y + ') ' + 'scale(' + tMatrix[0] + ',' + tMatrix[3] + ')'
  126. // var tmp = tMatrix.join(',')
  127. // el.style.transform = 'matrix(' + tmp + ')'
  128. // el.style.WebkitTransform = 'matrix(' + tmp + ')'
  129. // el.style.msTransform = 'matrix(' + tmp + ')'
  130. ticking = false
  131. }
  132. function requestElementUpdate() {
  133. if (!ticking) {
  134. reqAnimationFrame(updateElementTransform)
  135. ticking = true
  136. }
  137. }
  138. /**
  139. 初始化设置
  140. */
  141. requestElementUpdate()
  142. }