【问题标题】:Javascript zoom in/out to mouse x/y coordinatesJavascript放大/缩小鼠标x/y坐标
【发布时间】:2019-12-07 06:54:29
【问题描述】:

我设法让鼠标拖动来滚动 div,但是用鼠标放大/缩小不完整。

它有效,但我希望鼠标指针将图像保持在该位置并同时缩放它,如下所示:

我需要使用scrollBy() 将滚动返回到缩放之前的上一点。有人知道怎么做吗?

这是https://jsfiddle.net/xta2ccdt/13/ 某人制作的小提琴,这正是我需要的,但代码使用了translate() 和其他不适用于此处的东西,因为我也有滚动/拖动。

这是我的 jsfiddle 代码https://jsfiddle.net/catalinu/1f6e0jna/

这是stackoverflow中的代码:

请帮忙。我为此苦苦挣扎了好几天。

for (const divMain of document.getElementsByClassName('main')) {
  // drag the section
  for (const divSection of divMain.getElementsByClassName('section')) {
  	// when mouse is pressed store the current mouse x,y
    let previousX, previousY
    divSection.addEventListener('mousedown', (event) => {
      previousX = event.pageX
      previousY = event.pageY
    })
    
    // when mouse is moved, scrollBy() the mouse movement x,y
    divSection.addEventListener('mousemove', (event) => {
    	// only do this when the primary mouse button is pressed (event.buttons = 1)
      if (event.buttons) {
        let dragX = 0
        let dragY = 0
        // skip the drag when the x position was not changed
        if (event.pageX - previousX !== 0) {
          dragX = previousX - event.pageX
          previousX = event.pageX
        }
        // skip the drag when the y position was not changed
        if (event.pageY - previousY !== 0) {
          dragY = previousY - event.pageY
          previousY = event.pageY
        }
        // scrollBy x and y
        if (dragX !== 0 || dragY !== 0) {
          divMain.scrollBy(dragX, dragY)
        }
      }
    })
  }

  // zoom in/out on the section
  let scale = 1
  const scaleFactor = 0.05
  divMain.addEventListener('wheel', (event) => {
  	// preventDefault to stop the onselectionstart event logic
    event.preventDefault()
    for (const divSection of divMain.getElementsByClassName('section')) {
    	// set the scale change value
      const scaleChange = (event.deltaY < 0) ? scaleFactor : -scaleFactor
      // don't allow the scale to go outside of [0,5 - 2]
      if (scale + scaleChange < 0.5 || scale + scaleChange > 2) {
        return
      }
      // round the value when using high dpi monitors
      scale = Math.round((scale + scaleChange) * 100) / 100

			// apply the css scale
      divSection.style.transform = `scale(${scale}, ${scale})`

      // re-adjust the scrollbars        
      const x = Math.round(divMain.scrollLeft * scaleChange)
      const y = Math.round(divMain.scrollTop * scaleChange)
      divMain.scrollBy(x, y)
    }
  })
}
body {
  margin: 0;
}

.main {
	width: 100%; /* percentage fixes the X axis white space when zoom out */
	height: 100vh; /* this is still an issue where you see white space when zoom out in the Y axis */
	overflow: scroll; /* needed for safari to show the x axis scrollbar */
}

.main .section {
	width: 200%;
	height: 200vh;
	background-image: url('https://iso.500px.com/wp-content/uploads/2014/07/big-one.jpg');
	transform-origin: 0 0;
}
<main class="main">
  <section class="section"></section>
</main>

