Coder Social home page Coder Social logo

mvoloskov / fast-image-zoom Goto Github PK

View Code? Open in Web Editor NEW
40.0 1.0 3.0 90 KB

๐Ÿž Fast image zoom on click as seen on a popular publishing platform

Home Page: https://miloslav.website/fast-image-zoom

License: Boost Software License 1.0

JavaScript 64.66% HTML 35.34%

fast-image-zoom's Introduction

Dependencies npm License

Demo ย ย โ€ขย ย  Configuration

๐Ÿž Fast Image Zoom

Image zoom on click as seen on the popular publishing platform.

What does it do?

You click on an image and it smoothly zooms in or out to fit the screen. You click again โ€” it smoothly goes back to normal. You scroll โ€” it also goes back.

Why is it better than alternatives?

  • ๐Ÿ›  Framework-agnostic โ€” works with everything from Knockout.js to Web Components
  • ๐Ÿ‘Œ Zero-dependency
  • ๐Ÿงฌ Perfect for dynamic content, mutation-agnostic โ€” you can do whatever you want with images, it'll work
  • โšก๏ธ Blazing fast โ€” no matter if it's 10 images or 10000, it uses only two event listeners. Not per image, just two listeners. Complexity is always O(1)
  • ๐Ÿค“ Powered by quirky math to precisely calculate everything and do the trick with only one transformation
  • ๐Ÿฆ‹ Looks good on both dark and light modes
  • ๐Ÿฆ Zero-configuration by default but extensible when you need it
  • ๐Ÿ—ฟ Works flawlessly even on iOS Safari, in every orientation, with every image no matter the size and dimensions

Basic usage

npm install fast-image-zoom --save

or

yarn add fast-image-zoom
import imageZoom from 'fast-image-zoom'
imageZoom()

Alternative โ€” use CDN

<script src="https://unpkg.com/[email protected]/dist/fast-image-zoom.js"></script>
<script>
  imageZoom()
</script>

That's it!

How it works

Plugin targets meaningful, content images:

<!-- yes -->
<img src="foo.jpg" alt="Cute kitten" />

<!-- no -->
<img src="bar.jpg" />
<img src="bar.jpg" alt="" />

Configuration

Here are the defaults:

imageZoom({
    selector: `img[alt]:not([alt=""]):not([data-image-zoom-disabled])`,
    containerSelector: null,
    cb: () => {},
    exceed: false,
    padding: 20,
})
  • selector (string) is used to target images. By default it only targets meaningful images (e.g. ones with alt), so your icons won't be magnified on click.

  • containerSelector limits plugin's scope to a certain element. It's useful for modals. Only the images inside that element will be clickable, and the scroll handler that un-zooms images will work on that element only.

  • cb (function) is called after the plugin is initialized.

  • exceed (boolean) defines whether images should exceed their natural size when zoomed. For example, if you zoom 100x100 image on a 1080p screen with exceed: false, its final size will be 100px, meanwhile, with exceed: true it will be 1080px.

  • padding (integer) defines a gap in pixels between a zoomed image and the closest edge of the viewport.

Note that if exceed is false and smaller images appear to have a larger gap between their edges and the edge of the viewport, padding won't be added. For example, if you zoom a 100x100 image on a 1080p screen and your padding is set to 20, a natural gap between an image and the viewport edge would be (1080 - 100) / 2 = 490, thus there is no need to add that 20px gap.

Only pixels are supported by now.

Setting exceed per image

You can explicitly define exceed for a specific picture via a data attribute:

<img src="..." alt="..." data-image-zoom-exceed="true">

Disabling the plugin for the specific image

You can disable zooming for any image you like, even if it has alt:

<img src="..." alt="..." data-image-zoom-disabled>

Note that if you redefine the selector in a way that doesn't account data-image-zoom-disabled attribute, this feature will stop working.

Restyling

You can always hack the plugin redefining straightforward CSS:

Changing a timing function

.image-zoom,
.image-zoom-wrapper::after {
    transition-timing-function: ease-in-out;
}

Changing the background color

