-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(PanoViewer): Support video source (#48)
Changes - Support video source - Refactoring imageLoader - Change API (get/setImage) - Update Axes Version Ref #44
- Loading branch information
Jongmoon Yoon
authored
Dec 1, 2017
1 parent
98f6af5
commit 3111655
Showing
16 changed files
with
950 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,94 @@ | ||
const STATUS = { | ||
"NONE": 0, | ||
"LOADING": 1, | ||
"LOADED": 2, | ||
"ERROR": 3 | ||
}; | ||
|
||
export default class ImageLoader { | ||
constructor(image) { | ||
this.image = null; | ||
this._image = null; | ||
this._onceHandlers = []; | ||
this._loadStatus = STATUS.NONE; | ||
|
||
image && this.setImage(image); | ||
image && this.set(image); | ||
} | ||
|
||
get() { | ||
return new Promise((res, rej) => { | ||
if (!this.image) { | ||
rej("image is not defiend"); | ||
} else if (this.image.complete) { | ||
res(this.image); | ||
if (!this._image) { | ||
rej("ImageLoader: image is not defiend"); | ||
} else if (this._loadStatus === STATUS.LOADED) { | ||
/* Check isMaybeLoaded() first because there may have posibilities that image already loaded before get is called. for example calling get on external image onload callback.*/ | ||
res(this._image); | ||
} else if (this._loadStatus === STATUS.LOADING) { | ||
this._once("load", () => res(this._image)); | ||
this._once("error", () => rej("ImageLoader: failed to load images.")); | ||
} else { | ||
ImageLoader._once(this.image, "load", () => { | ||
res(this.image); | ||
}); | ||
ImageLoader._once(this.image, "error", () => { | ||
rej("failed to load images."); | ||
}); | ||
rej("ImageLoader: failed to load images"); | ||
} | ||
}); | ||
} | ||
|
||
setImage(image) { // img element or img url | ||
/** | ||
* @param image img element or img url | ||
*/ | ||
set(image) { | ||
this._loadStatus = STATUS.LOADING; | ||
|
||
if (typeof image === "string") { | ||
this.image = new Image(); | ||
this.image.src = image; | ||
} else if (typeof image === "object") { // img element 나 image object 이어야 함 | ||
this.image = image; | ||
this._image = new Image(); | ||
this._image.onload = () => { | ||
this._loadStatus = STATUS.LOADED; | ||
}; | ||
this._image.onerror = () => { | ||
this._loadStatus = STATUS.ERROR; | ||
}; | ||
this._image.src = image; | ||
} else if (typeof image === "object") { | ||
this._image = image; | ||
} | ||
|
||
// promise for image | ||
return this.get(); | ||
if (ImageLoader._isMaybeLoaded(this._image)) { | ||
// Already loaded image | ||
this._loadStatus = STATUS.LOADED; | ||
} | ||
} | ||
|
||
static _once(target, type, listener) { | ||
target.addEventListener(type, function fn(event) { | ||
target.removeEventListener(type, fn); | ||
listener(event); | ||
}); | ||
// target.addEventListener(type, listener); | ||
static _isMaybeLoaded(image) { | ||
return image && image.naturalWidth !== 0; | ||
} | ||
|
||
isImageLoaded() { | ||
if (!this.image) { | ||
return false; | ||
} | ||
_once(type, listener) { | ||
const target = this._image; | ||
|
||
return !!this.image.src && !!this.image.complete; | ||
} | ||
const fn = event => { | ||
target.removeEventListener(type, fn); | ||
listener(event); | ||
}; | ||
|
||
/** | ||
* TODO: 이 기능이 정말로 필요한가? | ||
*/ | ||
cancelLoadImage() { | ||
if (!!this.image && !this.isImageLoaded()) { | ||
this.image.src = ""; | ||
} | ||
target.addEventListener(type, fn); | ||
this._onceHandlers.push({type, fn}); | ||
} | ||
|
||
loadImage() { | ||
if (this._imageURL && !this.isImageLoaded()) { | ||
this.image.setAttribute("crossorigin", "anonymous"); | ||
this.image.src = this._imageURL; | ||
} | ||
getStatus() { | ||
return this._loadStatus; | ||
} | ||
|
||
destroy() { | ||
this.image = null; | ||
this._onceHandlers.forEach(handler => { | ||
this._image.removeEventListener(handler.type, handler.fn); | ||
}); | ||
this._onceHandlers = []; | ||
/** | ||
* Init event handlers | ||
*/ | ||
this._image.onload = null; | ||
this._image.onerror = null; | ||
this._image.src = ""; | ||
this._image = null; | ||
this._loadStatus = STATUS.NONE; | ||
} | ||
} | ||
|
||
ImageLoader.STATUS = STATUS; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* Ref https://www.w3schools.com/tags/av_prop_readystate.asp */ | ||
const READY_STATUS = { | ||
HAVE_NOTHING: 0, // no information whether or not the audio/video is ready | ||
HAVE_METADATA: 1, // HAVE_METADATA - metadata for the audio/video is ready | ||
HAVE_CURRENT_DATA: 2, // data for the current playback position is available, but not enough data to play next frame/millisecond | ||
HAVE_FUTURE_DATA: 3, // data for the current and at least the next frame is available | ||
HAVE_ENOUGH_DATA: 4 // enough data available to start playing | ||
}; | ||
|
||
export default class VideoLoader { | ||
constructor(video) { | ||
this._handlers = []; | ||
video && this.set(video); | ||
} | ||
|
||
set(video) { | ||
if (typeof video === "string") { | ||
// url | ||
this._video = document.createElement("video"); | ||
this._video.src = video; | ||
} else if (video instanceof HTMLVideoElement) { | ||
// video tag | ||
this._video = video; | ||
} else { | ||
this.destroy(); | ||
} | ||
} | ||
|
||
get() { | ||
/** | ||
* TODO: How about to resolve(null) if video is defiend. | ||
*/ | ||
return new Promise((res, rej) => { | ||
if (!this._video) { | ||
rej("VideoLoader: video is undefined"); | ||
} else if (this._video.readyState === READY_STATUS.HAVE_ENOUGH_DATA) { | ||
res(this._video); | ||
} else { | ||
this._once("canplaythrough", () => { | ||
res(this._video); | ||
}); | ||
this._once("error", () => rej(`VideoLoader: failed to load ${this._video.src}`)); | ||
this._video.load(); | ||
} | ||
}); | ||
} | ||
|
||
destroy() { | ||
this._handlers.forEach(handler => { | ||
this._video.removeEventListener(handler.type, handler.fn); | ||
}); | ||
this._handlers = []; | ||
|
||
if (this._video) { | ||
this._video.pause(); | ||
this._video.src = ""; | ||
this._video = null; | ||
} | ||
} | ||
|
||
_once(type, listener) { | ||
const target = this._video; | ||
|
||
const fn = event => { | ||
target.removeEventListener(type, fn); | ||
listener(event); | ||
}; | ||
|
||
target.addEventListener(type, fn); | ||
this._handlers.push({type, fn}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.