【问题讨论】:

    标签: javascript css zooming scale


    【解决方案1】:

    您的问题主要围绕以下几行

    const x = Math.round(divMain.scrollLeft * scaleChange)
    const y = Math.round(divMain.scrollTop * scaleChange)
    

    按比例滚动的方式如下所示

    • 计算发生缩放的未缩放x, y 坐标
    • 计算新缩放的x, y 坐标我将它与新缩放相乘
    • 现在您希望这个新坐标保持在现有坐标所在的位置。所以基本上如果你从新的scaled x,y 中减去offset x,y,你会得到左右滚动。

    更新后的代码如下

    for (const divMain of document.getElementsByClassName('main')) {
      // drag the section
      for (const divSection of divMain.getElementsByClassName('section')) {
        // when mouse is pressed store the current mouse x,y
        let previousX, previousY
        divSection.addEventListener('mousedown', (event) => {
          previousX = event.pageX
          previousY = event.pageY
        })
    
        // when mouse is moved, scrollBy() the mouse movement x,y
        divSection.addEventListener('mousemove', (event) => {
            // only do this when the primary mouse button is pressed (event.buttons = 1)
          if (event.buttons) {
            let dragX = 0
            let dragY = 0
            // skip the drag when the x position was not changed
            if (event.pageX - previousX !== 0) {
              dragX = previousX - event.pageX
              previousX = event.pageX
            }
            // skip the drag when the y position was not changed
            if (event.pageY - previousY !== 0) {
              dragY = previousY - event.pageY
              previousY = event.pageY
            }
            // scrollBy x and y
            if (dragX !== 0 || dragY !== 0) {
              divMain.scrollBy(dragX, dragY)
            }
          }
        })
      }
    
      // zoom in/out on the section
      let scale = 1
      const factor = 0.05
      const max_scale =4
    
      divMain.addEventListener('wheel', (e) => {
        // preventDefault to stop the onselectionstart event logic
        for (const divSection of divMain.getElementsByClassName('section')) {
            e.preventDefault();
            var delta = e.delta || e.wheelDelta;
            if (delta === undefined) {
              //we are on firefox
              delta = e.originalEvent.detail;
            }
            delta = Math.max(-1,Math.min(1,delta)) // cap the delta to [-1,1] for cross browser consistency
                offset = {x: divMain.scrollLeft, y: divMain.scrollTop};
         image_loc = {
            x: e.pageX + offset.x,
            y: e.pageY + offset.y
         }
    
         zoom_point = {x:image_loc.x/scale, y: image_loc.y/scale}
    
            // apply zoom
            scale += delta*factor * scale
            scale = Math.max(1,Math.min(max_scale,scale))
    
         zoom_point_new = {x:zoom_point.x * scale, y: zoom_point.y * scale}
    
         newScroll = {
            x: zoom_point_new.x - e.pageX,
            y: zoom_point_new.y - e.pageY
         }
    
    
          divSection.style.transform = `scale(${scale}, ${scale})`
          divMain.scrollTop = newScroll.y
          divMain.scrollLeft = newScroll.x
        }
    
    
      })
    }
    

    更新的小提琴是

    https://jsfiddle.net/uy390v8t/1/

    【讨论】:

    • 谢谢。这确实修复了滚动。我已将您的更改应用到我的代码jsfiddle.net/catalinu/zof8q63u/15,并且在最大缩小时我还修复了底部的空白区域。也需要等待 18 小时才能给你赏金。
    • 用你的小提琴jsfiddle.net/catalinu/jLfrbzwp把最小比例改为0.5,你知道为什么当你缩小到0.5时,为什么垂直滚动条那么大,向下滚动会显示很多空白?有什么办法解决吗?
    • 这是因为你给了一个固定的200vh高度,高度也需要通过javascript来设置,以确保它是你想要的
    • 我已经像 jsfiddle.net/catalinu/jLfrbzwp/2 一样在部分 div 中添加了 5000px 的固定宽度和高度。我需要用 javascript 设置什么宽度/高度,因为它总是保持不变,只有缩放变化?浏览器不应该解决这个问题吗?水平边工作导致主容器为 100%,但垂直边因我们使用 100vh 而中断,因为 100% 高度没有任何作用。有什么解决办法吗?
    • 我建议为此发布一个新问题。还看看这是否有帮助 stackoverflow.com/questions/42616579/… ?还要在此线程中发布指向您的新问题的链接以供参考
    猜你喜欢
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-11
    • 1970-01-01
    • 2014-08-27
    • 2016-01-01
    • 2011-01-23
    相关资源
    最近更新 更多