.image-zoom-wrapper::after {
    background-color: hotpink;
}

For now, !important might be needed, as styles are injected into <head>. This will probably be changed in the future.

Anatomy

  • .image-zoom-wrapper โ€” element that wraps every image. Mimics its display property. We use it to add page background and slightly separate the zoomed image from what's behind it.
  • .image-zoom-wrapper-zoomed โ€” the same wrapper but for when the image is zoomed.
  • .image-zoom โ€” the image itself that was processed and is interactive, ready to zoom.
  • .image-zoom-zoomed โ€” zoomed image.

Disabling the plugin

Being called, the plugin returns the destroy function that you may call to remove event listeners. It will also remove related styles from <head> and from the images themselves.

const destroy = imageZoom()

// don't need it anymore
destroy()

Limitations

  • img inline styles will be overwritten. Use CSS selectors to stylize images.
  • img shouldn't have transforms. If needed, wrap it with a container and apply transforms there instead.
  • Container's overflow-x will be hidden. If containerSelector is null, then overflow-x will be hidden for the root element.

Enjoy!

fast-image-zoom's People

Contributors

josh- avatar miloxeon 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

Watchers

 avatar

fast-image-zoom's Issues

scroll listener

Sometimes we wrap our main app into another container (left sidebar and content box to the right). The lib works well if the image is placed into the body, but if placed into another container the scroll listener that un-zoom's the image doesn't work. A fix for this would be to pass the element that we want the lib to listen for scroll events.

This are the parts of the lib that need to be modified for this to work:

  const destroy = () => {
    document.body.removeEventListener("click", handleClick);
    document
      .querySelector(".fast-image-zoom-content")
      ?.addEventListener("scroll", handleUnzoomingInteraction);
    //window.removeEventListener("scroll", handleUnzoomingInteraction);
    window.removeEventListener("resize", handleUnzoomingInteraction);
    document.removeEventListener("keydown", handleKeydown);
    document.head.removeChild(
      document.getElementById("image-zoom-styles") as Node
    );
  };
  const start = () => {
    injectStyles(styles);

    getImages().forEach(processImage);

    document.body.addEventListener("click", handleClick);
    document
      .querySelector(".fast-image-zoom-content")
      ?.addEventListener("scroll", handleUnzoomingInteraction);
    //window.addEventListener("scroll", handleUnzoomingInteraction);
    document.querySelector("fast-image-zoom-content");
    window.addEventListener("resize", handleUnzoomingInteraction);
    document.addEventListener("keydown", handleKeydown);

    cb();
  };

SyntaxError: Cannot use import statement outside a module

