Skip to content

Repository files navigation

SmartPhoto

npm versionnpm downloadGitHub license

The most easy to use responsive image viewer especially for mobile devices

See https://appleple.github.io/SmartPhoto/ for complete docs and demos
If you are Japasese, See here https://www.appleple.com/blog/javascript/smartphoto-js.html instead.

Feature

  • Intuitive gestures such as pinch-in/pinch-out/drag/swipe
  • Use Accelerometer to move images
  • Accessible from keyboards and screen-readers
  • Show pictures via URL hash
  • Can make photo groups

Installation

via npm

npm install smartphoto --save

or yarn

yarn add smartphoto

Usage

require

constSmartPhoto=require('smartphoto');

smartphoto.js

document.addEventListener('DOMContentLoaded',function(){newSmartPhoto(".js-smartphoto");});

jquery-smartphoto.js

$(function(){$(".js-smartphoto").SmartPhoto();});

Basic Standalone Usage

<ahref="./assets/large-bear.jpg" class="js-smartphoto" data-caption="bear" data-id="bear" data-group="0"><imgsrc="./assets/bear.jpg" width="360"/></a><ahref="./assets/large-camel.jpg" class="js-smartphoto" data-caption="camel" data-id="camel" data-group="0"><imgsrc="./assets/camel.jpg" width="360"/></a><ahref="./assets/large-rhinoceros.jpg" class="js-smartphoto" data-caption="rhinoceros" data-id="sai" data-group="0"><imgsrc="./assets/rhinoceros.jpg" width="360"/></a><linkrel="stylesheet" href="./css/smartphoto.min.css"><scriptsrc="./js/smartphoto.js"></script><script>document.addEventListener('DOMContentLoaded',function(){newSmartPhoto(".js-smartphoto");});</script>

When SmartPhoto is constructed with a CSS selector string (as above), clicks are handled via a single delegated listener, so elements added to the page after construction (e.g. by Ajax/infinite scroll) are picked up automatically just by clicking them — no need to call addItem()/addNewItem() manually. Right before a photo is opened, SmartPhoto also reconciles that photo's group against the current DOM: newly appended matching elements are added, and elements that have since been removed from the DOM are dropped from the group (remaining indices are recalculated). This auto-detection only applies to the selector-string form; when a NodeList/Element[] is passed (or in data source mode below), add/remove items explicitly via addItem()/addNewItem().

A few things to keep in mind:

  • Reconciliation only happens right before a photo is opened (via a click, show(), or hash restoration) — not continuously. If an element disappears from the DOM while the viewer is already open and you next()/prev() through the same session, that removal isn't reflected until the viewer is opened again.
  • It does not support replacing an entire container's innerHTML (which recreates existing elements too, as brand-new DOM nodes) — that produces duplicate items, since the old and new elements aren't recognized as the same one. Only appending/removing individual elements is supported; if you regenerate the whole container, call destroy() and construct a new instance instead.
  • Changing data-group on an element that has already been opened/registered has no effect (the group is fixed at first registration). Changing it before the element is first interacted with is picked up correctly.
  • If multiple instances are built with overlapping selectors, avoid relying on distinguishing exactly which instance handles a click for elements that could match either.

Programmatic usage (data source mode)

Instead of scanning <a> elements in the page, you can pass an array of slide objects directly (inspired by yet-another-react-lightbox). This is useful when your images come from an API or a JS-rendered list.

constphoto=newSmartPhoto([{src: "/img/bear-large.jpg",thumb: "/img/bear.jpg",caption: "bear",id: "bear"},{src: "/img/camel-large.jpg",thumb: "/img/camel.jpg",caption: "camel",id: "camel",width: 1200,height: 800},]);photo.show(0);// open by indexphoto.show("camel");// or by idphoto.next();photo.prev();photo.hide();photo.on("change",()=>{/* ... */});// same event contract as HTML mode

Slide fields:

fieldrequireddescription
srcyesfull-size image URL (equivalent to href in HTML mode)
thumbnothumbnail URL used in the nav strip. Falls back to src
captionnocaption text (equivalent to data-caption)
altnoimage alt text. Falls back to caption, then src
idnoidentifier used by show(id) and the URL hash. Falls back to the index
groupnogroup name (equivalent to data-group). Falls back to "nogroup"
width / heightnonatural image size in px. When given, SmartPhoto skips the preload used to measure the image

show(indexOrId, options) also accepts options.group (which group to open) and options.trigger (the element to animate from / return focus to). Both HTML mode and data source mode share the exact same public API, options, and events.

Option

