npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@voderl/medium-zoom

v1.0.7

Published

A JavaScript library for zooming images like Medium (Enhanced with srcset and source support)

Downloads

3

Readme

CHANGE

  1. optimize the image with srcset loading, avoid being stucked.
  2. add source support. <picture><source /><img /></picture>. it works like srcset

it's recommended to be used in Gatsby. (like what i am doing)

if you meet some condition worked unnormal, please submit issues.

use with Gatsby

  1. install this package
yarn add @voderl/medium-zoom
  1. install gatsby-plugin-images
;[
  {
    resolve: `gatsby-remark-images`,
    options: {
      linkImagesToOriginal: false, // important
    },
  },
]
  1. Copy the following code into gatsby-browser.js
import mediumZoom from '@voderl/medium-zoom'

const options = {
  margin: 24,
  background: '#fff',
  scrollOffset: 40,
  container: undefined,
  template: undefined,
  zIndex: 999,
  excludedSelector: undefined,
  respectSrcsetImageSize: true,
}

export const onClientEntry = () => {
  const { zIndex } = options

  const styles = `
    .medium-zoom-overlay, .medium-zoom-image--opened {
      z-index: ${zIndex};
    }
  `

  const node = document.createElement(`style`)
  node.id = `medium-zoom-styles`
  node.innerHTML = styles
  document.head.appendChild(node)
}

export const onRouteUpdate = () => {
  mediumZoom('.gatsby-resp-image-image', options)
}

Features

  • 📱 Responsivescale on mobile and desktop
  • 🚀 Performant and lightweightshould be able to reach 60 fps
  • ⚡️ High definition supportload the HD version of your image on zoom
  • 🔎 Flexibilityapply the zoom to a selection of images
  • 🖱 Mouse, keyboard and gesture friendlyclick anywhere, press a key or scroll away to close the zoom
  • 🎂 Event handlingtrigger events when the zoom enters a new state
  • 📦 Customizationset your own margin, background and scroll offset
  • 🔧 Pluggableadd your own features to the zoom
  • 💎 Custom templatesextend the default look to match the UI of your app

Installation

The module is available on the npm registry.

npm install medium-zoom
# or
yarn add medium-zoom
Download
CDN

Usage

Try it out in the browser

Import the library as a module:

import mediumZoom from 'medium-zoom'

Or import the library with a script tag:

<script src="node_modules/medium-zoom/dist/medium-zoom.min.js"></script>

That's it! You don't need to import any CSS styles.

Assuming you add the data-zoomable attribute to your images:

mediumZoom('[data-zoomable]')

API

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 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 → | | template | string | HTMLTemplateElement | null | The template element to display on zoom Read more → |

mediumZoom('[data-zoomable]', {
  margin: 24,
  background: '#BADA55',
  scrollOffset: 0,
  container: '#zoom-container',
  template: '#zoom-template',
})

Methods

open({ target?: HTMLElement }): Promise<Zoom>

Opens the zoom and returns a promise resolving with the zoom.

const zoom = mediumZoom('[data-zoomable]')

zoom.open()

Emits an event open on animation start and opened when completed.

close(): Promise<Zoom>

Closes the zoom and returns a promise resolving with the zoom.

const zoom = mediumZoom('[data-zoomable]')

zoom.close()

Emits an event close on animation start and closed when completed.

toggle({ target?: HTMLElement }): Promise<Zoom>

Opens the zoom when closed / dismisses the zoom when opened, and returns a promise resolving with the zoom.

const zoom = mediumZoom('[data-zoomable]')

zoom.toggle()

attach(...selectors: string[] | HTMLElement[] | NodeList[] | Array[]): Zoom

Attaches the images to the zoom and returns the zoom.

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.

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 on the image.

update(options: object): Zoom

Updates the options and returns the zoom.

const zoom = mediumZoom('[data-zoomable]')

zoom.update({ background: '#BADA55' })

Emits an event update 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.

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 are used.

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 are used.

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.

const zoom = mediumZoom({ background: '#BADA55' })

zoom.getOptions() // => { background: '#BADA55', ... }

getImages(): HTMLElement[]

Returns the images attached to the zoom as an array of HTMLElements.

const zoom = mediumZoom('[data-zoomable]')

zoom.getImages() // => [HTMLElement, HTMLElement]

getZoomedImage(): HTMLElement

Returns the current zoomed image as an HTMLElement or null if none.

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.

<img src="image-thumbnail.jpg" data-zoom-src="image-hd.jpg" alt="My image" />

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 |

const zoom = mediumZoom('[data-zoomable]')

zoom.on('open', event => {
  // track when the image is zoomed
})

The zoom object is accessible in event.detail.zoom.

Examples

const button = document.querySelector('[data-action="zoom"]')
const zoom = mediumZoom('#image')

button.addEventListener('click', () => zoom.open())

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.

let counter = 0
const zoom = mediumZoom('#image-tracked')

zoom.on('open', event => {
  console.log(`"${event.target.alt}" has been zoomed ${++counter} times`)
})
const zoom = mediumZoom('[data-zoomable]')

zoom.on('closed', () => zoom.detach(), { once: true })

jQuery elements are compatible with medium-zoom once converted to an array.

mediumZoom($('[data-zoomable]').toArray())

Using React hooks

import React from 'react'
import mediumZoom from 'medium-zoom'

function ImageZoom({ zoom, src, alt, background }) {
  const zoomRef = React.useRef(zoom.clone({ background }))

  function attachZoom(image) {
    zoomRef.current.attach(image)
  }

  return <img src={src} alt={alt} ref={attachZoom} />
}

function App() {
  const zoom = React.useRef(mediumZoom({ background: '#000', margin: 48 }))

  render() {
    return (
      <ImageZoom src="image.jpg" alt="Image" zoom={zoom.current} color="#BADA55" />
    )
  }
}

Using React classes

import React, { Component } from 'react'
import mediumZoom from 'medium-zoom'

class ImageZoom extends Component {
  zoom = this.props.zoom.clone({
    background: this.props.color,
  })

  attachZoom = image => {
    this.zoom.attach(image)
  }

  render() {
    return (
      <img src={this.props.src} alt={this.props.alt} ref={this.attachZoom} />
    )
  }
}

class App extends Component {
  zoom = mediumZoom({ background: '#000', margin: 48 })

  render() {
    return (
      <ImageZoom src="image.jpg" alt="Image" zoom={this.zoom} color="#BADA55" />
    )
  }
}

You can see more examples including React and Vue, or check out the storybook.

Debugging

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:

.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 when using custom templates.

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:9001

Please read the contributing guidelines for more detailed explanations.

You can also use npm.

License

MIT © François Chalifour