Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New feature: keyboard navigation #90

Open
axlevxa opened this issue Jul 13, 2021 · 3 comments
Open

New feature: keyboard navigation #90

axlevxa opened this issue Jul 13, 2021 · 3 comments

Comments

@axlevxa
Copy link

axlevxa commented Jul 13, 2021

Would be nice to add simple keyboard navigation to zoom with +/- keys, and to move with arrow keys. Similar to implementation demo'd here for anvaka/panzoom (which is really great work but i still much prefer this one for use with SVG.JS).

Keyboard navigation would definitely help for accessibility purposes.

@Fuzzyma
Copy link
Member

Fuzzyma commented Jul 14, 2021

Mh, just thinking if that would fit better in a separate plugin...
Also it should not blindly capture those keys whenever someone on the page uses +/-.
It is rather easy to implement thought especially so I don't really see the need for it:

Something along those lines:

canvas.on('keydown', (ev) => {
  if (ev.key === '+') {
    canvas.zoom(canvas.zoom() + 1)
  }

  if (ev.key === '-') {
    canvas.zoom(canvas.zoom() - 1)
  }
})

Could be enhanced by not using linear scale

@axlevxa
Copy link
Author

axlevxa commented Jul 15, 2021

Good points. Thank you so much for providing a sample script! I have extended a bit:

canvas.on('keydown', (ev) => {
  let currentZoom = canvas.zoom();
  let zoomMax = 4;
  let zoomMin = 0.3;
  let zoomAmount = 0.5;
  let panAmount = 20;
  if (ev.key === '=' || ev.key === '+') {
    // Increase Zoom (+)
    if ((currentZoom + zoomAmount) < zoomMax) {
      canvas.zoom(currentZoom + zoomAmount)
    }
    else {
      canvas.zoom(zoomMax)
    }
  }
  if (ev.key === '-' || ev.key === '_') {
    // Minus Zoom (-)
    if ((currentZoom - zoomAmount) > zoomMin) {
      canvas.zoom(currentZoom - zoomAmount)
    }
    else {
      canvas.zoom(zoomMin)
    }
  }
  if (ev.key === 'Enter') {
    // Click currently focused element on (Enter)
    let canvasFocus = document.activeElement;
    canvasFocus.dispatchEvent(new Event('click'));
  }
  if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown' || ev.key === 'ArrowLeft' || ev.key === 'ArrowRight' || ev.key === 'w' || ev.key === 's' || ev.key === 'a' || ev.key === 'd') {
    // Move with arrow keys or WSAD keys
    let currentViewbox = canvas.viewbox()
    let currentX = currentViewbox["x"]
    let currentY = currentViewbox["y"]
    if (ev.key === 'ArrowUp' || ev.key === 'w') {
      canvas.viewbox(currentX, currentY - panAmount, currentViewbox["w"], currentViewbox["h"])
    }
    if (ev.key === 'ArrowDown' || ev.key === 's') {
      canvas.viewbox(currentX, currentY + panAmount, currentViewbox["w"], currentViewbox["h"])
    }
    if (ev.key === 'ArrowLeft' || ev.key === 'a') {
      canvas.viewbox(currentX - panAmount, currentY, currentViewbox["w"], currentViewbox["h"])
    }
    if (ev.key === 'ArrowRight' || ev.key === 'd') {
      canvas.viewbox(currentX + panAmount, currentY, currentViewbox["w"], currentViewbox["h"])
    }
  }
})

to allow keyboard users to interact with the SVG using enter key, arrow keys and so forth.

Thanks again for the code snippet, it really nudged me along.

@Fuzzyma
Copy link
Member

Fuzzyma commented Jul 15, 2021

Awesome! That looks great.
Btw you can write currentViewbox.w instead of currentViewbox["w"] and to create a real mouse event (and not just some random event called "click") you can use new MouseEvent.

If the +/- doesn't feel natural (because your step size is fixed and you zoom the same amount even if you are really far zoomed out) you can try to adapt it with an exponential function. This is also used for the wheel zoom in the lib. The corresponding line is this:

let lvl = Math.pow(1 + zoomFactor, (-1 * normalizedPixelDeltaY) / 100) * this.zoom()

I think what should work is:

let newZoom = Math.pow(3, -1 / 100) * this.zoom()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants