2011-11-05 16:46:53 +00:00
|
|
|
'use strict';
|
|
|
|
|
2012-05-21 10:38:18 +00:00
|
|
|
/*@
|
2012-05-31 10:32:54 +00:00
|
|
|
Ox.VideoPreview <f> Video Preview
|
2012-05-21 10:38:18 +00:00
|
|
|
options <o> Options
|
|
|
|
self <o> Shared private variable
|
2012-07-04 11:29:18 +00:00
|
|
|
([options[, self]]) -> <o:Ox.Element> Video Preview
|
|
|
|
click <!> click
|
2012-05-21 10:38:18 +00:00
|
|
|
@*/
|
2011-08-08 13:58:19 +00:00
|
|
|
Ox.VideoPreview = function(options, self) {
|
|
|
|
|
|
|
|
self = self || {};
|
|
|
|
var that = Ox.Element({}, self)
|
|
|
|
.defaults({
|
|
|
|
duration: 0,
|
|
|
|
getFrame: null,
|
|
|
|
fps: 25,
|
2011-09-18 06:50:54 +00:00
|
|
|
frameRatio: 16/9,
|
|
|
|
height: 256,
|
2011-09-29 17:25:50 +00:00
|
|
|
position: void 0,
|
2011-09-18 21:17:39 +00:00
|
|
|
scaleToFill: false,
|
2011-08-08 13:58:19 +00:00
|
|
|
timeline: '',
|
2011-09-18 06:50:54 +00:00
|
|
|
width: 256
|
2011-08-08 13:58:19 +00:00
|
|
|
})
|
|
|
|
.options(options || {})
|
2012-05-28 19:35:41 +00:00
|
|
|
.update({
|
|
|
|
height: function() {
|
|
|
|
that.css({height: self.options.height + 'px'});
|
|
|
|
self.$frame.css(getFrameCSS());
|
|
|
|
},
|
|
|
|
position: function() {
|
|
|
|
self.$frame.attr({src: self.options.getFrame(self.options.position)});
|
|
|
|
},
|
|
|
|
width: function() {
|
|
|
|
that.css({width: self.options.width + 'px'});
|
|
|
|
stopLoading();
|
|
|
|
self.$frame.attr({src: self.options.getFrame()})
|
|
|
|
.css(getFrameCSS());
|
2012-05-31 18:15:44 +00:00
|
|
|
self.$timeline && self.$timeline.css({width: self.options.width + 'px'});
|
2012-05-28 19:35:41 +00:00
|
|
|
}
|
|
|
|
})
|
2011-09-19 12:29:06 +00:00
|
|
|
.addClass('OxVideoPreview')
|
|
|
|
.css({
|
|
|
|
width: self.options.width + 'px',
|
|
|
|
height: self.options.height + 'px'
|
|
|
|
});
|
2011-08-08 13:58:19 +00:00
|
|
|
|
|
|
|
self.loaded = [];
|
|
|
|
self.queue = [];
|
|
|
|
|
2011-09-30 10:34:33 +00:00
|
|
|
self.$frameElement = $('<div>')
|
2011-08-08 13:58:19 +00:00
|
|
|
.addClass('OxFrame')
|
2012-06-26 16:21:39 +00:00
|
|
|
.appendTo(that);
|
2011-09-30 10:34:33 +00:00
|
|
|
|
|
|
|
self.$frame = $('<img>')
|
2011-09-29 17:25:50 +00:00
|
|
|
.attr({src: self.options.getFrame(self.options.position)})
|
2011-09-18 06:50:54 +00:00
|
|
|
.css(getFrameCSS())
|
2011-09-30 10:34:33 +00:00
|
|
|
.appendTo(self.$frameElement);
|
2011-08-08 13:58:19 +00:00
|
|
|
|
2012-06-10 18:18:03 +00:00
|
|
|
if (self.options.timeline) {
|
2012-05-31 18:15:44 +00:00
|
|
|
self.$timeline = $('<img>')
|
|
|
|
.addClass('OxTimeline')
|
|
|
|
.attr({src: self.options.timeline})
|
|
|
|
.css({width: self.options.width + 'px'})
|
2012-06-26 16:21:39 +00:00
|
|
|
.appendTo(that);
|
2012-05-31 18:15:44 +00:00
|
|
|
}
|
2011-08-08 13:58:19 +00:00
|
|
|
|
|
|
|
self.$interface = Ox.Element({
|
|
|
|
tooltip: function(event) {
|
2012-01-30 20:48:19 +00:00
|
|
|
// e.offsetX does not work in Firefox
|
2011-08-17 18:57:58 +00:00
|
|
|
var position = getPosition(event.clientX - that.offset().left);
|
2012-01-30 20:48:19 +00:00
|
|
|
self.$frame.attr({src: getClosestFrame(position)});
|
|
|
|
self.timeout && clearTimeout(self.timeout);
|
|
|
|
self.timeout = setTimeout(function() {
|
|
|
|
self.$frame.attr({src: self.options.getFrame(position)});
|
|
|
|
}, 250);
|
2011-08-08 13:58:19 +00:00
|
|
|
return Ox.formatDuration(position, 2);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.addClass('OxInterface')
|
2012-05-28 14:06:22 +00:00
|
|
|
.on({
|
2011-08-08 13:58:19 +00:00
|
|
|
click: click,
|
|
|
|
mouseenter: startLoading,
|
|
|
|
mouseleave: function() {
|
|
|
|
stopLoading();
|
2012-01-30 20:59:07 +00:00
|
|
|
self.$frame.attr({src: self.options.getFrame(self.options.position)});
|
2011-08-08 13:58:19 +00:00
|
|
|
}
|
|
|
|
})
|
2012-06-26 16:21:39 +00:00
|
|
|
.appendTo(that);
|
2011-08-08 13:58:19 +00:00
|
|
|
|
|
|
|
function click(e) {
|
|
|
|
that.triggerEvent('click', {
|
2011-09-18 06:50:54 +00:00
|
|
|
// e.offsetX does not work in Firefox
|
2011-08-17 18:57:58 +00:00
|
|
|
position: getPosition(e.clientX - that.offset().left)
|
2011-08-08 13:58:19 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2012-01-30 20:48:19 +00:00
|
|
|
function getClosestFrame(position) {
|
|
|
|
return self.loaded.length == 0
|
|
|
|
? self.options.getFrame(self.options.position)
|
|
|
|
: self.loaded.sort(function(a, b) {
|
|
|
|
return Math.abs(a.position - position) - Math.abs(b.position - position);
|
|
|
|
})[0].frame;
|
|
|
|
}
|
|
|
|
|
2011-09-18 06:50:54 +00:00
|
|
|
function getFrameCSS() {
|
2011-09-30 10:34:33 +00:00
|
|
|
var css = {},
|
|
|
|
elementWidth = self.options.width,
|
2012-05-31 18:15:44 +00:00
|
|
|
elementHeight = self.options.height - (self.options.timeline ? 16 : 0),
|
2011-09-30 10:34:33 +00:00
|
|
|
elementRatio = elementWidth / elementHeight,
|
|
|
|
frameRatio = self.options.frameRatio,
|
|
|
|
frameIsWider = frameRatio > elementRatio;
|
|
|
|
if (self.options.scaleToFill) {
|
|
|
|
css.width = frameIsWider ? elementHeight * frameRatio : elementWidth;
|
|
|
|
css.height = frameIsWider ? elementHeight : elementWidth / frameRatio;
|
|
|
|
css.marginLeft = frameIsWider ? (elementWidth - css.width) / 2 : 0;
|
|
|
|
css.marginTop = frameIsWider ? 0 : (elementHeight - css.height) / 2;
|
2011-09-18 21:17:39 +00:00
|
|
|
} else {
|
2011-09-30 10:34:33 +00:00
|
|
|
css.width = frameIsWider ? elementWidth : elementHeight * frameRatio;
|
|
|
|
css.height = frameIsWider ? elementWidth / frameRatio : elementHeight;
|
2012-05-31 18:15:44 +00:00
|
|
|
css.marginLeft = frameIsWider ? 0 : (elementWidth - css.width) / 2;
|
|
|
|
css.marginTop = frameIsWider ? (elementHeight - css.height) / 2 : 0;
|
2011-09-18 06:50:54 +00:00
|
|
|
}
|
2011-09-18 21:17:39 +00:00
|
|
|
return Ox.map(css, function(value) {
|
2011-09-30 10:34:33 +00:00
|
|
|
return Math.round(value) + 'px';
|
2011-09-18 21:17:39 +00:00
|
|
|
});
|
2011-09-18 06:50:54 +00:00
|
|
|
}
|
|
|
|
|
2011-08-08 13:58:19 +00:00
|
|
|
function getPosition(x) {
|
|
|
|
return Math.round(
|
2011-09-18 06:50:54 +00:00
|
|
|
self.options.duration * x / self.options.width * self.options.fps
|
2011-08-08 13:58:19 +00:00
|
|
|
) / self.options.fps;
|
|
|
|
}
|
|
|
|
|
|
|
|
function startLoading() {
|
|
|
|
var last,
|
2011-09-18 06:50:54 +00:00
|
|
|
steps = [Math.round(self.options.width / 2)];
|
2011-08-08 13:58:19 +00:00
|
|
|
while ((last = steps[steps.length - 1]) > 1) {
|
|
|
|
steps.push(Math.round(last / 2));
|
|
|
|
}
|
|
|
|
steps.forEach(function(step) {
|
2011-09-18 06:50:54 +00:00
|
|
|
Ox.loop(0, self.options.width, step, function(x) {
|
2012-01-30 20:48:19 +00:00
|
|
|
var position = getPosition(x),
|
|
|
|
frame = self.options.getFrame(position);
|
2012-05-21 06:40:40 +00:00
|
|
|
if (!self.loaded.some(function(image) {
|
|
|
|
return image.frame == frame;
|
|
|
|
}) && !self.queue.some(function(image) {
|
|
|
|
return image.frame == frame;
|
|
|
|
})) {
|
2012-01-30 20:48:19 +00:00
|
|
|
self.queue.push({frame: frame, position: position});
|
2011-08-08 13:58:19 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2012-01-30 20:48:19 +00:00
|
|
|
self.queue.length && loadFrame();
|
2011-08-08 13:58:19 +00:00
|
|
|
function loadFrame() {
|
2012-01-30 20:48:19 +00:00
|
|
|
var image = self.queue.shift();
|
2011-08-08 13:58:19 +00:00
|
|
|
$('<img>')
|
|
|
|
.load(function() {
|
2012-01-30 20:48:19 +00:00
|
|
|
self.loaded.push(image);
|
2011-08-08 13:58:19 +00:00
|
|
|
self.queue.length && loadFrame();
|
|
|
|
})
|
2012-01-30 20:48:19 +00:00
|
|
|
.attr({src: image.frame})
|
2011-08-08 13:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function stopLoading() {
|
|
|
|
self.queue = [];
|
2012-01-30 20:59:07 +00:00
|
|
|
self.timeout && clearTimeout(self.timeout);
|
2011-08-08 13:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return that;
|
|
|
|
|
2011-08-17 18:57:58 +00:00
|
|
|
};
|