Giter VIP home page Giter VIP logo

worka / vanilla-js-wheel-zoom Goto Github PK

View Code? Open in Web Editor NEW
158.0 3.0 29.0 1.17 MB

Image resizing using mouse wheel (pinch to zoom) + drag scrollable image (as well as any HTML content)

Home Page: https://worka.github.io/vanilla-js-wheel-zoom

License: MIT License

JavaScript 99.00% Dockerfile 0.14% Shell 0.87%
wheelzoom js javascript vanilla mousewheel imagezoom imagescale drag-scrollable-image scrollableimage dragimage

vanilla-js-wheel-zoom's Introduction

vanilla-js-wheel-zoom

Image resizing using mouse wheel (pinch to zoom) + drag scrollable image (as well as any HTML content)

GitHub tag (latest by date) GitHub stars GitHub issues GitHub forks

Advantages:

  • the ability to fit the image into a container of any proportion
  • the ability to scale any HTML content
  • touch screen devices support

Starting with version 5, the plugin switched to using style transform. To use the plugin in older browsers, switch to earlier versions.

You need to center the image (or any HTML content) in the "viewport" in which scaling will take place. The "viewport" is taken automatically as the parent of the image in DOM.

HTML content can be of any structure, but the topmost child element in the β€œviewport” must be one. In the example with "badge" below, it will be more clear what is meant.

πŸ– If you find my plugin helpful, please donate me 🀝

Demo (only one image)

Demo (multi images)

Demo (html)

Install

npm i vanilla-js-wheel-zoom

or

yarn add vanilla-js-wheel-zoom

Get started

#myViewport {
    display: flex;
    align-items: center;
    justify-content: center;
}
<div id="myViewport" style="width:600px;height:600px;">
    <img id="myContent" src="https://via.placeholder.com/2400x1400" alt="image" />
</div>
WZoom.create('#myContent');

Syntax & Parameters

/**
 * Create WZoom instance
 * @param {string|HTMLElement} selectorOrHTMLElement
 * @param {Object} [options]
 * @returns {WZoom}
 */
const wzoom = WZoom.create(selectorOrHTMLElement[, options]);

Badge on the image

#myViewport {
    display: flex;
    align-items: center;
    justify-content: center;
}

#myBadge {
    position: absolute;
    border: solid 2px red;
    font-size: 80px;
}

#myImage {
    width: auto;
    height: auto;
    margin: auto;
}
<div id="myViewport" style="width:600px;height:600px;">
    <div id="myContent">
        <div id="myBadge" style="left:900px;top:500px;">Badge</div>
        <img id="myImage" src="https://via.placeholder.com/2500x1500" alt="image"/>
    </div>
</div>
WZoom.create('#myContent', {
    type: 'html',
    width: 2500,
    height: 1500,
});

Control buttons

<button data-zoom-up>Zoom Up</button>
<button data-zoom-down>Zoom Down</button>
const wzoom = WZoom.create('img');

document.querySelector('[data-zoom-up]').addEventListener('click', () => {
    wzoom.zoomUp();
});

document.querySelector('[data-zoom-down]').addEventListener('click', () => {
    wzoom.zoomDown();
});

On window resize

const wzoom = WZoom.create('img');

window.addEventListener('resize', () => {
    wzoom.prepare();
});

How to rotate the image?

Try this πŸ˜‰ (and see demo)

Callbacks onMaxScaleReached() / onMinScaleReached()

There are no such, but you can get the desired behavior (and see demo)

Saving image state on page reload

See demo

Playground...

Have some fun πŸ€Έβ€β™‚οΈ

Options