variabledescriptiondefault
arrowsprev/next arrowstrue
navnavigation images at the bottomtrue
showAnimationanimate the open/close transitiontrue
verticalGravityapply device-tilt gravity to the vertical axis too (in addition to horizontal)false
useOrientationApiuse the accelerometer (deviceorientation) to move a zoomed imagefalse
useHistoryApiupdate the URL hash (#group=…&photo=…) via the History APItrue
swipeTopToCloseclose the viewer on an upward swipefalse
swipeBottomToCloseclose the viewer on a downward swipetrue
swipeOffsetminimum swipe distance (px) to trigger navigation/close100
swipeVelocityminimum swipe speed (px/ms) that triggers navigation even below swipeOffset (fast flicks)0.5
headerHeightheight (px) reserved for the header when fitting images60
footerHeightheight (px) reserved for the footer when fitting images60
resizeStyleresize images to fill/fit on the screen'fit'
animationSpeedanimation speed (ms) when switching/opening/closing images450
forceIntervalfrequency (ms) to apply force to images10
registancefriction applied to the inertia scroll of a zoomed image0.5
loadOffsetnumber of neighboring slides to preload around the current one2
lazyAttributeattribute read for a lazy-loaded thumbnail (HTML mode only)'data-src'
classNamesoverride any of the generated CSS class namessee source
messageoverride screen-reader text (gotoNextImage / gotoPrevImage / closeDialog / carouselLabel)see source

Hide parts

document.addEventListener('DOMContentLoaded',function(){newSmartPhoto(".js-smartphoto",{arrows: false,nav: false});});

Fit/Fill Option

You can choose if you want to scale images to fit/fill

document.addEventListener('DOMContentLoaded',function(){newSmartPhoto(".js-smartphoto",{resizeStyle: 'fit'});});

Event

// when the modal openedphoto.on('open',function(){console.log('open');});// when the modal closedphoto.on('close',function(){console.log('close');});// when all images are loadedphoto.on('loadall',function(){console.log('loadall');});// when photo is changedphoto.on('change',function(){console.log('change');});// when swipe startedphoto.on('swipestart',function(){console.log('swipestart');});// when swipe endedphoto.on('swipeend',function(){console.log('swipeend');});// when zoomed inphoto.on('zoomin',function(){console.log('zoomin');});// when zoomed outphoto.on('zoomout',function(){console.log('zoomout');});

Methods

methoddescription
on(event, listener)subscribe to one of the events listed above
destroy()remove the viewer and all of its event listeners
[Symbol.dispose]()same as destroy(). Lets a using declaration destroy the instance automatically when it goes out of scope: { using photo = new SmartPhoto(...); }
gotoSlide(index)go to the slide at index within the current group
hidePhoto(dir?)close the viewer. dir is 'bottom' (default) or 'top' and controls the close animation direction
zoomPhoto() / zoomOutPhoto()zoom the current image in/out programmatically
addNewItem(element)register a new <a> thumbnail element (HTML mode). Only needed when constructed with a NodeList/Element[] or otherwise not using a selector string — with a selector string, elements added later are auto-detected on click (see above)
show(indexOrId?, options?)open the viewer, by index or id. Works in both HTML mode and data source mode. options.group picks the group; options.trigger sets the element to animate from and to return focus to
hide()alias of hidePhoto()
next() / prev()go to the next/previous slide. No-op at the start/end of the group
addItem(slideOrElement)add a new item. Accepts a slide object (data source mode, where explicit registration is always required) or an Element (HTML mode, same caveat as addNewItem)
currentIndex(getter) the index currently displayed within its group

CSS Custom Properties

propertydescriptiondefault
--smartphoto-animation-speedanimation speed when switching/opening/closing images. Overridden per-instance by the animationSpeed JS option450ms
--smartphoto-animation-functioneasing function used for animationsease-out
--smartphoto-backdrop-colorbackdrop color when viewing imagesrgba(0, 0, 0, 1)
--smartphoto-header-colorheader colorrgba(0, 0, 0, .2)

Set these on .smartphoto (or :root) to override the defaults, no rebuild required:

.smartphoto {
--smartphoto-animation-speed:450ms;
--smartphoto-animation-function: ease-in-out;
--smartphoto-backdrop-color:rgba(0,0,0,0.9);
--smartphoto-header-color:rgba(0,0,0,0.4);
}

Download

Download ZIP

Github

https://github.com/appleple/SmartPhoto

License

Code and documentation copyright 2017 by appleple, Inc. Code released under the MIT License.

About

The most easy to use responsive image viewer especially for mobile devices

Topics

Resources

Stars

896 stars

Watchers

25 watching

Forks

Releases

Packages

Used by

Contributors

Languages