npm package: @olefjaerestad/wc-interactive-slideshow
Description: Image slideshow with play/pause/interval functionality.
Author: olefjaerestad
Latest version: 0.0.4

# `@olefjaerestad/wc-interactive-slideshow`

Image slideshow with play/pause/reverse/stops/goto/reset functionality.

## Motivation
Consider this component a video player playing image files in order, complementing the native `<video>` element. The `<video>` element is good at many things. It's not good at the following:
- Playing backwards.
- Programmatic control over which frame to display (only timestamp).
- Automatically stop playing at certain frames (requires custom code).
- It requires a video file. Not everyone has a video file.

This component aims to solve these issues by providing a simple to use API for configuration and playing.

### Use cases
- Product 360° view.
- Video stopping at certain frames to highlight important things.
- The component has minimal styling on its own, so it should be easy to overwrite for you to build whatever you want.

## Usage

### Define
You need to define the component yourself. This way you won't run into naming conflicts with other components. It also lets you extend the component class.

```javascript
const { WcInteractiveSlideshow } = require('@olefjaerestad/wc-interactive-slideshow');

if (!customElements.get('wc-interactive-slideshow')) {
  customElements.define('wc-interactive-slideshow', WcInteractiveSlideshow);
}
```

### Basic use
```html
<wc-interactive-slideshow 
  count="30"
  src="http://url.to/images/"
></wc-interactive-slideshow>
```

### Attributes
- `count`: How many images the slideshow should show. Required.
- `format`: Which format your images are. Optional. Default: `jpeg`.
- `fps`: How many images should be displayed pr. second when using `play()`. Optional. Default: `10`.
- `poster`: Full URL to image to display while the images in `src` are being loaded. Does not depend on the `format` attribute. Optional. Default: `null`.
- `src`: Full URL to where your images are stored. The element expects a folder with images named 1.jpeg, 2.jpeg, 3.jpeg, etc (you can change format with the `format` attribute). Required.
- `stops`: When playing the slideshow (using the `play()` or `reverse()` methods), the slideshow can automatically stop at certain images. You'll have to `play()` or `reverse()` in order to start playing again. Example: `stops="5,15,24"` would stop at 5.jpeg, 15.jpeg and 24.jpeg. Optional. Default: `null`.
- `title`: The title will be put on the nested image element (added by the component) and deleted from the component itself. For improved accessibility.

> Note: You can of course add all the standard attributes, such as id, class and data-* attributes as well.

> Note 2: Each of these attributes have setter methods, so you can do:

```javascript
const myComponent = document.querySelector('wc-interactive-slideshow');
myComponent.count = 31;
myComponent.format = 'png';
myComponent.fps = 5;
myComponent.poster = 'http://url.to/poster.jpeg';
myComponent.src = 'http://url.to/new/images/';
myComponent.stops = '7,13,17,25';
```

### Methods
- `goto(to: number)`: Go to specific image. `goto(24)` would go to image 24.
- `pause()`: Pause the slideshow.
- `play(to?: number)`: Play the slideshow from the current image. Pass `to` to play until a given image is reached. `to = 3` will play until 3.jpeg is reached. If there are any `stops` between the current index and `to`, the slideshow will stop before `to` is reached.
- `reset()`: Go to first image and pause the player.
- `reverse(to?: number)`: Play the slideshow backwards from the current image. Pass `to` to reverse until a given image is reached. `to = 3` will reverse until 3.jpeg is reached. If there are any `stops` between the current index and `to`, the slideshow will stop before `to` is reached.

### Properties
- `batch: string[] = []`: The currently loaded image URLs.
- `count: number|null`: The value passed to the count attribute.
- `currentIndex: number`: The index at which the slideshow is currently at. 0-based.
- `error: Error`: The error if an operation in the component has failed.
- `format: 'jpeg'|string`: The value passed to the format attribute.
- `fps: number|null`: The value passed to the fps attribute.
- `img: HTMLImageElement`: The nested `<img>` element used to display the images.
- `poster: string|null`: The value passed to the poster attribute.
- `rafId: number`: The requestAnimationFrameId used for animating the slideshow.
- `src: string|null`: The value passed to the src attribute.
- `stops: string|null`: The value passed to the stops attribute.
- `stopsArr: number[]`: The value passed to the stops attribute, converted to an array of numbers by splitting on `,`.

> Note: For regular use, you probably won't need to use any of these. These are just available for your convenience if you want to do some custom stuff.

### Events
The slideshow will emit events when certain, well, events happen. You can listen for these and run custom code when they happen. Most of the events will contain some extra information (in the form of an object) in the `.detail` property of the event object.

| Event name           | Description             | e.detail                     |
|:--                   |:--                      |:--                           |
| `slideshow.change`   | Image changed           | from: number<br>to: number   |
| `slideshow.error`    | An error happened       | error: Error                 |
| `slideshow.load`     | Images finished loading | urls: string[]               |
| `slideshow.pause`    | Playing pauses          | index: number                |
| `slideshow.play`     | Playing starts          | index: number                |
| `slideshow.reset`    | Slideshow resets        |                              |
| `slideshow.reverse`  | Reverse playing starts  | index: number                |


```javascript
const myComponent = document.querySelector('wc-interactive-slideshow');
myComponent.addEventListener('slideshow.change', e => {
  console.log(`Changed from image ${e.detail.from} to ${e.detail.to}`);
});
```

## Server side rendering
Instead of passing a poster attribute, just add an `<img>` as a child element. Once JS has loaded, the element will hydrate and start working as expected.

```html
<wc-interactive-slideshow 
  src="http://url.to/images/"
  count="34"
  fps="5"
>
  <img src="http://url.to/poster.jpeg" title="An image slideshow of some very cool stuff.">
</wc-interactive-slideshow>
```

## Browser support

|          Browser         | Supported? |
|:--                       |:--         |
| Chrome >= 49             | ✅         |
| Edge >= 18               | ✅         |
| Firefox >= 45            | ✅         |
| Internet Explorer        | ❌         |
| Opera >= 36              | ✅         |
| Safari >= 10             | ✅         |
| Chrome for Android > 49  | ✅         |
| Firefox for Android > 45 | ✅         |
| Opera for Android > 36   | ✅         |
| Safari for iOS > 10      | ✅         |
| Node.js                  | ❌         |


Browser support is mainly affected by 
- [Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
- [Promise.all](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)
- [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent)
- [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)

## Troubleshooting

### My images look stretched
Your images might be malformed in some way. Try saving them again and see if that fixes things. See [https://prodevsblog.com/questions/209590/css-object-fit-cover-is-stretching-a-particular-image-in-chrome-on-mac/](https://prodevsblog.com/questions/209590/css-object-fit-cover-is-stretching-a-particular-image-in-chrome-on-mac/)