name type default note
type String image image - if you need to scale only one image. In this case, there is no need to pass the parameters width and height. html - if you need to scale the HTML code. It is advisable to specify the parameters width and height that correspond to the original full size of the HTML content.
width Number null For type image computed auto (if width set null), for type html need set real html content width, else computed auto.
height Number null For type image computed auto (if height set null), for type html need set real html content height, else computed auto.
minScale Number null The minimum scale to which the image can be zoomed.
If falsy or greater than maxScale then computed auto.
maxScale Number 1 The maximum scale to which the image can be zoomed.
1 means that the image can be maximized to 100%, 2 - 200%, etc.
speed Number 1.1 Factor with which the image will be scaled.
The larger the value, the larger the step.
Can tend to 1, but should not be equal to it (ex. 1.05, 1.005) or can be greater (ex. 1.5, 2, 5, 10)
zoomOnClick Boolean true Zoom to maximum (minimum) size on click.
zoomOnDblClick Boolean false Zoom to maximum (minimum) size on double click. If true then zoomOnClick = false
prepare Function undefined Called after the script is initialized when the image is scaled and fit into the container. Gets WZoom instance as the first argument.
rescale Function undefined Called on every change of scale. Gets WZoom instance as the first argument.
alignContent String center Align content center, left, top, right, bottom
smoothTime Number .25 Time of smooth extinction. if 0 then no smooth extinction. Disabled for touch devices. (value in seconds)
disableWheelZoom Boolean false
reverseWheelDirection Boolean false Reverse wheel zoom direction
dragScrollable Boolean true If true - scaled image can be dragged with the mouse to see parts of the image that are out of scale.
smoothTimeDrag Number smoothTime Optional override to smoothTime for mouse drag/pan actions.
Setting low (or 0) allows fluid drag actions, while maintaining zoom-smoothness from higher smoothTime.
If not provided, matches whatever smoothTime resolves to: smoothTime's provided value or its default.
onGrab Function undefined Called after grabbing an element. Gets the event and WZoom instance as the arguments.
onMove Function undefined Called on every tick when moving element. Gets the event and WZoom instance as the arguments.
onDrop Function undefined Called after dropping an element. Gets the event and WZoom instance as the arguments.

API

name note
.prepare() Reinitialize script
.transform(top, left, scale) Rebuild content state with passed params
.zoomUp() Zoom on one step (see option speed)
.maxZoomUp() Zoom to max scale
.zoomDown() Zoom out on one step (see option speed)
.maxZoomDown() Zoom to min scale
.zoomUpToPoint({x, y}) Zoom on one step to point (see option speed)
.zoomDownToPoint({x, y}) Zoom out on one step to point (see option speed)
.maxZoomUpToPoint({x, y}) Zoom to max scale to point
.destroy() Destroy object

License

MIT

vanilla-js-wheel-zoom's People

Contributors

dependabot[bot] avatar gunarm avatar worka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

vanilla-js-wheel-zoom's Issues

bootstrapt modal

when i use the


image

inside bootstrap modal body the image get bigger and the zoom in and out won't work

Exponential zoom feature

Thanks for vanilla-js-wheel-zoom, exactly what I was looking for.

But it works better for me, when I modify it to zoom exponentially, instead of linearly.
Because as you zoom in more and more, with the linear (normal) version, the zoom factor decreases.
While with the exponential version, the zoom factor stays constant.

Here is a quick comparison/demonstration: wzoom-exponential-test.zip
I don't use Git but here is the diff: exponentialzoom.patch.txt
In the minified version I replaced +this.direction/this.options.speed with *Math.pow(this.options.speed,this.direction).

Anyway, hopefully this is useful for someone else.

Fix smoothTime set to 0 not work

In this line:

options.smoothTime = Number(options.smoothTime) || wZoomDefaultOptions.smoothTime;

https://github.com/worka/vanilla-js-wheel-zoom/blob/727db6934e4d84d562c87a5e44bb66fccca7f894/src/wheel-zoom.js#L372C60-L372C60

Has something problem, since smoothTime option value can set to be 0, but the || operator means check "falsely" (false == 0), so if we set that the 0, || operator will assume that the value is false lead to be apply default value.

So I think we could use ?? operator, who will check undefined or null instead of the "falsely".

Fix:

options.smoothTime = Number(options.smoothTime) ?? wZoomDefaultOptions.smoothTime;

How to scale wzoom to the rotated image?

Hello,

Probably it is not an issue. But could you please let me know how is it better to update wzoom parameters or object to use it for the rotated images? I mean that initially, the image is horizontal, like 800x600 px. Then I use css transform rotate style (interaction with the user) and the image becomes vertical, like 600x800 px. And then the wzoom doesn't work properly due to the size was changed. And what do I need to do to update wzoom? Does it make sense?

Thank you in advance.

Best regards,
Igor

SyntaxError: Cannot use import statement outside a module

When attempting to run our tests that import the library throws an error in wheel-zoom.js.

