Увеличение / уменьшение масштаба Javascript до координат x / y мыши

Мне удалось заставить мышь перетаскивать, чтобы прокрутить 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>


person Community    schedule 29.07.2019    source источник


Ответы (1)


Ваша проблема в основном связана со следующими строками

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

Прокрутка со шкалой работает, как показано ниже

  • Вычислите немасштабированную x, y координату, где происходит масштабирование
  • Рассчитайте новую масштабированную x, y координату, умножив ее на новую шкалу
  • Теперь вы хотите, чтобы эта новая координата оставалась на том же месте, где была существующая координата. Таким образом, если вы вычтите offset x,y из нового scaled 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/

Результаты

person Tarun Lalwani    schedule 01.08.2019
comment
Спасибо. Это действительно исправило прокрутку. Я применил ваши изменения в моем коде здесь jsfiddle.net/catalinu/zof8q63u/15 и Я также исправил белое пространство внизу при максимальном уменьшении масштаба. Вам тоже нужно подождать 18 часов, чтобы назначить награду. - person ; 01.08.2019
comment
Используя свою скрипку jsfiddle.net/catalinu/jLfrbzwp и изменив минимальную шкалу на 0,5, знаете ли вы почему, когда вы уменьшаете масштаб на 0,5, почему вертикальная полоса прокрутки такая большая и при прокрутке вниз появляется много белого пространства? Есть способ исправить это? - person ; 01.08.2019
comment
Это происходит из-за того, что вы указали фиксированную высоту 200vh, высоту также необходимо установить с помощью javascript, чтобы убедиться, что это именно то, что вы хотите. - person Tarun Lalwani; 01.08.2019
comment
Я добавил фиксированную ширину и высоту 5000 пикселей в раздел div, например, jsfiddle.net/catalinu/jLfrbzwp / 2. Какую ширину / высоту мне нужно установить с помощью javascript, поскольку они всегда будут оставаться такими же, меняется только масштабирование? Разве браузер не должен это понять? Горизонтальная сторона работает, потому что основной контейнер составляет 100%, но вертикальная сторона разрывается этим пустым пространством, потому что мы используем 100vh, поскольку высота 100% ничего не делает. Какие-нибудь решения? - person ; 01.08.2019
comment
Я бы предложил задать по этому поводу новый вопрос. Также посмотрите, помогает ли это stackoverflow.com/questions / 42616579 /? Также опубликуйте ссылку на ваш новый вопрос в этой теме для справки. - person Tarun Lalwani; 03.08.2019
comment
Спасибо за предложение. Я создал здесь новый вопрос stackoverflow.com/questions/57373062/ - person ; 06.08.2019