Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/francoischalifour/medium-zoom
ππΌ A JavaScript library for zooming images like Medium
https://github.com/francoischalifour/medium-zoom
event image image-zoom javascript medium no-dependencies performance picture ux vanilla vanilla-javascript zoom zoomable zooming
Last synced: 4 days ago
JSON representation
ππΌ A JavaScript library for zooming images like Medium
- Host: GitHub
- URL: https://github.com/francoischalifour/medium-zoom
- Owner: francoischalifour
- License: mit
- Created: 2016-07-26T20:48:35.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2024-07-24T21:21:36.000Z (5 months ago)
- Last Synced: 2024-11-20T11:47:28.355Z (23 days ago)
- Topics: event, image, image-zoom, javascript, medium, no-dependencies, performance, picture, ux, vanilla, vanilla-javascript, zoom, zoomable, zooming
- Language: JavaScript
- Homepage: https://medium-zoom.francoischalifour.com
- Size: 22.6 MB
- Stars: 3,680
- Watchers: 20
- Forks: 163
- Open Issues: 47
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
- awesome-list - medium-zoom
- awesome-star-libs - francoischalifour / medium-zoom
- awesome - francoischalifour/medium-zoom - ππΌ A JavaScript library for zooming images like Medium (JavaScript)
- awesome - francoischalifour/medium-zoom - ππΌ A JavaScript library for zooming images like Medium (JavaScript)
README
medium-zoom
A JavaScript library for zooming images like Medium
π¬ Playground γ»
π Demo γ»
π Storybook
Contents
- [Features](#features)
- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
- [Selectors](#selectors)
- [Options](#options)
- [Methods](#methods)
- [Attributes](#attributes)
- [Events](#events)
- [Framework integrations](#framework-integrations)
- [Examples](#examples)
- [Debugging](#debugging)
- [Browser support](#browser-support)
- [Contributing](#contributing)
- [License](#license)## Features
- π± **Responsive** β scale on mobile and desktop
- π **Performant and lightweight** β optimized to reach 60 [fps](https://en.wikipedia.org/wiki/Framerate)
- β‘οΈ **High definition support** β load the HD version of your image on zoom
- π **Flexibility** β apply the zoom to a selection of images
- π± **Mouse, keyboard and gesture friendly** β click anywhere, press a key or scroll away to close the zoom
- π **Event handling** β trigger events when the zoom enters a new state
- π¦ **Customization** β set your own margin, background and scroll offset
- π§ **Pluggable** β add your own features to the zoom
- π **Custom templates** β extend the default look to match the UI of your app
- π [**Framework agnostic**](#framework-integrations) β works with React, Vue, Angular, Svelte, Solid, etc.## Installation
The module is available on the [npm](https://www.npmjs.com) registry.
```sh
npm install medium-zoom
# or
yarn add medium-zoom
```###### Download
- [Normal](https://cdn.jsdelivr.net/npm/medium-zoom/dist/medium-zoom.js)
- [Minified](https://cdn.jsdelivr.net/npm/medium-zoom/dist/medium-zoom.min.js)###### CDN
- [jsDelivr](https://www.jsdelivr.com/package/npm/medium-zoom)
- [unpkg](https://unpkg.com/medium-zoom/)
- [esm.sh](https://esm.sh/medium-zoom)## Usage
> [Try it out in the browser](https://codesandbox.io/s/github/francoischalifour/medium-zoom/tree/master/website)
Import the library as a module:
```js
import mediumZoom from 'medium-zoom'
```Or import the library with a script tag:
```html
```
That's it! You don't need to import any CSS styles.
Assuming you add the `data-zoomable` attribute to your images:
```js
mediumZoom('[data-zoomable]')
```> [!TIP]
> If you want to control when to inject the Medium Zoom CSS styles, you can use the pure JavaScript bundle:
>
> ```js
> import mediumZoom from 'medium-zoom/dist/pure'
> import 'medium-zoom/dist/style.css'
> ```## API
```ts
mediumZoom(selector?: string | HTMLElement | HTMLElement[] | NodeList, options?: object): Zoom
```### Selectors
The selector allows attaching images to the zoom. It can be of the following types:
- [CSS selectors](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors)
- [`HTMLElement`](https://developer.mozilla.org/docs/Web/API/HTMLElement)
- [`NodeList`](https://developer.mozilla.org/docs/Web/API/NodeList)
- [`Array`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)```js
// CSS selector
mediumZoom('[data-zoomable]')// HTMLElement
mediumZoom(document.querySelector('#cover'))// NodeList
mediumZoom(document.querySelectorAll('[data-zoomable]'))// Array
const images = [
document.querySelector('#cover'),
...document.querySelectorAll('[data-zoomable]'),
]mediumZoom(images)
```### Options
The options enable the customization of the zoom. They are defined as an object with the following properties:
| Property | Type | Default | Description |
| -------------- | ------------------------------------- | -------- | --------------------------------------------------------------------------- |
| `margin` | `number` | `0` | The space outside the zoomed image |
| `background` | `string` | `"#fff"` | The background of the overlay |
| `scrollOffset` | `number` | `40` | The number of pixels to scroll to close the zoom |
| `container` | `string` \| `HTMLElement` \| `object` | `null` | The viewport to render the zoom in
[Read more β](docs/container.md) |
| `template` | `string` \| `HTMLTemplateElement` | `null` | The template element to display on zoom
[Read more β](docs/template.md) |```js
mediumZoom('[data-zoomable]', {
margin: 24,
background: '#BADA55',
scrollOffset: 0,
container: '#zoom-container',
template: '#zoom-template',
})
```### Methods
#### `open({ target?: HTMLElement }): Promise`
Opens the zoom and returns a promise resolving with the zoom.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.open()
```_Emits an event [`open`](#events) on animation start and [`opened`](#events) when completed._
#### `close(): Promise`
Closes the zoom and returns a promise resolving with the zoom.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.close()
```_Emits an event [`close`](#events) on animation start and [`closed`](#events) when completed._
#### `toggle({ target?: HTMLElement }): Promise`
Opens the zoom when closed / dismisses the zoom when opened, and returns a promise resolving with the zoom.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.toggle()
```#### `attach(...selectors: string[] | HTMLElement[] | NodeList[] | Array[]): Zoom`
Attaches the images to the zoom and returns the zoom.
```js
const zoom = mediumZoom()zoom.attach('#image-1', '#image-2')
zoom.attach(
document.querySelector('#image-3'),
document.querySelectorAll('[data-zoomable]')
)
```#### `detach(...selectors: string[] | HTMLElement[] | NodeList[] | Array[]): Zoom`
Releases the images from the zoom and returns the zoom.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.detach('#image-1', document.querySelector('#image-2')) // detach two images
zoom.detach() // detach all images
```_Emits an event [`detach`](#events) on the image._
#### `update(options: object): Zoom`
Updates the options and returns the zoom.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.update({ background: '#BADA55' })
```_Emits an event [`update`](#events) on each image of the zoom._
#### `clone(options?: object): Zoom`
Clones the zoom with provided options merged with the current ones and returns the zoom.
```js
const zoom = mediumZoom('[data-zoomable]', { background: '#BADA55' })const clonedZoom = zoom.clone({ margin: 48 })
clonedZoom.getOptions() // => { background: '#BADA55', margin: 48, ... }
```#### `on(type: string, listener: () => void, options?: boolean | AddEventListenerOptions): Zoom`
Registers the listener on each target of the zoom.
The same `options` as [`addEventListener`](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener#Parameters) are used.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.on('closed', event => {
// the image has been closed
})zoom.on(
'open',
event => {
// the image has been opened (tracked only once)
},
{ once: true }
)
```The zoom object is accessible in `event.detail.zoom`.
#### `off(type: string, listener: () => void, options?: boolean | AddEventListenerOptions): Zoom`
Removes the previously registered listener on each target of the zoom.
The same `options` as [`removeEventListener`](https://developer.mozilla.org/docs/Web/API/EventTarget/removeEventListener#Parameters) are used.
```js
const zoom = mediumZoom('[data-zoomable]')function listener(event) {
// ...
}zoom.on('open', listener)
// ...
zoom.off('open', listener)
```The zoom object is accessible in `event.detail.zoom`.
#### `getOptions(): object`
Returns the zoom options as an object.
```js
const zoom = mediumZoom({ background: '#BADA55' })zoom.getOptions() // => { background: '#BADA55', ... }
```#### `getImages(): HTMLElement[]`
Returns the images attached to the zoom as an array of [`HTMLElement`s](https://developer.mozilla.org/docs/Web/API/HTMLElement).
```js
const zoom = mediumZoom('[data-zoomable]')zoom.getImages() // => [HTMLElement, HTMLElement]
```#### `getZoomedImage(): HTMLElement`
Returns the current zoomed image as an [`HTMLElement`](https://developer.mozilla.org/docs/Web/API/HTMLElement) or `null` if none.
```js
const zoom = mediumZoom('[data-zoomable]')zoom.getZoomedImage() // => null
zoom.open().then(() => {
zoom.getZoomedImage() // => HTMLElement
})
```### Attributes
#### `data-zoom-src`
Specifies the high definition image to open on zoom. This image loads when the user clicks on the source image.
```html
```### Events
| Event | Description |
| ------ | --------------------------------------------------- |
| open | Fired immediately when the `open` method is called |
| opened | Fired when the zoom has finished being animated |
| close | Fired immediately when the `close` method is called |
| closed | Fired when the zoom out has finished being animated |
| detach | Fired when the `detach` method is called |
| update | Fired when the `update` method is called |```js
const zoom = mediumZoom('[data-zoomable]')zoom.on('open', event => {
// track when the image is zoomed
})
```The zoom object is accessible in `event.detail.zoom`.
## Framework integrations
Medium Zoom is a JavaScript library that can be used with any framework. Here are some integrations that you can use to get started quickly:
- [React](./examples/react)
- [React Markdown](./examples/react-markdown)
- [Vue](./examples/vue)
- [Svelte](./examples/svelte)## Examples
Trigger a zoom from another element
```js
const button = document.querySelector('[data-action="zoom"]')
const zoom = mediumZoom('#image')button.addEventListener('click', () => zoom.open())
```Track an event (for analytics)
You can use the `open` event to keep track of how many times a user interacts with your image. This can be useful if you want to gather some analytics on user engagement.
```js
let counter = 0
const zoom = mediumZoom('#image-tracked')zoom.on('open', event => {
console.log(`"${event.target.alt}" has been zoomed ${++counter} times`)
})
```Detach a zoom once closed
```js
const zoom = mediumZoom('[data-zoomable]')zoom.on('closed', () => zoom.detach(), { once: true })
```Attach jQuery elements
jQuery elements are compatible with `medium-zoom` once converted to an array.
```js
mediumZoom($('[data-zoomable]').toArray())
```Create a zoomable React component
```js
import React, { useRef } from 'react'
import mediumZoom from 'medium-zoom'export function ImageZoom({ options, ...props }) {
const zoomRef = useRef(null)function getZoom() {
if (zoomRef.current === null) {
zoomRef.current = mediumZoom(options)
}return zoomRef.current
}function attachZoom(image) {
const zoom = getZoom()if (image) {
zoom.attach(image)
} else {
zoom.detach()
}
}return
}
```
You can see [more examples](examples/) including [React](examples/react) and [Vue](examples/vue), or check out the [storybook](https://medium-zoom.francoischalifour.com/storybook).
## Debugging
### The zoomed image is not visible
The library doesn't provide a `z-index` value on the zoomed image to avoid conflicts with other frameworks. Some frameworks might specify a `z-index` for their elements, which makes the zoomed image not visible.
If that's the case, you can provide a `z-index` value in your CSS:
```css
.medium-zoom-overlay,
.medium-zoom-image--opened {
z-index: 999;
}
```## Browser support
| IE | Edge | Chrome | Firefox | Safari |
| --------------- | --------------- | ------ | ------- | ------ |
| 10\* | 12\* | 36 | 34 | 9 |\* _These browsers require a [`template` polyfill](https://github.com/webcomponents/template) when using [custom templates](docs/template.md)_.
Cross-browser testing is sponsored by
## Contributing
- Run `yarn` to install Node dev dependencies
- Run `yarn start` to build the library in watch mode
- Run `yarn run storybook` to see your changes at http://localhost:9001Please read the [contributing guidelines](CONTRIBUTING.md) for more detailed explanations.
_You can also use [npm](https://www.npmjs.com)._
## License
MIT © [François Chalifour](https://francoischalifour.com)