{"version":3,"file":"ken-burns-carousel.min.js","sources":["../src/element.ts","../src/ken-burns-carousel.ts"],"sourcesContent":["/**\n * Specifies the direction of the ken burns effect.\n */\nexport const enum Direction {\n Normal = 'normal',\n Reverse = 'reverse',\n Random = 'random',\n}\n\n/**\n * All available ken burns CSS animations.\n */\nexport const animationNames = [\n 'ken-burns-bottom-right',\n 'ken-burns-top-left',\n 'ken-burns-bottom-left',\n 'ken-burns-top-right',\n 'ken-burns-middle-left',\n 'ken-burns-middle-right',\n 'ken-burns-top-middle',\n 'ken-burns-bottom-middle',\n 'ken-burns-center',\n];\n\nconst enum Attributes {\n AnimationDirection = 'animation-direction',\n AnimationNames = 'animation-names',\n FadeDuration = 'fade-duration',\n Images = 'images',\n SlideDuration = 'slide-duration',\n}\n\nconst template = document.createElement('template') as HTMLTemplateElement;\ntemplate.innerHTML = `\n\n`;\n\nif (typeof (window as any).ShadyCSS === 'object') {\n (window as any).ShadyCSS.prepareTemplate(template, 'ken-burns-carousel');\n}\n\n/**\n * `ken-burns-carousel`\n *\n * Displays a set of images in a smoothly-fading ken burns style carousel.\n *\n * @demo ../demo/index.html\n */\nexport default class KenBurnsCarousel extends HTMLElement {\n static get observedAttributes(): string[] {\n return [\n Attributes.AnimationDirection,\n Attributes.AnimationNames,\n Attributes.FadeDuration,\n Attributes.Images,\n Attributes.SlideDuration,\n ];\n }\n\n /**\n * Specifies the list of ken burns animations to apply to the elements.\n *\n * This allows customizing the built-in animations to your liking by overriding\n * the ones you don't like with custom CSS animations.\n *\n * This can also be set via setting the `animation-names`-attribute to a space-\n * separated list of CSS animation names.\n *\n * @type String[]\n */\n animationNames: string[] = animationNames;\n\n /**\n * The direction to play the animations in.\n *\n * Defaults to Direction.Random, meaning that with each image the associated ken\n * burns animation is either played forwards or backwards adding additional visual\n * diversity.\n *\n * This can also be set via the `animation-direction`-attribute.\n *\n * @type Direction\n */\n animationDirection: Direction = Direction.Random;\n\n private _fadeDuration: number = 2500;\n private _imgList: string[] = [];\n private _slideDuration: number = 20000;\n private _timeout: number = 0;\n private _zCounter: number = 0;\n\n /**\n * The duration of the crossfading animation in millseconds.\n *\n * Must be smaller than the slide duration. Defaults to 2500ms.\n * This can also be set via the `fade-duration`-attribute.\n *\n * @type number\n */\n get fadeDuration() {\n return this._fadeDuration;\n }\n\n set fadeDuration(val: number) {\n if (val > this.slideDuration) {\n throw new RangeError(\"Fade duration must be smaller than slide duration\");\n }\n\n this._fadeDuration = val;\n }\n\n /**\n * The list of URLs to the images to display.\n *\n * You can either set this property directly, or set the `images`-attribute\n * to a space-separated list of URLs.\n *\n * The element will dirty-check this property to avoid switching to the next image\n * even if the images set were the same. If you forcefully want to rerender, ensure\n * you pass a different array because the dirty-check will check for identity.\n *\n * @type string[]\n */\n get images(): string[] {\n return this._imgList;\n }\n\n set images(images: string[]) {\n if (arraysEqual(this._imgList, images)) {\n return;\n }\n\n this._imgList = images;\n if (images.length > 0) {\n this.animateImages(images);\n } else {\n this.stop();\n }\n }\n\n /**\n * The duration of the sliding (or ken burns) animation in millseconds.\n *\n * Must be greater than or equal to the fade duration. Defaults to 20s.\n * This can also be set via the `slide-duration`-attribute.\n *\n * @type number\n */\n get slideDuration() {\n return this._slideDuration;\n }\n\n set slideDuration(val: number) {\n if (val < this.fadeDuration) {\n throw new RangeError(\"Slide duration must be greater than fade duration\");\n }\n\n this._slideDuration = val;\n }\n\n constructor() {\n super();\n\n this.attachShadow({ mode: 'open' });\n this.shadowRoot!.appendChild(template.content.cloneNode(true));\n }\n\n attributeChangedCallback(name: string, oldVal: string, newVal: string) {\n switch (name) {\n case Attributes.AnimationDirection:\n this.animationDirection = newVal as Direction;\n break;\n case Attributes.AnimationNames:\n this.animationNames = newVal\n ? newVal.split(' ').filter(name => name)\n : animationNames;\n break;\n case Attributes.FadeDuration:\n this.fadeDuration = Number(newVal);\n break;\n case Attributes.Images:\n this.images = newVal\n ? newVal.split(' ').filter(url => url)\n : [];\n break;\n case Attributes.SlideDuration:\n this.slideDuration = Number(newVal);\n break;\n }\n }\n\n connectedCallback() {\n if (typeof (window as any).ShadyCSS === 'object') {\n (window as any).ShadyCSS.styleElement(this);\n }\n }\n\n private animateImages(images: string[]) {\n const insert = (index: number, img: HTMLImageElement) => {\n const random = Math.random();\n const animationIndex = Math.floor(random * this.animationNames.length);\n const direction = this.animationDirection === Direction.Random\n ? random > .5 ? 'normal' : 'reverse'\n : this.animationDirection;\n\n /*\n * Here we wrap the image element into a surrounding div that is promoted\n * onto a separate GPU layer using `will-change: transform`. The wrapping div\n * is then ken-burns-animated instead of the image itself.\n *\n * This leads the browser to pre-computing the image filter (--img-filter)\n * instead of computing it every frame. This can be a massive performance boost\n * if the filter is expensive.\n *\n * See https://developers.google.com/web/updates/2017/10/animated-blur for\n * more information.\n */\n\n const wrap = document.createElement('div');\n wrap.appendChild(img);\n\n wrap.style.animationName = `${this.animationNames[animationIndex]}, fade-in`;\n wrap.style.animationDuration = `${this.slideDuration}ms, ${this.fadeDuration}ms`;\n wrap.style.animationDirection = `${direction}, normal`;\n wrap.style.animationTimingFunction = 'linear, ease';\n wrap.style.zIndex = String(this._zCounter++);\n\n this.shadowRoot!.appendChild(wrap);\n setTimeout(() => wrap.remove(), this.slideDuration);\n\n // Preload next image and place it in browser cache\n const nextIndex = (index + 1) % images.length;\n const next = document.createElement('img') as HTMLImageElement;\n next.src = images[nextIndex];\n\n this._timeout = setTimeout(\n () => insert(nextIndex, next),\n this.slideDuration - this.fadeDuration,\n );\n };\n\n const img = document.createElement('img') as HTMLImageElement;\n img.src = images[0];\n img.onload = () => {\n /*\n * Prevent race condition leading to wrong list being displayed.\n *\n * The problem arose when you were switching out the image list before\n * this callback had fired. The callback of a later list could have fired\n * faster than the one of earlier lists, which lead to the later slideshow\n * (the right one) being cancelled when the previous one became available.\n *\n * We now check whether we're still displaying the list we started\n * with and only then proceed with actually stopping the old slideshow\n * and displaying it.\n */\n if (!arraysEqual(this._imgList, images)) {\n return;\n }\n\n this.stop();\n insert(0, img);\n };\n }\n\n private stop() {\n clearTimeout(this._timeout);\n this._timeout = 0;\n }\n}\n\nfunction arraysEqual(arr1: T[] | null, arr2: T[] | null) {\n // tslint:disable-next-line:triple-equals\n if (arr1 === arr2 || (!arr1 && !arr2)) { // undefined == null here\n return true;\n }\n if (!arr1 || !arr2 || arr1.length !== arr2.length) {\n return false;\n }\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) {\n return false;\n }\n }\n\n return true;\n}\n","import Carousel from './element.js';\n\ncustomElements.define('ken-burns-carousel', Carousel);\n\nexport default Carousel;\n"],"names":["length","document","createElement","innerHTML","window","ShadyCSS","prepareTemplate","HTMLElement","constructor","attachShadow","mode","shadowRoot","appendChild","content","cloneNode","observedAttributes","fadeDuration","_fadeDuration","slideDuration","RangeError","images","_imgList","animateImages","stop","_slideDuration","attributeChangedCallback","animationDirection","animationNames","split","filter","connectedCallback","styleElement","Math","random","floor","style","animationName","animationDuration","animationTimingFunction","zIndex","_zCounter","setTimeout","remove","src","_timeout","onload","clearTimeout","customElements","define"],"mappings":"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"}