UNPKG

@egjs/flicking

Version:

Everyday 30 million people experience. It's reliable, flexible and extendable carousel.

134 lines (110 loc) 3.6 kB
/* * Copyright (c) 2015 NAVER Corp. * egjs projects are licensed under the MIT license */ import Component from "@egjs/component"; import { isString } from "../utils"; export interface ResizeWatherOptions { resizeDebounce?: number; maxResizeDebounce?: number; useResizeObserver?: boolean; useWindowResize?: boolean; watchDirection?: "width" | "height" | "box" | false; rectBox?: "border-box" | "content-box"; } class ResizeWatcher { private _container: HTMLElement; private _rect = { width: 0, height: 0 }; private _resizeTimer = 0; private _maxResizeDebounceTimer = 0; private _emitter: Component<{ resize: void }>; private _observer: ResizeObserver | null; private _options!: Required<ResizeWatherOptions>; public constructor(container: HTMLElement | string, options: ResizeWatherOptions = {}) { this._options = { resizeDebounce: 100, maxResizeDebounce: 0, useResizeObserver: false, useWindowResize: true, watchDirection: false, rectBox: "content-box", ...options }; this._container = isString(container) ? document.querySelector<HTMLElement>(container)! : container; this._init(); } public getRect() { return this._rect; } public setRect(rect: { width: number; height: number }) { this._rect = { ...rect }; } public resize() { const container = this._container; this.setRect(this._options.rectBox === "border-box" ? { width: container.offsetWidth, height: container.offsetHeight } : { width: container.clientWidth, height: container.clientHeight }); } public listen(callback: () => void) { this._emitter.on("resize", callback); return this; } public destroy() { this._observer?.disconnect(); if (this._options.useWindowResize) { window.removeEventListener("resize", this._onResize); } } private _init() { const container = this._container; const options = this._options; this._emitter = new Component(); if (options.useResizeObserver && !!window.ResizeObserver) { this._observer = new window.ResizeObserver(this._scheduleResize); this._observer.observe(container, { box: options.rectBox }); } if (options.useWindowResize) { window.addEventListener("resize", this._scheduleResize); } this.resize(); } private _onResize = () => { clearTimeout(this._resizeTimer); clearTimeout(this._maxResizeDebounceTimer); this._maxResizeDebounceTimer = 0; this._resizeTimer = 0; const watchDirection = this._options.watchDirection; const prevRect = this._rect; this.resize(); const rect = this._rect; const isWatchWidth = watchDirection === "box" || watchDirection === "width"; const isWatchHeight = watchDirection === "box" || watchDirection === "height"; const isResize = !watchDirection || (isWatchWidth && prevRect.width !== rect.width) || (isWatchHeight && prevRect.height !== rect.height); if (isResize) { this._emitter.trigger("resize"); } }; private _scheduleResize = () => { const { resizeDebounce, maxResizeDebounce } = this._options; if (!this._maxResizeDebounceTimer && maxResizeDebounce >= resizeDebounce) { this._maxResizeDebounceTimer = window.setTimeout(this._onResize, maxResizeDebounce); } if (this._resizeTimer) { clearTimeout(this._resizeTimer); this._resizeTimer = 0; } this._resizeTimer = window.setTimeout(this._onResize, resizeDebounce); }; } export default ResizeWatcher;