Можно ли получить альтернативное изображение src вместо другого, если исходное src меньше по масштабу на «x» пикселей (ширина / высота)?
Чтобы быть более наглядным, я работаю над разработкой скрипта, который накладывает высококачественное миниатюрное изображение на iframe видео. Для видео в формате HD (например, 720p и 1080p) они возвращают полноразмерную миниатюру maxresdefault
.
Однако для видео, которые не в формате HD (видео с разрешением меньше 720p), они генерируют очень маленькое изображение maxresdefault.jpg
, которое я бы предпочел вместо этого заменить миниатюрой hqdefault.jpg
.
Вот фрагмент сценария, с которым я сейчас работаю:
;
(function($, window, document, undefined) {
"use strict";
var defaults = {
darkenThumbnail: false
};
function YouTubeHDThumbnail(element, options) {
this.elem = element;
this.$elem = $(element);
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = 'youTubeHDThumbnail';
this.init();
}
$.extend(YouTubeHDThumbnail.prototype, {
init: function() {
this.videoId = null,
this.$thumbnail = null;
// retrieve HD thumbnail
var src = this.$elem.attr('src'),
srcSplit = src.split('?'),
srcMain = null,
srcPure = null;
if (srcSplit.length > 0) {
srcMain = srcSplit[0];
srcPure = srcMain.split('/');
this.videoId = srcPure.pop();
this.$thumbnail = $('<a />')
.attr({
'href': '#'
})
.addClass('yt-hd-thumbnail')
.append(
$('<img/>').attr({
'src': 'http://i.ytimg.com/vi/' + this.videoId + '/maxresdefault.jpg'
})
);
} else {
console.info('The src attribute of iframe is not valid.');
return;
}
// create container
var $outerContainer = $('<div />')
.addClass('yt-hd-thumbnail-outer-container')
.insertAfter(this.elem)
.css('width', this.$elem.attr('width')),
$innerContainer = $('<div />')
.addClass('yt-hd-thumbnail-inner-container')
.appendTo($outerContainer);
// insert thumbnail and iframe
if (this.settings.darkenThumbnail) {
this.$thumbnail.addClass('yt-hd-thumbnail-darken');
}
$innerContainer.append(this.$thumbnail).append(this.elem);
// add click handler to thumbnail
var self = this;
this.$thumbnail.on('click', function(e) {
e.preventDefault();
src = src + '&autoplay=1';
$innerContainer.addClass('yt-hd-thumbnail-clicked');
self.$elem.attr({
'src': src
});
});
},
});
$.fn['youTubeHDThumbnail'] = function(options) {
return this.each(function() {
if (!$.data(this, "plugin_" + 'youTubeHDThumbnail')) {
$.data(this, "plugin_" +
'youTubeHDThumbnail', new YouTubeHDThumbnail(this, options));
}
});
};
})(jQuery, window, document);
/* YouTube HD Thumbnails / Add HD Class */
$(document).ready(function() {
$('iframe[src* = "youtube.com"]').addClass("yt-hd-thumbnail");
});
/* YouTube HD Thumbnails / Thumbnail Hover Effect */
$(document).ready(function() {
$('iframe.yt-hd-thumbnail').youTubeHDThumbnail({
darkenThumbnail: true
});
});
.yt-hd-thumbnail-inner-container {
height: 0;
padding-top: 56.25%;
position: relative
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail,
.yt-hd-thumbnail-inner-container>iframe {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-width: 0
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail {
z-index: 2
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail img {
width: 100%
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail.yt-hd-thumbnail-darken:before {
display: block;
position: absolute;
content: '';
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #000;
opacity: .3;
-webkit-transition: opacity .3s ease;
-moz-transition: opacity .3s ease;
transition: opacity .3s ease
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail.yt-hd-thumbnail-darken:hover:before {
opacity: 0
}
.yt-hd-thumbnail-inner-container>iframe {
max-width: 100%;
opacity: 0;
-webkit-transition: opacity .3s ease .3s;
-moz-transition: opacity .3s ease .3s;
transition: opacity .3s ease .3s
}
.yt-hd-thumbnail-inner-container.yt-hd-thumbnail-clicked>a.yt-hd-thumbnail {
display: none
}
.yt-hd-thumbnail-inner-container.yt-hd-thumbnail-clicked>iframe {
opacity: 1
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b>Video with a Max Resolution of: 480p</b>
<br>
<iframe width = "560" height = "315" src = "https://www.youtube.com/embed/QgfxdTnLdt4?rel=0" frameborder = "0" allow = "autoplay; encrypted-media" allowfullscreen></iframe>
<br>
<b>Video with a Max Resolution of: 1080p</b>
<br>
<iframe width = "560" height = "315" src = "https://www.youtube.com/embed/fPj-mEFPhrA?rel=0" frameborder = "0" allow = "autoplay; encrypted-media" allowfullscreen></iframe>
Кажется, это работает:
/*... */
const thumb = $('<img/>', {
src: 'http://i.ytimg.com/vi/' + this.videoId + '/maxresdefault.jpg'
});
thumb.on('load', () => {
const src = thumb[0].width < 121 ?
'https://cdn.pixabay.com/photo/2015/06/19/17/58/sample-815141_960_720.jpg' :
'http://i.ytimg.com/vi/' + this.videoId + '/maxresdefault.jpg';
this.$thumbnail.append( $('<img/>',{src}) );
});
/*... */
;
(function($, window, document, undefined) {
"use strict";
var defaults = {
darkenThumbnail: false
};
function YouTubeHDThumbnail(element, options) {
this.elem = element;
this.$elem = $(element);
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = 'youTubeHDThumbnail';
this.init();
}
$.extend(YouTubeHDThumbnail.prototype, {
init: function() {
this.videoId = null,
this.$thumbnail = null;
// retrieve HD thumbnail
var src = this.$elem.attr('src'),
srcSplit = src.split('?'),
srcMain = null,
srcPure = null;
if (srcSplit.length > 0) {
srcMain = srcSplit[0];
srcPure = srcMain.split('/');
this.videoId = srcPure.pop();
this.$thumbnail = $('<a />')
.attr({
'href': '#'
})
.addClass('yt-hd-thumbnail')
const thumb = $('<img/>', {
src: 'http://i.ytimg.com/vi/' + this.videoId + '/maxresdefault.jpg'
});
thumb.on('load', () => {
const src = thumb[0].width < 121 ?
'https://cdn.pixabay.com/photo/2015/06/19/17/58/sample-815141_960_720.jpg':
'http://i.ytimg.com/vi/' + this.videoId + '/maxresdefault.jpg';
this.$thumbnail.append(
$('<img/>',{src})
);
});
} else {
console.info('The src attribute of iframe is not valid.');
return;
}
// create container
var $outerContainer = $('<div />')
.addClass('yt-hd-thumbnail-outer-container')
.insertAfter(this.elem)
.css('width', this.$elem.attr('width')),
$innerContainer = $('<div />')
.addClass('yt-hd-thumbnail-inner-container')
.appendTo($outerContainer);
// insert thumbnail and iframe
if (this.settings.darkenThumbnail) {
this.$thumbnail.addClass('yt-hd-thumbnail-darken');
}
$innerContainer.append(this.$thumbnail).append(this.elem);
// add click handler to thumbnail
var self = this;
this.$thumbnail.on('click', function(e) {
e.preventDefault();
src = src + '&autoplay=1';
$innerContainer.addClass('yt-hd-thumbnail-clicked');
self.$elem.attr({
'src': src
});
});
},
});
$.fn['youTubeHDThumbnail'] = function(options) {
return this.each(function() {
if (!$.data(this, "plugin_" + 'youTubeHDThumbnail')) {
$.data(this, "plugin_" +
'youTubeHDThumbnail', new YouTubeHDThumbnail(this, options));
}
});
};
})(jQuery, window, document);
/* YouTube HD Thumbnails / Add HD Class */
$(document).ready(function() {
$('iframe[src* = "youtube.com"]').addClass("yt-hd-thumbnail");
});
/* YouTube HD Thumbnails / Thumbnail Hover Effect */
$(document).ready(function() {
$('iframe.yt-hd-thumbnail').youTubeHDThumbnail({
darkenThumbnail: true
});
});
.yt-hd-thumbnail-inner-container {
height: 0;
padding-top: 56.25%;
position: relative
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail,
.yt-hd-thumbnail-inner-container>iframe {
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-width: 0
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail {
z-index: 2
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail img {
width: 100%
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail.yt-hd-thumbnail-darken:before {
display: block;
position: absolute;
content: '';
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #000;
opacity: .3;
-webkit-transition: opacity .3s ease;
-moz-transition: opacity .3s ease;
transition: opacity .3s ease
}
.yt-hd-thumbnail-inner-container>a.yt-hd-thumbnail.yt-hd-thumbnail-darken:hover:before {
opacity: 0
}
.yt-hd-thumbnail-inner-container>iframe {
max-width: 100%;
opacity: 0;
-webkit-transition: opacity .3s ease .3s;
-moz-transition: opacity .3s ease .3s;
transition: opacity .3s ease .3s
}
.yt-hd-thumbnail-inner-container.yt-hd-thumbnail-clicked>a.yt-hd-thumbnail {
display: none
}
.yt-hd-thumbnail-inner-container.yt-hd-thumbnail-clicked>iframe {
opacity: 1
}
.yt-hd-thumbnail-inner-container a {
overflow: hidden;
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<b>Video with a Max Resolution of: 480p</b>
<br>
<iframe width = "560" height = "315" src = "https://www.youtube.com/embed/QgfxdTnLdt4?rel=0" frameborder = "0" allow = "autoplay; encrypted-media" allowfullscreen></iframe>
<br>
<b>Video with a Max Resolution of: 1080p</b>
<br>
<iframe width = "560" height = "315" src = "https://www.youtube.com/embed/fPj-mEFPhrA?rel=0" frameborder = "0" allow = "autoplay; encrypted-media" allowfullscreen></iframe>
Что я сделал:
.append($('<img />')...)
.<img>
в переменную и дождался его загрузки.load
этого img я проверяю его ширину. Если меньше, чем 121
, я устанавливаю src
на мою красивую картинку. Если нет, я передаю исходный (который уже загружен, следовательно, кешируется).<img>
к this.$thumnail
.121
возникает из-за того, что пиксельное изображение эскиза имеет ширину 120px
.
Отличное решение, это полностью помогло! Немного изменил ваш ответ, чтобы он взял hqdefault.jpg
с YouTube.
У изображений есть события загрузки, и вы можете проверить размеры внутри обратного вызова. Легко исследовать, как