diff --git a/package.json b/package.json index 68e898959..72f5a57dc 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "printsizes": "print-sizes ./dist --exclude=\\.map", "test": "karma start", "test:chrome": "karma start --chrome", - "lint": "eslint src && tslint declaration/**/*", + "lint": "tslint src/**/*", "jsdoc": "rm -rf ./doc && jsdoc -c jsdoc.json", "coverage": "karma start --coverage", "coverage:nogl": "karma start --coverage --nogl", diff --git a/src/SpinViewer/SpinViewer.js b/src/SpinViewer/SpinViewer.js deleted file mode 100644 index 9da40c4ba..000000000 --- a/src/SpinViewer/SpinViewer.js +++ /dev/null @@ -1,262 +0,0 @@ -import Component from "@egjs/component"; -import Axes, {PanInput} from "@egjs/axes"; -import SpriteImage from "./SpriteImage"; -import {VERSION} from "../version"; - -const DEFAULT_PAN_SCALE = 0.21; - -/** - * @class eg.view360.SpinViewer - * @classdesc A module used to displays each image sequentially according to the direction of the user's touch movement (left / right) of the sprite image that is collected by rotating the object. - * @ko 물체 주위를 회전하여 촬영한 이미지들을 모은 스프라이트 이미지를 사용자의 터치 이동 방향(좌 / 우) 에 따라 각 이미지들을 순차적으로 보여주는 컴포넌트입니다. - * @extends eg.Component - * - * @param {HTMLElement} element The element to show the image 이미지를 보여줄 대상 요소 - * @param {Object} options The option object파라미터 객체 - * @param {String} options.imageUrl The url of the sprite image 스프라이트 이미지의 url - * @param {Number} [options.rowCount=1] Number of horizontal frames in the sprite image 스프라이트 이미지의 가로 프레임 갯수 - * @param {Number} [options.colCount=1] Number of vertical frames in the sprite image 스프라이트 이미지의 세로 프레임 갯수 - * @param {Number|String} [options.width="auto"] The width of the target element to show the image 이미지를 보여줄 대상 요소의 너비 - * @param {Number|String} [options.height="auto"] The height of the target element to show the image 이미지를 보여줄 대상 요소의 높이 - * @param {Boolean} [options.autoHeight=true] Whether to automatically set the height of the image area to match the original image's proportion 원본 이미지 비율에 맞게 이미지 영역의 높이를 자동으로 설정할지 여부 - * @param {Number[]} [options.colRow=[0, 0]] The column, row coordinates of the first frame of the sprite image (based on 0 index) 스프라이트 이미지 중 처음 보여줄 프레임의 (column, row) 좌표 (0 index 기반) - * @param {Number} [options.scale=1] Spin scale (The larger the spin, the more).Spin 배율 (클 수록 더 많이 움직임) - * @support {"ie": "9+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"} - * @example - * - * // Initialize SpinViewer - * var el = document.getElementById("product-360"); - * var viewer = new eg.view360.SpinViewer(el, { - * imageUrl: "/img/bag360.jpg", // required - * rowCount: 24 //required - * }); - */ -class SpinViewer extends Component { - /** - * Version info string - * @ko 버전정보 문자열 - * @name VERSION - * @static - * @type {String} - * @example - * eg.view360.SpinViewer.VERSION; // ex) 3.0.1 - * @memberof eg.view360.SpinViewer - */ - static VERSION = VERSION; - constructor(element, options) { - super(); - - this._el = element; - - const opt = Object.assign({}, options); - const colCount = opt.colCount || 1; - const rowCount = opt.rowCount || 1; - - this._scale = (opt.scale || 1); - this._panScale = this._scale * DEFAULT_PAN_SCALE; - - this._frameCount = colCount * rowCount; - - // Init SpriteImage - this._sprites = new SpriteImage(element, opt).on({ - "load": evt => { - /** - * Events that occur when component loading is complete - * @ko 컴포넌트 로딩이 완료되면 발생하는 이벤트 - * @name eg.view360.SpinViewer#load - * @event - * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 - * @param {HTMLElement} param.target The target element for which to display the image 이미지를 보여줄 대상 엘리먼트 - * @param {HTMLElement} param.bgElement Generated background image element 생성된 background 이미지 엘리먼트 - * - * @example - * - * viwer.on({ - * "load" : function(evt) { - * this.spinBy(360, {duration: 300}); - * } - * }); - */ - this.trigger("load", evt); - }, - "imageError": evt => { - /** - * An event that occurs when the image index is changed by the user's left / right panning - * @ko 사용자의 좌우 Panning 에 의해 이미지 인덱스가 변경되었을때 발생하는 이벤트 - * @name eg.view360.SpinViewer#imageError - * @event - * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 - * @param {String} param.imageUrl User-specified image URL 사용자가 지정한 이미지 URL - * - * @example - * - * viewer.on({ - * "imageError" : function(evt) { - * // Error handling - * console.log(e.imageUrl); - * } - * }); - */ - this.trigger("imageError", { - imageUrl: evt.imageUrl - }); - } - }); - - // Init Axes - this._panInput = new PanInput(this._el, { - scale: [this._panScale, this._panScale] - }); - this._axes = new Axes({ - angle: { - range: [0, 359], - circular: true - } - }).on({ - "change": evt => { - const curr = Math.floor(evt.pos.angle / (360 / this._frameCount)); - const frameIndex = this._frameCount - curr - 1; - - this._sprites.setFrameIndex(frameIndex); - - /** - * An event that occurs when the image index is changed by the user's left / right panning - * @ko 사용자의 좌우 Panning 에 의해 이미지 인덱스가 변경되었을때 발생하는 이벤트 - * @name eg.view360.SpinViewer#change - * @event - * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 - * @param {Number[]} param.colRow Column, row of the frame in the sprite image 스프라이트 이미지 내 프레임의 column, row - * @param {Number} param.frameIndex Index value that is sequentially appended in Z direction based on col and row.col, row 를 기반으로 Z 방향으로 순차적으로 붙여지는 index 값 - * @param {Number} param.angle The angle that is currently internally held at an angle between 0 and 359. (not a real product angle) 0 ~ 359 범위의 각도로 현재 내부적으로 유지하고 있는 각도 (실제 이미지의 각도가 아님) - * - * @example - * - * viwer.on({ - * "change" : function(evt) { - * console.log(event.frameIndex, event.colRow, event.angle); // event.colRow = [0, 4] event.frameIndex = 4, event = 30 - * } - * }); - */ - this.trigger("change", { - frameIndex, - colRow: this._sprites.getColRow(), - angle: evt.pos.angle - }); - }, - "animationEnd": evt => { - /** - * This event is fired when animation ends. - * @ko 에니메이션이 끝났을 때 발생하는 이벤트 - * @name eg.view360.SpinViewer#animationEnd - * @event - * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 - * @param {Boolean} param.isTrusted true if an event was generated by the user action, or false if it was caused by a script or API call사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다. - * - * @example - * - * viwer.on({ - * "animationEnd" : function(evt) { - * // evt.isTrusted === true or false - * } - * }); - */ - this.trigger("animationEnd", { - isTrusted: evt.isTrusted - }); - } - }); - - this._axes.connect("angle", this._panInput); - } - - /** - * Set spin scale - * @ko scale 을 조정할 수 있는 함수 - * @method eg.view360.SpinViewer#setScale - * @param {Number} scale Rotation multiples at spin, the larger the rotationSpin 시 회전 배수값, 커질 수록 더 많이 회전 - * - * @return {Object} Instance of SpinViewer SpinViewer 인스턴스 - * - * @example - * - * viewer.setScale(2);// It moves twice as much. - */ - setScale(scale) { - if (isNaN(scale) || scale < 0) { - return this; - } - - this._scale = scale; - this._panScale = scale * DEFAULT_PAN_SCALE; - this._panInput.options.scale = [this._panScale, this._panScale]; - - return this; - } - - /** - * Get spin scale - * @ko scale 값을 반환한다. - * @method eg.view360.SpinViewer#getScale - * - * @return {Number} Rotation multiples at spin, the larger the rotationSpin 시 회전 배수값, 커질 수록 더 많이 회전 - * - * @example - * - * viewer.getScale();// It returns number - */ - getScale() { - return this._scale; - } - - /** - * It gives the effect of rotating for a certain duration by the specified angle based on the current rotation angle. - * @ko 현재 회전 각도를 기준으로 지정된 각도(angle)만큼 일정 시간동안(duration) 회전하는 효과를 준다. - * @method eg.view360.SpinViewer#spinBy - * - * @param {Number} [angle = 0] angle상대적 회전 각도 - * @param {Object} param The parameter object파라미터 객체 - * @param {Number} [param.duration = 0] duration회전할 시간 - 밀리세컨드 단위 - * - * @return {Object} Instance of SpinViewer SpinViewer 인스턴스 - * - * @example - * - * viewer.spinBy(720, {duration: 500}); - */ - spinBy(angle = 0, param = {duration: 0}) { - this._axes.setBy({angle}, param.duration); - return this; - } - - /** - * It gives the effect of rotating for a certain duration (duration) by the specified angle (angle). - * @ko 지정된 각도(angle)만큼 일정 시간동안(duration) 회전하는 효과를 준다. - * @method eg.view360.SpinViewer#spinTo - * - * @param {Number} [angle = 0] angle회전 각도 - * @param {Object} param The parameter object파라미터 객체 - * @param {Number} [param.duration = 0] duration회전할 시간 - 밀리세컨드 단위 - * - * @return {Object} Instance of SpinViewer SpinViewer 인스턴스 - * - * @example - * - * viewer.spinTo(30, {duration:100}); - */ - spinTo(angle = 0, param = {duration: 0}) { - this._axes.setTo({angle}, param.duration); - return this; - } - - /** - * Returns current angles - * @ko 현재 각도를 반환한다. - * - * @return {Number} Current angle 현재 각도 - */ - getAngle() { - return this._axes.get().angle || 0; - } -} - -export default SpinViewer; diff --git a/src/SpinViewer/SpinViewer.ts b/src/SpinViewer/SpinViewer.ts new file mode 100644 index 000000000..f424255ca --- /dev/null +++ b/src/SpinViewer/SpinViewer.ts @@ -0,0 +1,289 @@ +import Component from "@egjs/component"; +import Axes, { PanInput } from "@egjs/axes"; +import SpriteImage from "./SpriteImage"; +import { VERSION } from "../version"; + +const DEFAULT_PAN_SCALE = 0.21; + +/** + * @memberof eg.view360 + * @extends eg.Component + * SpinViewer + */ +class SpinViewer extends Component<{ + /** + * Events that occur when component loading is complete + * @ko 컴포넌트 로딩이 완료되면 발생하는 이벤트 + * @name eg.view360.SpinViewer#load + * @event + * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 + * @param {HTMLElement} param.target The target element for which to display the image 이미지를 보여줄 대상 엘리먼트 + * @param {HTMLElement} param.bgElement Generated background image element 생성된 background 이미지 엘리먼트 + * + * @example + * + * viwer.on({ + * "load" : function(evt) { + * this.spinBy(360, {duration: 300}); + * } + * }); + */ + load: { + target: HTMLElement; + bgElement: HTMLDivElement; + }; + /** + * An event that occurs when the image index is changed by the user's left / right panning + * @ko 사용자의 좌우 Panning 에 의해 이미지 인덱스가 변경되었을때 발생하는 이벤트 + * @name eg.view360.SpinViewer#imageError + * @event + * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 + * @param {String} param.imageUrl User-specified image URL 사용자가 지정한 이미지 URL + * + * @example + * + * viewer.on({ + * "imageError" : function(evt) { + * // Error handling + * console.log(e.imageUrl); + * } + * }); + */ + imageError: { + imageUrl?: string; + }; + /** + * An event that occurs when the image index is changed by the user's left / right panning + * @ko 사용자의 좌우 Panning 에 의해 이미지 인덱스가 변경되었을때 발생하는 이벤트 + * @name eg.view360.SpinViewer#change + * @event + * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 + * @param {Number[]} param.colRow Column, row of the frame in the sprite image 스프라이트 이미지 내 프레임의 column, row + * @param {Number} param.frameIndex Index value that is sequentially appended in Z direction based on col and row.col, row 를 기반으로 Z 방향으로 순차적으로 붙여지는 index 값 + * @param {Number} param.angle The angle that is currently internally held at an angle between 0 and 359. (not a real product angle) 0 ~ 359 범위의 각도로 현재 내부적으로 유지하고 있는 각도 (실제 이미지의 각도가 아님) + * + * @example + * + * viwer.on({ + * "change" : function(evt) { + * console.log(event.frameIndex, event.colRow, event.angle); // event.colRow = [0, 4] event.frameIndex = 4, event = 30 + * } + * }); + */ + change: { + colRow: number[]; + frameIndex: number; + angle: number; + }; + /** + * This event is fired when animation ends. + * @ko 에니메이션이 끝났을 때 발생하는 이벤트 + * @name eg.view360.SpinViewer#animationEnd + * @event + * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 + * @param {Boolean} param.isTrusted true if an event was generated by the user action, or false if it was caused by a script or API call사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다. + * + * @example + * + * viwer.on({ + * animationEnd" : function(evt) { + * // evt.isTrusted === true or false + * } + * }); + */ + animationEnd: { + isTrusted: boolean; + } +}> { + /** + * Version info string + * @ko 버전정보 문자열 + * @static + * @example + * eg.view360.SpinViewer.VERSION; // ex) 3.0.1 + * @memberof eg.view360.SpinViewer + */ + public static VERSION = VERSION; + + private _el: HTMLElement; + private _sprites: SpriteImage; + private _axes: Axes; + private _panInput: PanInput; + + private _scale: number; + private _panScale: number; + private _frameCount: number; + + /** + * @classdesc A module used to displays each image sequentially according to the direction of the user's touch movement (left / right) of the sprite image that is collected by rotating the object. + * @ko 물체 주위를 회전하여 촬영한 이미지들을 모은 스프라이트 이미지를 사용자의 터치 이동 방향(좌 / 우) 에 따라 각 이미지들을 순차적으로 보여주는 컴포넌트입니다. + * + * @param {HTMLElement} element The element to show the image 이미지를 보여줄 대상 요소 + * @param {Object} options The option object파라미터 객체 + * @param {String} options.imageUrl The url of the sprite image 스프라이트 이미지의 url + * @param {Number} [options.rowCount=1] Number of horizontal frames in the sprite image 스프라이트 이미지의 가로 프레임 갯수 + * @param {Number} [options.colCount=1] Number of vertical frames in the sprite image 스프라이트 이미지의 세로 프레임 갯수 + * @param {Number|String} [options.width="auto"] The width of the target element to show the image 이미지를 보여줄 대상 요소의 너비 + * @param {Number|String} [options.height="auto"] The height of the target element to show the image 이미지를 보여줄 대상 요소의 높이 + * @param {Boolean} [options.autoHeight=true] Whether to automatically set the height of the image area to match the original image's proportion 원본 이미지 비율에 맞게 이미지 영역의 높이를 자동으로 설정할지 여부 + * @param {Number[]} [options.colRow=[0, 0]] The column, row coordinates of the first frame of the sprite image (based on 0 index) 스프라이트 이미지 중 처음 보여줄 프레임의 (column, row) 좌표 (0 index 기반) + * @param {Number} [options.scale=1] Spin scale (The larger the spin, the more).Spin 배율 (클 수록 더 많이 움직임) + * @support {"ie": "9+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"} + * @example + * ``` + * // Initialize SpinViewer + * var el = document.getElementById("product-360"); + * var viewer = new eg.view360.SpinViewer(el, { + * imageUrl: "/img/bag360.jpg", // required + * rowCount: 24 //required + * }); + * ``` + */ + constructor(element: HTMLElement, options: Partial<{ + imageUrl: string; + rowCount: number; + colCount: number; + width: number | string; + height: number | string; + autoHeight: boolean; + colRow: number[]; + scale: number; + }> = {}) { + super(); + + this._el = element; + + const opt = Object.assign({}, options); + const colCount = opt.colCount || 1; + const rowCount = opt.rowCount || 1; + + this._scale = (opt.scale || 1); + this._panScale = this._scale * DEFAULT_PAN_SCALE; + + this._frameCount = colCount * rowCount; + + // Init SpriteImage + this._sprites = new SpriteImage(element, opt).on({ + "load": evt => { + this.trigger("load", evt); + }, + "imageError": evt => { + this.trigger("imageError", { + imageUrl: evt.imageUrl + }); + } + }); + + // Init Axes + this._panInput = new PanInput(this._el, { + scale: [this._panScale, this._panScale] + }); + this._axes = new Axes({ + angle: { + range: [0, 359], + circular: true + } + }).on({ + "change": evt => { + const curr = Math.floor(evt.pos.angle / (360 / this._frameCount)); + const frameIndex = this._frameCount - curr - 1; + + this._sprites.setFrameIndex(frameIndex); + + this.trigger("change", { + frameIndex, + colRow: this._sprites.getColRow(), + angle: evt.pos.angle + }); + }, + "animationEnd": evt => { + this.trigger("animationEnd", { + isTrusted: evt.isTrusted + }); + } + }); + + this._axes.connect("angle", this._panInput); + } + + /** + * Set spin scale + * @ko scale 을 조정할 수 있는 함수 + * @param {Number} scale Rotation multiples at spin, the larger the rotationSpin 시 회전 배수값, 커질 수록 더 많이 회전 + * + * @return {Object} Instance of SpinViewer SpinViewer 인스턴스 + * + * @example + * viewer.setScale(2);// It moves twice as much. + */ + public setScale(scale: number) { + if (isNaN(scale) || scale < 0) { + return this; + } + + this._scale = scale; + this._panScale = scale * DEFAULT_PAN_SCALE; + this._panInput.options.scale = [this._panScale, this._panScale]; + + return this; + } + + /** + * Get spin scale + * @ko scale 값을 반환한다. + * + * @return {Number} Rotation multiples at spin, the larger the rotationSpin 시 회전 배수값, 커질 수록 더 많이 회전 + * + * @example + * viewer.getScale();// It returns number + */ + public getScale() { + return this._scale; + } + + /** + * It gives the effect of rotating for a certain duration by the specified angle based on the current rotation angle. + * @ko 현재 회전 각도를 기준으로 지정된 각도(angle)만큼 일정 시간동안(duration) 회전하는 효과를 준다. + * @param {Number} [angle = 0] angle상대적 회전 각도 + * @param {Object} param The parameter object파라미터 객체 + * @param {Number} [param.duration = 0] duration회전할 시간 - 밀리세컨드 단위 + * + * @return {Object} Instance of SpinViewer SpinViewer 인스턴스 + * + * @example + * viewer.spinBy(720, {duration: 500}); + */ + public spinBy(angle = 0, param = {duration: 0}) { + this._axes.setBy({angle}, param.duration); + return this; + } + + /** + * It gives the effect of rotating for a certain duration (duration) by the specified angle (angle). + * @ko 지정된 각도(angle)만큼 일정 시간동안(duration) 회전하는 효과를 준다. + * @param {Number} [angle = 0] angle회전 각도 + * @param {Object} param The parameter object파라미터 객체 + * @param {Number} [param.duration = 0] duration회전할 시간 - 밀리세컨드 단위 + * + * @return {Object} Instance of SpinViewer SpinViewer 인스턴스 + * + * @example + * viewer.spinTo(30, {duration:100}); + */ + public spinTo(angle = 0, param = {duration: 0}) { + this._axes.setTo({angle}, param.duration); + return this; + } + + /** + * Returns current angles + * @ko 현재 각도를 반환한다. + * + * @return {Number} Current angle 현재 각도 + */ + public getAngle() { + return this._axes.get().angle || 0; + } +} + +export default SpinViewer; diff --git a/src/SpinViewer/SpriteImage.js b/src/SpinViewer/SpriteImage.js deleted file mode 100644 index 974411eaa..000000000 --- a/src/SpinViewer/SpriteImage.js +++ /dev/null @@ -1,321 +0,0 @@ -import Component from "@egjs/component"; -import {TRANSFORM, SUPPORT_WILLCHANGE} from "../utils/browserFeature"; -import {VERSION} from "../version"; -/** - * @class eg.view360.SpriteImage - * @classdesc A module that displays a single or continuous image of any one of the "sprite images". SpinViewer internally uses SpriteImage to show each frame of the sprite image. - * @ko 스프라이트 이미지 중 임의의 한 프레임을 단발성 혹은 연속적으로 보여주는 컴포넌트입니다. SpinViewer 는 내부적으로 SpriteImage 를 사용하여 스프라이트 이미지의 각 프레임을 보여줍니다. - * @extends eg.Component - * - * @param {HTMLElement} element The element to show the image 이미지를 보여줄 대상 요소 - * @param {Object} options The option object파라미터 객체 - * @param {String} options.imageUrl The url of the sprite image 스프라이트 이미지의 url - * @param {Number} [options.rowCount=1] Number of horizontal frames in the sprite image 스프라이트 이미지의 가로 프레임 갯수 - * @param {Number} [options.colCount=1] Number of vertical frames in the sprite image 스프라이트 이미지의 세로 프레임 갯수 - * @param {Number|String} [options.width="auto"] The width of the target element to show the image 이미지를 보여줄 대상 요소의 너비 - * @param {Number|String} [options.height="auto"] The height of the target element to show the image 이미지를 보여줄 대상 요소의 높이 - * @param {Boolean} [options.autoHeight=true] Whether to automatically set the height of the image area to match the original image's proportion 원본 이미지 비율에 맞게 이미지 영역의 높이를 자동으로 설정할지 여부 - * @param {Number[]} [options.colRow=[0, 0]] The column, row coordinates of the first frame of the sprite image (based on 0 index) 스프라이트 이미지 중 처음 보여줄 프레임의 (column, row) 좌표 (0 index 기반) - * @param {Number} [options.frameIndex=0] frameIndex specifies the index of the frame to be displayed in the "Sprite image". The frameIndex order is zero-based and indexed in Z form (left-to-right, top-to-bottom, and newline again from left to right).
- colRow is equivalent to frameIndex. However, if colRow is specified at the same time, colRow takes precedence.스프라이트 이미지 중에서 보여질 프레임의 인덱스를 지정합니다. frameIndex 순서는 0부터 시작하며 Z 형태(왼쪽에서 오른쪽, 위에서 아래, 개행 시 다시 왼쪽 부터)로 인덱싱합니다.
- colRow 는 frameIndex 와 동일한 기능을 합니다. 단, colRow 가 동시에 지정된 경우 colRow 가 우선합니다.
- * @param {Number} [options.scale=1] Spin scale (The larger the spin, the more).Spin 배율 (클 수록 더 많이 움직임) - * - * @support {"ie": "9+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"} - * @example - * - * // Initialize SpriteImage - * - * var el = document.getElementById("image-div"); - * var sprites = new eg.view360.SpriteImage(el, { - * imageUrl: "/img/bag360.jpg", // required - * rowCount: 24 - * }); - */ -class SpriteImage extends Component { - static VERSION = VERSION; - constructor(element, options) { - super(); - const opt = options || {}; - - this._el = element; - this._rowCount = opt.rowCount || 1; - this._colCount = opt.colCount || 1; - this._totalCount = this._rowCount * this._colCount;// total frames - this._width = opt.width || "auto"; - this._height = opt.height || "auto"; - this._autoHeight = opt.autoHeight != null ? opt.autoHeight : "true"; // If autoHeight is specified, _height will be overwritten. - this._colRow = [0, 0]; - - if (opt.colRow) { - this._colRow = opt.colRow; - } else if (opt.frameIndex) { - this.setFrameIndex(opt.frameIndex); - } - - this._el.style.width = SpriteImage._getSizeString(this._width); - this._el.style.height = SpriteImage._getSizeString(this._height); - - if (!opt.imageUrl) { - setTimeout(() => { - this.trigger("imageError", { - imageUrl: opt.imageUrl - }); - }, 0); - return; - } - - this._image = new Image(); - /** - * Event - */ - this._image.onload = () => { - this._bg = SpriteImage._createBgDiv( - this._image, this._rowCount, this._colCount, this._autoHeight); - this._el.appendChild(this._bg); - this.setColRow(this._colRow[0], this._colRow[1]); - - /** - * Events that occur when component loading is complete - * @ko 컴포넌트 로딩이 완료되면 발생하는 이벤트 - * @name eg.view360.SpriteImage#load - * @event - * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 - * @param {HTMLElement} param.target The target element for which to display the image 이미지를 보여줄 대상 엘리먼트 - * @param {HTMLElement} param.bgElement Generated background image element 생성된 background 이미지 엘리먼트 - * - * @example - * - * sprites.on({ - * "load" : function(evt) { - * console.log("load event fired - e.target", e.target, "e.bgElement", e.bgElement); - * } - * }); - */ - this.trigger("load", { - target: this._el, - bgElement: this._bg - }); - - if (this._autoPlayReservedInfo) { - this.play(this._autoPlayReservedInfo); - this._autoPlayReservedInfo = null; - } - }; - - this._image.onerror = e => { - /** - * An event that occurs when the image index is changed by the user's left / right panning - * @ko 사용자의 좌우 Panning 에 의해 이미지 인덱스가 변경되었을때 발생하는 이벤트 - * @name eg.view360.SpriteImage#imageError - * @event - * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 - * @param {String} param.imageUrl User-specified image URL 사용자가 지정한 이미지 URL - * - * @example - * - * sprites.on({ - * "imageError" : function(evt) { - * // Error handling - * console.log(e.imageUrl); - * } - * }); - */ - this.trigger("imageError", { - imageUrl: opt.imageUrl - }); - }; - - this._image.src = opt.imageUrl; - } - - static _createBgDiv(img, rowCount, colCount, autoHeight) { - const el = document.createElement("div"); - - el.style.position = "relative"; - el.style.overflow = "hidden"; - - img.style.position = "absolute"; - img.style.width = `${colCount * 100}%`; - img.style.height = `${rowCount * 100}%`; - /** Prevent image from being dragged on IE10, IE11, Safari especially */ - img.ondragstart = () => (false); // img.style.pointerEvents = "none"; - // Use hardware accelerator if available - SUPPORT_WILLCHANGE && (img.style.willChange = "transform"); - - el.appendChild(img); - - const unitWidth = img.width / colCount; - const unitHeight = img.height / rowCount; - - if (autoHeight) { - const r = unitHeight / unitWidth; - - el.style.paddingBottom = `${r * 100}%`; - } else { - el.style.height = "100%"; - } - - return el; - } - - /** - * Specifies the frameIndex of the frame to be shown in the sprite image. - * @ko 스프라이트 이미지 중 보여질 프레임의 frameIndex 값을 지정 - * @method eg.view360.SpriteImage#setFrameIndex - * @param {Number} frameIndex frame index of a frame프레임의 인덱스 - * - * @example - * - * sprites.setFrameIndex(0, 1);// col = 0, row = 1 - */ - setFrameIndex(index) { - const colRow = this.toColRow(index); - - this.setColRow(colRow[0], colRow[1]); - } - - /** - * Returns the frameIndex of the frame to be shown in the sprite image. - * @ko 스프라이트 이미지 중 보여지는 프레임의 index 값을 반환 - * @method eg.view360.SpriteImage#getFrameIndex - * @return {Number} frame index frame 인덱스 - * - * @example - * - * var frameIndex = sprites.getFrameIndex(); // eg. frameIndex = 1 - * - */ - getFrameIndex() { - return this._colRow[1] * this._colCount + this._colRow[0]; - } - - /** - * Specifies the col and row values of the frame to be shown in the sprite image. - * @ko 스프라이트 이미지 중 보여질 프레임의 col, row 값을 지정 - * @method eg.view360.SpriteImage#setColRow - * @param {Number} col Column number of a frame프레임의 행값 - * @param {Number} row Row number of a frame프레임의 열값 - * - * @example - * - * sprites.setlColRow(1, 2); // col = 1, row = 2 - */ - setColRow(col, row) { - if (row > this._rowCount - 1 || col > this._colCount - 1) { - return; - } - - if (this._image && TRANSFORM) { - // NOTE: Currently, do not apply translate3D for using layer hack. Do we need layer hack for old browser? - this._image.style[TRANSFORM] = `translate(${-(col / this._colCount * 100)}%, ${-(row / this._rowCount * 100)}%)`; - } - - this._colRow = [col, row]; - } - - /** - * Returns the col and row values of the frame to be shown in the sprite image. - * @ko 스프라이트 이미지 중 보여지는 프레임의 col, row 값을환반환 - * @method eg.view360.SpriteImage#gelColRow - * @return {Number[]} Array containing col, rowcol, row 정보를 담는 배열 - * - * @example - * - * var colRow = sprites.getlColRow(); - * // colRow = [1, 2] - index of col is 1, index of row is 2 - * - */ - getColRow() { - return this._colRow; - } - - static _getSizeString(size) { - if (typeof size === "number") { - return `${size}px`; - } - - return size; - } - - /** - * Stop playing - * @ko play 되고 있던 프레임 재생을 중지합니다. - * @method eg.view360.SpriteImage#stop - * - * @example - * - * viewer.stop(); - * - */ - stop() { - if (this._autoPlayTimer) { - clearInterval(this._autoPlayTimer); - this._autoPlayTimer = null; - } - } - - /** - * Switches frames sequentially in the 'interval' starting from the currently displayed frame and plays all frames by 'playCount'. - * @ko 현재 보여지고 있는 프레임을 시작으로 'interval' 간격으로 순차적으로 프레임을 전환하며 모든 프레임을 'playCount' 만큼 재생한다. - * @method eg.view360.SpriteImage#play - * @param {Object} param The parameter object파라미터 객체 - * @param {Number} [param.interval=1000 / totalFrameCount] Interframe Interval - in milliseconds프레임간 간격 - 밀리세컨드 단위 - * @param {Number} [param.playCount=0] PlayCount = 1 in which all frames are reproduced once, and playCount = n in which all frames are repeated n times. playCount = 0 in which all frames are repeated infinitely모든 프레임을 1회씩 재생한 것이 playCount = 1, 모든 프레임을 n 회 재상한 것이 playCount = n 이 된다. 0 dms 무한반복 - * - * @example - * - * viewer.play({angle: 16, playCount: 1}); - * - */ - play({interval, playCount} = {interval: 1000 / this._totalCount, playCount: 0}) { - if (!this._bg) { - this._autoPlayReservedInfo = {interval, playCount}; - return; - } - - if (this._autoPlayTimer) { - clearInterval(this._autoPlayTimer); - this._autoPlayTimer = null; - } - - let frameIndex = this.getFrameIndex(); - let count = 0; - let frameCount = 0; // for checking 1 cycle - - this._autoPlayTimer = setInterval(() => { - frameIndex %= this._totalCount; - const colRow = this.toColRow(frameIndex); - - this.setColRow(colRow[0], colRow[1]); - frameIndex++; - - // Done 1 Cycle? - if (++frameCount === this._totalCount) { - frameCount = 0; - count++; - } - - if (playCount > 0 && count === playCount) { - clearInterval(this._autoPlayTimer); - } - }, interval); - } - - toColRow(frameIndex) { - const colCount = this._colCount; - const rowCount = this._rowCount; - - if (frameIndex < 0) { - return [0, 0]; - } else if (frameIndex >= this._totalCount) { - return [colCount - 1, rowCount - 1]; - } - - const col = frameIndex % colCount; - const row = Math.floor(frameIndex / colCount); - - // console.log(frameIndex, col, row); - return [col, row]; - } -} - -export default SpriteImage; diff --git a/src/SpinViewer/SpriteImage.ts b/src/SpinViewer/SpriteImage.ts new file mode 100644 index 000000000..6e40a0026 --- /dev/null +++ b/src/SpinViewer/SpriteImage.ts @@ -0,0 +1,361 @@ +import Component from "@egjs/component"; +import { TRANSFORM, SUPPORT_WILLCHANGE } from "../utils/browserFeature"; +import { VERSION } from "../version"; + +/** + * @memberof eg.view360 + * @extends eg.Component + * SpriteImage + */ +class SpriteImage extends Component<{ + /** + * Events that occur when component loading is complete + * @ko 컴포넌트 로딩이 완료되면 발생하는 이벤트 + * @name eg.view360.SpriteImage#load + * @event + * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 + * @param {HTMLElement} param.target The target element for which to display the image 이미지를 보여줄 대상 엘리먼트 + * @param {HTMLElement} param.bgElement Generated background image element 생성된 background 이미지 엘리먼트 + * + * @example + * + * sprites.on({ + * "load" : function(evt) { + * console.log("load event fired - e.target", e.target, "e.bgElement", e.bgElement); + * } + * }); + */ + load: { + target: HTMLElement; + bgElement: HTMLDivElement; + } + /** + * An event that occurs when the image index is changed by the user's left / right panning + * @ko 사용자의 좌우 Panning 에 의해 이미지 인덱스가 변경되었을때 발생하는 이벤트 + * @name eg.view360.SpriteImage#imageError + * @event + * @param {Object} param The object of data to be sent to an event 이벤트에 전달되는 데이터 객체 + * @param {String} param.imageUrl User-specified image URL 사용자가 지정한 이미지 URL + * + * @example + * + * sprites.on({ + * "imageError" : function(evt) { + * // Error handling + * console.log(e.imageUrl); + * } + * }); + */ + imageError: { + imageUrl?: string; + } +}> { + public static VERSION = VERSION; + + private _el: HTMLElement; + private _rowCount: number; + private _colCount: number; + private _totalCount: number; + private _width: number | string; + private _height: number | string; + private _autoHeight: boolean; + private _colRow: number[]; + private _image: HTMLImageElement; + private _bg: HTMLDivElement; + private _autoPlayReservedInfo: { interval: number; playCount: number; } | null; + private _autoPlayTimer: number; + + /** + * @class eg.view360.SpriteImage + * @classdesc A module that displays a single or continuous image of any one of the "sprite images". SpinViewer internally uses SpriteImage to show each frame of the sprite image. + * @ko 스프라이트 이미지 중 임의의 한 프레임을 단발성 혹은 연속적으로 보여주는 컴포넌트입니다. SpinViewer 는 내부적으로 SpriteImage 를 사용하여 스프라이트 이미지의 각 프레임을 보여줍니다. + * @extends eg.Component + * + * @param {HTMLElement} element The element to show the image 이미지를 보여줄 대상 요소 + * @param {Object} options The option object파라미터 객체 + * @param {String} options.imageUrl The url of the sprite image 스프라이트 이미지의 url + * @param {Number} [options.rowCount=1] Number of horizontal frames in the sprite image 스프라이트 이미지의 가로 프레임 갯수 + * @param {Number} [options.colCount=1] Number of vertical frames in the sprite image 스프라이트 이미지의 세로 프레임 갯수 + * @param {Number|String} [options.width="auto"] The width of the target element to show the image 이미지를 보여줄 대상 요소의 너비 + * @param {Number|String} [options.height="auto"] The height of the target element to show the image 이미지를 보여줄 대상 요소의 높이 + * @param {Boolean} [options.autoHeight=true] Whether to automatically set the height of the image area to match the original image's proportion 원본 이미지 비율에 맞게 이미지 영역의 높이를 자동으로 설정할지 여부 + * @param {Number[]} [options.colRow=[0, 0]] The column, row coordinates of the first frame of the sprite image (based on 0 index) 스프라이트 이미지 중 처음 보여줄 프레임의 (column, row) 좌표 (0 index 기반) + * @param {Number} [options.frameIndex=0] frameIndex specifies the index of the frame to be displayed in the "Sprite image". The frameIndex order is zero-based and indexed in Z form (left-to-right, top-to-bottom, and newline again from left to right).
- colRow is equivalent to frameIndex. However, if colRow is specified at the same time, colRow takes precedence.스프라이트 이미지 중에서 보여질 프레임의 인덱스를 지정합니다. frameIndex 순서는 0부터 시작하며 Z 형태(왼쪽에서 오른쪽, 위에서 아래, 개행 시 다시 왼쪽 부터)로 인덱싱합니다.
- colRow 는 frameIndex 와 동일한 기능을 합니다. 단, colRow 가 동시에 지정된 경우 colRow 가 우선합니다.
+ * @param {Number} [options.scale=1] Spin scale (The larger the spin, the more).Spin 배율 (클 수록 더 많이 움직임) + * + * @support {"ie": "9+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"} + * @example + * + * // Initialize SpriteImage + * + * var el = document.getElementById("image-div"); + * var sprites = new eg.view360.SpriteImage(el, { + * imageUrl: "/img/bag360.jpg", // required + * rowCount: 24 + * }); + */ + constructor(element: HTMLElement, options: Partial<{ + imageUrl: string; + rowCount: number; + colCount: number; + width: number | string; + height: number | string; + autoHeight: boolean; + colRow: number[]; + frameIndex: number; + scale: number; + }> = {}) { + super(); + const opt = options || {}; + + this._el = element; + this._rowCount = opt.rowCount || 1; + this._colCount = opt.colCount || 1; + this._totalCount = this._rowCount * this._colCount; // total frames + this._width = opt.width || "auto"; + this._height = opt.height || "auto"; + this._autoHeight = opt.autoHeight != null ? opt.autoHeight : true; // If autoHeight is specified, _height will be overwritten. + this._colRow = [0, 0]; + + if (opt.colRow) { + this._colRow = opt.colRow; + } else if (opt.frameIndex) { + this.setFrameIndex(opt.frameIndex); + } + + this._el.style.width = SpriteImage._getSizeString(this._width); + this._el.style.height = SpriteImage._getSizeString(this._height); + + if (!opt.imageUrl) { + setTimeout(() => { + this.trigger("imageError", { + imageUrl: opt.imageUrl + }); + }, 0); + return; + } + + this._image = new Image(); + /** + * Event + */ + this._image.onload = () => { + this._bg = SpriteImage._createBgDiv( + this._image, this._rowCount, this._colCount, this._autoHeight); + this._el.appendChild(this._bg); + this.setColRow(this._colRow[0], this._colRow[1]); + + this.trigger("load", { + target: this._el, + bgElement: this._bg + }); + + if (this._autoPlayReservedInfo) { + this.play(this._autoPlayReservedInfo); + this._autoPlayReservedInfo = null; + } + }; + + this._image.onerror = e => { + this.trigger("imageError", { + imageUrl: opt.imageUrl + }); + }; + + this._image.src = opt.imageUrl; + } + + private static _createBgDiv(img: HTMLImageElement, rowCount: number, colCount: number, autoHeight: boolean) { + const el = document.createElement("div"); + + el.style.position = "relative"; + el.style.overflow = "hidden"; + + img.style.position = "absolute"; + img.style.width = `${colCount * 100}%`; + img.style.height = `${rowCount * 100}%`; + /** Prevent image from being dragged on IE10, IE11, Safari especially */ + img.ondragstart = () => (false); // img.style.pointerEvents = "none"; + // Use hardware accelerator if available + if (SUPPORT_WILLCHANGE) { + (img.style.willChange = "transform"); + } + + el.appendChild(img); + + const unitWidth = img.width / colCount; + const unitHeight = img.height / rowCount; + + if (autoHeight) { + const r = unitHeight / unitWidth; + + el.style.paddingBottom = `${r * 100}%`; + } else { + el.style.height = "100%"; + } + + return el; + } + + private static _getSizeString(size) { + if (typeof size === "number") { + return `${size}px`; + } + + return size; + } + + /** + * Specifies the frameIndex of the frame to be shown in the sprite image. + * @ko 스프라이트 이미지 중 보여질 프레임의 frameIndex 값을 지정 + * @method eg.view360.SpriteImage#setFrameIndex + * @param {Number} frameIndex frame index of a frame프레임의 인덱스 + * + * @example + * + * sprites.setFrameIndex(0, 1);// col = 0, row = 1 + */ + public setFrameIndex(index: number) { + const colRow = this.toColRow(index); + + this.setColRow(colRow[0], colRow[1]); + } + + /** + * Returns the frameIndex of the frame to be shown in the sprite image. + * @ko 스프라이트 이미지 중 보여지는 프레임의 index 값을 반환 + * @method eg.view360.SpriteImage#getFrameIndex + * @return {Number} frame index frame 인덱스 + * + * @example + * + * var frameIndex = sprites.getFrameIndex(); // eg. frameIndex = 1 + * + */ + public getFrameIndex() { + return this._colRow[1] * this._colCount + this._colRow[0]; + } + + /** + * Specifies the col and row values of the frame to be shown in the sprite image. + * @ko 스프라이트 이미지 중 보여질 프레임의 col, row 값을 지정 + * @method eg.view360.SpriteImage#setColRow + * @param {Number} col Column number of a frame프레임의 행값 + * @param {Number} row Row number of a frame프레임의 열값 + * + * @example + * + * sprites.setlColRow(1, 2); // col = 1, row = 2 + */ + public setColRow(col: number, row: number) { + if (row > this._rowCount - 1 || col > this._colCount - 1) { + return; + } + + if (this._image && TRANSFORM) { + // NOTE: Currently, do not apply translate3D for using layer hack. Do we need layer hack for old browser? + this._image.style[TRANSFORM] = `translate(${-(col / this._colCount * 100)}%, ${-(row / this._rowCount * 100)}%)`; + } + + this._colRow = [col, row]; + } + + /** + * Returns the col and row values of the frame to be shown in the sprite image. + * @ko 스프라이트 이미지 중 보여지는 프레임의 col, row 값을환반환 + * @method eg.view360.SpriteImage#gelColRow + * @return {Number[]} Array containing col, rowcol, row 정보를 담는 배열 + * + * @example + * + * var colRow = sprites.getlColRow(); + * // colRow = [1, 2] - index of col is 1, index of row is 2 + * + */ + public getColRow() { + return this._colRow; + } + + /** + * Stop playing + * @ko play 되고 있던 프레임 재생을 중지합니다. + * @method eg.view360.SpriteImage#stop + * + * @example + * + * viewer.stop(); + * + */ + public stop() { + if (this._autoPlayTimer) { + clearInterval(this._autoPlayTimer); + this._autoPlayTimer = -1; + } + } + + /** + * Switches frames sequentially in the 'interval' starting from the currently displayed frame and plays all frames by 'playCount'. + * @ko 현재 보여지고 있는 프레임을 시작으로 'interval' 간격으로 순차적으로 프레임을 전환하며 모든 프레임을 'playCount' 만큼 재생한다. + * @method eg.view360.SpriteImage#play + * @param {Object} param The parameter object파라미터 객체 + * @param {Number} [param.interval=1000 / totalFrameCount] Interframe Interval - in milliseconds프레임간 간격 - 밀리세컨드 단위 + * @param {Number} [param.playCount=0] PlayCount = 1 in which all frames are reproduced once, and playCount = n in which all frames are repeated n times. playCount = 0 in which all frames are repeated infinitely모든 프레임을 1회씩 재생한 것이 playCount = 1, 모든 프레임을 n 회 재상한 것이 playCount = n 이 된다. 0 dms 무한반복 + * + * @example + * + * viewer.play({angle: 16, playCount: 1}); + * + */ + public play({ interval, playCount } = { interval: 1000 / this._totalCount, playCount: 0 }) { + if (!this._bg) { + this._autoPlayReservedInfo = {interval, playCount}; + return; + } + + if (this._autoPlayTimer) { + clearInterval(this._autoPlayTimer); + this._autoPlayTimer = -1; + } + + let frameIndex = this.getFrameIndex(); + let count = 0; + let frameCount = 0; // for checking 1 cycle + + this._autoPlayTimer = window.setInterval(() => { + frameIndex %= this._totalCount; + const colRow = this.toColRow(frameIndex); + + this.setColRow(colRow[0], colRow[1]); + frameIndex++; + + // Done 1 Cycle? + if (++frameCount === this._totalCount) { + frameCount = 0; + count++; + } + + if (playCount > 0 && count === playCount) { + clearInterval(this._autoPlayTimer); + } + }, interval); + } + + public toColRow(frameIndex: number) { + const colCount = this._colCount; + const rowCount = this._rowCount; + + if (frameIndex < 0) { + return [0, 0]; + } else if (frameIndex >= this._totalCount) { + return [colCount - 1, rowCount - 1]; + } + + const col = frameIndex % colCount; + const row = Math.floor(frameIndex / colCount); + + // console.log(frameIndex, col, row); + return [col, row]; + } +} + +export default SpriteImage; diff --git a/src/SpinViewer/index.js b/src/SpinViewer/index.ts similarity index 54% rename from src/SpinViewer/index.js rename to src/SpinViewer/index.ts index f87752883..048e0cbd9 100644 --- a/src/SpinViewer/index.js +++ b/src/SpinViewer/index.ts @@ -1,9 +1,9 @@ import SpinViewer from "./SpinViewer"; import SpriteImage from "./SpriteImage"; -import {VERSION} from "../version"; +import { VERSION } from "../version"; export { - SpinViewer, - SpriteImage, - VERSION + SpinViewer, + SpriteImage, + VERSION };