Details:
     C:\Development\angular\node_modules\vanilla-js-wheel-zoom\src\wheel-zoom.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import {
                                                                                      ^^^^^^
    SyntaxError: Cannot use import statement outside a module
      11 | import { Actions, EffectsModule } from '@ngrx/effects';
      12 | import { filter, take, takeUntil, tap, withLatestFrom } from 'rxjs';
    > 13 | import WZoom from 'vanilla-js-wheel-zoom';
         | ^
      14 | import { ofZoomDown } from './zoom-down-action-creator';
      15 | import { ofZoomUp } from './zoom-up-action-creator';
      16 |
      at Runtime.createScriptFromCode (../../../../node_modules/jest-runtime/build/index.js:1728:14)
      at Object.<anonymous> (../../framework/src/lib/directives/zoom-and-pinch/zoom-and-pinch.directive.ts:13:1)

We think that a possible cause is because typings are missing.
We have no problem doing a PR to fix it, but we're not sure what caused the error.

How to avoid moving the whole page on the mobile?

Hi,

I'm trying to use this plugin on the page to zoom the image. But when I moving the zoomed image on the mobile it moves the whole HTML page, not the image only. Could you please fix it? Or help me how to do it?

And is it possible to zoom on the mobile browser using 2 fingers?

Thanks in advance.

Best regards,
Igor

Clicking on "out of bounds area" can result in not being able to drag

To reproduce
goto: https://worka.github.io/vanilla-js-wheel-zoom/demo-image.html
Click in the far upper right of the image box, so in the gray area. Now try to drag the image, you should only be able to drag the image left-right, it should be "stuck" when trying to drag vertically. I think that is because the transform is outside the bounds set in the draggable limits

I think the following change

            var maxAvailableLeft =
                (contentNewWidth - window.originalWidth) / 2 +
                content.correctX;

            var maxAvailableTop =
                (contentNewHeight - window.originalHeight) / 2 +
                content.correctY;

            if (contentNewLeft < -maxAvailableLeft)
                contentNewLeft = -maxAvailableLeft;
            if (contentNewLeft > maxAvailableLeft)
                contentNewLeft = maxAvailableLeft;

            if (contentNewTop < -maxAvailableTop)
                contentNewTop = -maxAvailableTop;
            if (contentNewTop > maxAvailableTop)
                contentNewTop = maxAvailableTop;

Zooming on mobile with two fingers is triggering zoomOnDblClick

Hi,

I think this is amazing, but I've been having a small problem integrating it into my site. I'd like to have it so the user can double click (or double tap) on mobile to zoom the picture all the way in, or zoom it all the way out. However, when users on mobile go to scale the image manually using two fingers, it's triggering the double tap event, and zooming it all the way in, essentially making it so people on mobile can't manually scale.

Is there an easy fix for this? I'd also love it if double tapping would always zoom the image all the way out if the image is already partially zoomed, and only zoom all the way in if the image is at its native scale. Not sure if this is possible with the current system!

Similarly, I'd also like to make it so users can single tap the image to get rid of it. However, that currently seems pretty tricky to do as just using listeners, as it's pretty hard to tap without dragging even slightly. I guess it'd be easy to do a workaround if you could get the start co-ordinates and end co-ordinates of the tap, so you could write a bit of leeway in, but I'm not sure if that sort of information about the image is freely available? (aha, never mind for this one - just found changedTouches[0].clientx in the event - I'm guessing I can use that)

Thanks for the great tool!

Ian

excludeClass - allow elements to be clickable

Can you implement something similar to this feature available in panzoom

"Add class options.excludeClass (default is "panzoom-exclude") to whatever element you want to be clickable. Panzoom will check for this class before handling the event. Alternatively, add a reference to the element to the exclude option, or call event.stopImmediatePropagation() in an event handler on the clickable element."

Zoom mode on double click/tap

Hello! I'm using your library and it's working great!
I saw you have an option to zoom fully on one click, but it's pretty confusing. Nowadays in most images previews we can "enter in zoom mode" when we double click/tap an image.
It would be cool to have a configurable handler in your lib to do that, for example when we double tap the image it just does a zoomUp() and I think that's it.
Thanks!

touch and mouse events

Hello,

I've been testing a lot this past day and I believe the plugin only allows touch or mouse events, never both simultaneously.
Because we have touchscreens, do you think it's possible to allow both simultaneously? It's good also for testing in the Chrome simulator.

.create() should alternatively accept element instead of selector

Hi, thanks for a nice library!

I would suggest to also allow passing the element itself into the WZoom.create() - my use case is that I don't have any fixed selector / ID to my img elements. I can create random ID a put it there but this seems like an unnecessary workaround.

Image position at default

when i change minscale to 2 then it load image from center, how can i position it as y coordinate of image to zero,
i mean default image load position of ycoordinate of image to 0, so that it will show the top portion of image.

ZoomUP() to specific position

Hey there,
Thanks for this great lib!

We use this in a special way and have a small issue.

Whenever the user is dragging the image we zoom in. On release we zoom out.

const zoom = WZoom.create(zoomImage, { dragScrollableOptions: { onGrab: function (e) { zoomImage.style.cursor = "grabbing"; zoom.maxZoomUp(); }, onDrop: function () { if (zoom.content.currentScale === 1) { zoomImage.style.cursor = "grab"; } else { zoomImage.style.cursor = "zoom-in"; } zoom.maxZoomDown(); }, }, zoomOnClick: false, disableWheelZoom: true, maxScale: defaultOptions.maxZoom, minScale: defaultOptions.minZoom });

It would be great to zoom into the image on this position where the user starts grabbing.
Any idea how to solve it with the existing version? Or any chance to get this feature?

not sure how to use with typescript

I've seen you have a index.d.ts which, to me, means that your library supports types for TS.

when using

import WZoom from 'vanilla-js-wheel-zoom'
const wzoom = WZoom.create(img, { maxScale: 10, speed: 5 })

the inferred type of wzoom is any

and when using

import WZoom from 'vanilla-js-wheel-zoom'
const wzoom: WZoom = WZoom.create(img, { maxScale: 10, speed: 5 })

I get the error : Cannot use namespace 'WZoom' as a type

with

import WZoom from 'vanilla-js-wheel-zoom'
const wzoom: InstanceType<typeof WZoom> = WZoom.create(img, { maxScale: 10, speed: 5 })

the inferred type of wzoom is still any

I am not sure what is the proper way to do this

Cannot find module '/src/wheel-zoom.js'.

Importing the library like this way...

import WZoom from 'vanilla-js-wheel-zoom'

I have this error:

Error: Cannot find module '/src/wheel-zoom.js'. Please verify that the package.json has a valid "main" entry

Do you know why this happens?
I think the 'main' entry is correct.

Make disableWheelZoom editable

Nice lib, works really well with html content, great work buddy!

Got a quick question, would it be possible to add a function to toggle wheelZoom after the script have ben initialised? My use case is that I want to require the user to press CMD (on mac) or CTRL (on WIN) to be able to zoom on scroll, if the meta button is not presset I would like the mouse wheel to work like it normally do.

Cheers,
Jonathan

When the image at maxScale is smaller than the viewport

This script is terrific. I'm using it in a custom lightbox.

Although my main interest is to view very large images with particular interest to be seen up close, it is not known ahead of time which images will be shown in it, so some small images will inevitably also be loaded. I do not want the small images (or the large ones) to be zoomed into pixels, so the maxScale option is very handy.

However I have noticed that if the viewport is larger than the (image * maxScale), there is odd behavior:

  • On load, it scales the image to the size of the viewport, which is larger than the max scale.
  • A wheel-zoom action zooms it back down to the max scale in a random (depending on where the mouse is) corner of the viewport.
  • A second wheel-zoom action snaps it back to stretched to the size of the view port.
  • Basically repeated wheel-zoom actions toggle the zoom between max-scale (not centered) and 100% of the viewport (greater than max scale).
  • If the max scale is increased so that the small (image * maxScale) is larger than the viewport, it behaves normally.
  • If the window is resized so that the (responsive) viewport is smaller than the (image * maxScale) and the page is reloaded, it behaves normally

I would have expected that if the image is smaller than the viewport (at max scale), it would be loaded at max scale and centered, with further zoom-in attempts doing nothing (because it's already at max scale).

Is this a known issue/unsupported? Or does it sound like I have done something strange?

For reference, this is effectively how I have it loaded.

      <style>
        #myViewport {
          height: 100%;
          width: 100%;
          background-color: darkkhaki;
          display: flex;
          align-items: center;
          justify-content: center;
          overflow: hidden;
          position: relative;
        }

        #myViewport img {
          cursor: grab;
          position: absolute;
        }
      </style>
      <script src="/assets/js/wheel-zoom.min.js"></script>

      <div id="myViewport">
        <img id="myContent" src="" alt="image" />
      </div>
      <script>
        var zoomContent = document.getElementById('myContent');
        WZoom.create('#myContent',{
          type: 'image',
          zoomOnDblClick: true,
          smoothTime: 0,
          maxScale: 1,
          dragScrollableOptions: {
              onGrab: function () {
                  zoomContent.style.cursor = 'grabbing';
              },
              onDrop: function () {
                  zoomContent.style.cursor = 'grab';
              }
          }
        }); /**/
      </script>

Ability to be destroyed and attached to another div dynamically

Hi,

So I have a carousel of images where a user clicks next to go to the next image. The zoom appears to work when I specify the active image element. But I tried setting the variable to null (to make sure the garbage collection removes it) and re-initialising it when image switches to next one but seems to break in this scenario. Possibility of a .destroy() method?

User can drag image out of its container

In my use case, users can drag the picture out of the designated area, which makes it harder to use for first-time users.

In the demos in the Readme, there is no such issue. For instance, I am not able to drag the picture anymore to the left after the right edge of the picture is at the right border of the container. This is also similar to how Photos work in Windows 10, and that is the desired behavior for me.

What could be the reason of this behavior?

chrome_vuKfoU7i5u

Changing image src

I am trying to change the image source file of a wzoom.
For every time I change the image.src it seems to make the drag more and more sensitive.

I have also tried destroying the wzoom, changing the img.src, and then re-creating the wzoom. When I do this I get the following error

Uncaught TypeError: this._prepare is not a function
    at j._init (wheel-zoom.min.js:1)

Thoughts on how I could accomplish changing the img.src while using a wzoom?

'Zoom to Width' feature

Hi worka,

any advice how to use your library to implement a Zoom to Width feature ?

"Zoom to Width" means making the image as wide as the viewport, maintaining the aspect ratio. It also aligns the top of the image to the top of the viewport.

It should behave the same way regardless of the original size of the image. Sometimes it will zoom in, sometimes it will zoom out

Conflict between vanilla-js-wheel-zoom and the zoom CSS descriptor (also -moz-transform: scale)

There is a conflict between vanilla-js-wheel-zoom script and the zoom CSS descriptor (also -moz-transform: scale). If you use the zoom CSS descriptor (or -moz-transform: scale) to resize elements of a page, the zoom loses it's position when you zoom an element, which makes the image move/disappear outside the container. As a temporary workaround I set the new positions to zero so that it always zooms from the center.

Also, is there a way to send variables into the script? My images are displayed in a loop and I need to send the loop index into the script in order to save the new x,y and scale values into localStorage. Thanks!

value of translate3d changed when click by zoom up

I want to scale only image. Image size is 2082x2596. Visible layout is 960x1024.

Here are my html and less.

<div class="zoom-window-container">
                    <div id="zoomWindow" class="zoom-window" style="cursor: grab;">
                        <img id="metroMap" class="zoom-window__content" src="/uploads/media/metro_timeline/0002/19/87e3974caeaadc5b849f9aed330b07a9c1beb3da.png" style="transform: translate3d(0px, 0px, 0px) scale(0.461095);">
                    </div>
                </div>

less

.zoom-window-container {
  position: relative;
  display: block;
  padding: 0;
  overflow: hidden;

  width: 960px;
  height: 1204px;


  .zoom-window {
    display: flex;
    align-items: center;
    justify-content: center;

    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: 0;

    .zoom-window__content {
      position: relative;
      display: flex;
      align-items: center;
    }

  }
}

I coped this from https://worka.github.io/vanilla-js-wheel-zoom/demo-image.html

But when i click by zoom up, value of transform set up in translate3d(0px, -435.758px, 0px) scale(0.627762);

But in your example it is translate3d(0px, 0px, 0px)

Can you help? Where ir issue?

Callback when max/min scale reached

Hello! We appreciate your work for this lib.
I was wondering if you can add some sort of callback when the max or min scale is reached, for example:
onMaxScaleReached(() => // I want to do something here)

With this feature we give to the lib users the possibility of enabling or disabling the zoom in/out buttons when those events happen which is the use case that I need.
Thanks!

Add wzoom to our single-page app

Hi,

We would like to add wzoom to our app, but unfortunately, we're not very versed in frontend JS.
Would it be possible to ask you to help us create the single-page app?

Not for free, obviously :)

You can contact me on Telegram @velsa

P.S.
Sorry for leaving it as an issue, but that's the only way I found to get in touch with you )
You can remove this issue at any time.

Bug during destroying the widget

I can see, when the widget is created, listeners are attached to this.content.$element

on(this.content.$element, 'wheel', this._wheelHandler);
if (this.options.zoomOnClick) {            
     on(this.content.$element, this.events.down, this._downHandler, this.events.options);           
     on(this.content.$element, this.events.up, this._upHandler, this.events.options);        
}

But when widget is destroyed, they are removed from this.window.$element, which is incorrect

off(this.window.$element, 'wheel', this._wheelHandler);
if (this.options.zoomOnClick) {            
    off(this.window.$element, this.events.down, this._downHandler, this.events.options);            
    off(this.window.$element, this.events.up, this._upHandler, this.events.options);        
}

Finally, when user tries to scroll after destroying the widget, there are errors in the console

vanilla-js-wheel-zoom.js?@@buildnumber:717 Uncaught TypeError: this._computeNewScale is not a function
at WZoom._wheelHandler (vanilla-js-wheel-zoom.js?@@buildnumber:717)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.