Увеличить курсор от холста до мыши - PullRequest
63 голосов
/ 04 марта 2011

Я программирую проект HTML5 , который включает увеличение и уменьшение изображений с помощью колеса прокрутки.Я хочу приблизиться к курсору, как это делают карты Google, но я совершенно заблудился, как рассчитать движения.

Что у меня есть: изображение x и y (верхний левый угол);ширина и высота изображения;курсор x и y относительно центра холста.

Ответы [ 4 ]

210 голосов
/ 03 апреля 2011

Короче говоря, вы хотите translate() контекст холста по вашему смещению, scale() его, чтобы увеличить или уменьшить масштаб, а затем translate() назад по противоположности смещению мыши.Обратите внимание, что вам нужно преобразовать позицию курсора из пространства экрана в преобразованный контекст холста.

ctx.translate(pt.x,pt.y);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);

Демонстрация: http://phrogz.net/tmp/canvas_zoom_to_cursor.html

Я выложил полный рабочий пример на моем веб-сайте, чтобы вы могли проверить, поддерживают ли перетаскивание, нажмите, чтобы увеличить масштаб, сдвиньте, щелкните, чтобы отклонить, или прокрутите колесо вверх / вниз.

Единственная (текущая) проблема заключается в том, что Safari увеличивает масштаб слишком быстро по сравнению с Chrome или Firefox.

15 голосов
/ 22 ноября 2011

Надеюсь, эти библиотеки JS помогут вам: (HTML5, JS)

  1. Loupe

http://www.netzgesta.de/loupe/

CanvasZoom

https://github.com/akademy/CanvasZoom

Скроллер

https://github.com/zynga/scroller

Что касается меня, я использую лупу.Это круто!Для вас лучший случай - скроллер.

7 голосов
/ 16 марта 2016

Мне недавно нужно было заархивировать те же результаты, что и Phrogz, но вместо использования context.scale() я вычислял каждый размер объекта на основе отношения.

Это то, что я придумал.Логика позади этого очень проста.Перед масштабированием я вычисляю расстояние от точки до края в процентах, а затем корректирую область просмотра в правильном месте.

Мне понадобилось довольно много времени, чтобы придумать его, надеюсь, это сэкономит кому-то время.

$(function () {
  var canvas = $('canvas.main').get(0)
  var canvasContext = canvas.getContext('2d')

  var ratio = 1
  var vpx = 0
  var vpy = 0
  var vpw = window.innerWidth
  var vph = window.innerHeight

  var orig_width = 4000
  var orig_height = 4000

  var width = 4000
  var height = 4000

  $(window).on('resize', function () {
    $(canvas).prop({
      width: window.innerWidth,
      height: window.innerHeight,
    })
  }).trigger('resize')

  $(canvas).on('wheel', function (ev) {
    ev.preventDefault() // for stackoverflow

    var step

    if (ev.originalEvent.wheelDelta) {
      step = (ev.originalEvent.wheelDelta > 0) ? 0.05 : -0.05
    }

    if (ev.originalEvent.deltaY) {
      step = (ev.originalEvent.deltaY > 0) ? 0.05 : -0.05
    }

    if (!step) return false // yea..

    var new_ratio = ratio + step
    var min_ratio = Math.max(vpw / orig_width, vph / orig_height)
    var max_ratio = 3.0

    if (new_ratio < min_ratio) {
      new_ratio = min_ratio
    }

    if (new_ratio > max_ratio) {
      new_ratio = max_ratio
    }

    // zoom center point
    var targetX = ev.originalEvent.clientX || (vpw / 2)
    var targetY = ev.originalEvent.clientY || (vph / 2)

    // percentages from side
    var pX = ((vpx * -1) + targetX) * 100 / width
    var pY = ((vpy * -1) + targetY) * 100 / height

    // update ratio and dimentsions
    ratio = new_ratio
    width = orig_width * new_ratio
    height = orig_height * new_ratio

    // translate view back to center point
    var x = ((width * pX / 100) - targetX)
    var y = ((height * pY / 100) - targetY)

    // don't let viewport go over edges
    if (x < 0) {
      x = 0
    }

    if (x + vpw > width) {
      x = width - vpw
    }

    if (y < 0) {
      y = 0
    }

    if (y + vph > height) {
      y = height - vph
    }

    vpx = x * -1
    vpy = y * -1
  })

  var is_down, is_drag, last_drag

  $(canvas).on('mousedown', function (ev) {
    is_down = true
    is_drag = false
    last_drag = { x: ev.clientX, y: ev.clientY }
  })

  $(canvas).on('mousemove', function (ev) {
    is_drag = true

    if (is_down) {
      var x = vpx - (last_drag.x - ev.clientX)
      var y = vpy - (last_drag.y - ev.clientY)

      if (x <= 0 && vpw < x + width) {
        vpx = x
      }

      if (y <= 0 && vph < y + height) {
        vpy = y
      }

      last_drag = { x: ev.clientX, y: ev.clientY }
    }
  })

  $(canvas).on('mouseup', function (ev) {
    is_down = false
    last_drag = null

    var was_click = !is_drag
    is_drag = false

    if (was_click) {

    }
  })

  $(canvas).css({ position: 'absolute', top: 0, left: 0 }).appendTo(document.body)

  function animate () {
    window.requestAnimationFrame(animate)

    canvasContext.clearRect(0, 0, canvas.width, canvas.height)

    canvasContext.lineWidth = 1
    canvasContext.strokeStyle = '#ccc'

    var step = 100 * ratio

    for (var x = vpx; x < width + vpx; x += step) {
      canvasContext.beginPath()
      canvasContext.moveTo(x, vpy)
      canvasContext.lineTo(x, vpy + height)
      canvasContext.stroke()
    }
    for (var y = vpy; y < height + vpy; y += step) {
      canvasContext.beginPath()
      canvasContext.moveTo(vpx, y)
      canvasContext.lineTo(vpx + width, y)
      canvasContext.stroke()
    }

    canvasContext.strokeRect(vpx, vpy, width, height)

    canvasContext.beginPath()
    canvasContext.moveTo(vpx, vpy)
    canvasContext.lineTo(vpx + width, vpy + height)
    canvasContext.stroke()

    canvasContext.beginPath()
    canvasContext.moveTo(vpx + width, vpy)
    canvasContext.lineTo(vpx, vpy + height)
    canvasContext.stroke()

    canvasContext.restore()
  }

  animate()
})
<!DOCTYPE html>
<html>
<head>
	<title></title>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
	<canvas class="main"></canvas>
</body>
</html>
6 голосов
/ 19 июня 2013

Я взял ответ @ Phrogz за основу и создал небольшую библиотеку, которая позволяет перемещать холсты с помощью перетаскивания, масштабирования и поворота.Вот пример.

var canvas = document.getElementById('canvas')
//assuming that @param draw is a function where you do your main drawing.
var control = new CanvasManipulation(canvas, draw)
control.init()
control.layout()
//now you can drag, zoom and rotate in canvas

Более подробные примеры и документацию можно найти на странице проекта

.
...