I am trying to use fast-image-zoom in my React/Next.js app & I get the following error:

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:353:18)
    at wrapSafe (node:internal/modules/cjs/loader:1039:15)
    at Module._compile (node:internal/modules/cjs/loader:1073:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1138:10)
    at Module.load (node:internal/modules/cjs/loader:989:32)
    at Function.Module._load (node:internal/modules/cjs/loader:829:14)
    at Module.require (node:internal/modules/cjs/loader:1013:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at Object.fast-image-zoom (my-app\.next\server\pages\_app.js:20969:18)
    at __webpack_require__ (my-app\.next\server\webpack-runtime.js:25:42)
my-app\node_modules\fast-image-zoom\src\index.js:1
import styles from './styles'
^^^^^^

I've made a reproduction here -> https://stackblitz.com/edit/nextjs-edw9pk?file=pages%2F_app.js

You can uncomment the 2 lines in pages/_app.js to see the errors.

How can I solve it?

Is there lazy loading and thumbnails support?

Sorry if this seems like either an outdated question (I haven't dabbled in websites in several years) or an out of scope question:

Do I understand it correctly that it's the same image when displayed small, as when zoomed in?

If not, where do you define what image should be loaded when you zoom, and there's no mention of fading/spinner to go between the thumbnail and the zoomed image while it is loading?

WordPress tutorial

Hey

I am looking into modifying my WordPress tutorial:
https://www.easywebdesigntutorials.com/adding-a-lightbox-to-wordpress-without-using-a-plugin/

Check out the colorbox lightbox setup method I used. Of the various lightboxes I shared there colorbox works straight out of the box so to speak.

I am curious if you are interested in helping me get fast-image-zoom working in a similar way as colorbox? If I get it to work then I can also add fast-image-zoom to the modified version of the tutorial. If you are interested in helping out then I will need step by step advice on getting it to work.

Thanks!

Image max size

Hi ๐Ÿ‘‹,

I'd like to know if there's an option to limit the zoom of the image to 100% of its real size. When using huge resolution, images are excessively zoomed.

Thanks for the work ๐Ÿ‘

Module parse failed: Unexpected token (51:54)

Hi there,

I'm running into an issue when trying to use your image zoom plugin. If I try and use the import method that is illustrated in your Basic usage example I get the following error:

ERROR in ./node_modules/fast-image-zoom/src/lib.js 51:54
Module parse failed: Unexpected token (51:54)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|   const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0);
|   const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
>   const shouldExceed = config.exceed || image.dataset?.imageZoomExceed === 'true';
|   let scale = getScale(imageHeight, imageWidth, vh, vw);
| 
 @ ./node_modules/fast-image-zoom/src/index.js 2:0-85 18:22-30 22:6-17 29:8-20 32:6-15 39:4-15 48:6-17 62:4-16 63:24-36
 @ ./src/js/c-ImageAndZoom.js
 @ ./src/js/modules.js
 @ ./src/index.js
 @ multi ./src/sass/main.scss ./src/index.js

However if I use your cdn example I don't get the error, which I'm assuming is because the cdn is using a minfied file.

Im just wondering if you have come across this issue before and know of a solution as I would prefer to use the import approach in my project if possible.

Cheers
Jack

Overlapping images

Hi again!
I have infinite grid canvas with images which wrapped in containers with transformation.
Zoom works fine, but in zoomed state image overlapping with grid:
Screenshot 2023-05-30 135905
Screenshot 2023-05-30 135521

I tried to change z-index and other settings of wrapper and .image-zoom-zoomed class but seems problem is more sophisticated.
So, maybe you have some ideas how to fix this, or where to look at the problem?

As base for the canvas i used this code: https://codepen.io/radixzz/pen/eRJKXy

Pinch to zoom further

The plugin is really excellent. As the zoom feels like a mobile phone photoviewer, would it perhaps be possible to allow further zooming in/out using pinch gestures on a trackpad or mobile device, or perhaps ctrl/command + scroll on a desktop?

[Snippet/Feature Request] Escape Keybind

A quick integration with Mousetrap.JS to add an escape keybind. Something I find useful on Medium but not in the vanilla script.

Mousetrap.bind('esc',function () {  try { document.getElementsByClassName('image-zoom-wrapper-zoomed')[0].click() } catch(e) {} });

Bottom padding

Hi, great thing, exactly what i needed, thank you!

I want to make asymmetrical zoom, but i can't set custom bottom-padding.
Is there a way to do this with css?

caption like medium?

this is a great plugin & i would love to see if there's a way to add caption to it?

right below the image, there should be a place where caption is shown using alt attribute.

something like data-caption=true on img to show caption that is the same as alt :)

Thoughts when using Framer Motion?

Hey @mvoloskov so I'm using fast-image-zoom & love it but the zoom-in & zoom-out cursors are blurry. Mostly because they are not SVG but rather cursors. They are also blurry on Medium.

I had a thought. What if I use Framer Motion to zoom-in & zoom-out images rather than using this library? Any pros & cons as you've probably spent more time than me thinking about this problem?

Slideshow

Any chance you could make a slideshow out of a set of images with the same .classname - once you are in the light box view?

HTML Videos support

Hello, this plugin is perfect but i would like to know if it's possible to support html videos.
It would be really nice if these videos had the same zoom effect as the rest of the images on the page.

I tried to do it myself (unmute/mute autoplayed videos on zoom/unzoom) but I'm having trouble with safari/firefox ios (no event fired on html videos).

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.