♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人
ランダムな画像をランダムにフェードさせながら入れ替える Ver.4
Ver.3をほぼ全面改訂。
Promiseやfetch()を使ってみたりなど内部的な修正がメインで、機能的な追加はVer.3では実装漏れとなっていた「複数ヶ所の画像をランダムに表示させる」ことに対応させたことくらい。
ということで、使い方や設定方法に変更はありません。
設定方法
- ランダムに表示させる画像を「1.jpg」「2.jpg」…、または「img1.jpg」「img2.jpg」…、など「1」から始まる連番の通し番号付きで用意してください
「01.jpg」「img01.jpg」など、桁数揃えのために「0」でパディングさせていてもOKです - 画像の種類(jpg、pngなど)は自由です(ただし同一フォルダ内では統一してください)
また、画像のサイズには基本的に制約されません(画像の縦横比が揃っていればOK) - HTMLに元々記述された画像はロード前にランダムな画像に差し替えられます
最初に表示する画像を固定のものにしたい場合(例えば"Loading"画像など)は「0.jpg」「00.jpg」「img0.jpg」など、「0」番を振った画像を用意してください
なお、0番の画像はランダム表示の対象からは除外され、1番からMax番までの画像がランダム表示の対象となります
また、0番の画像を用意する場合、ファイル名の命名規則ならびに画像の種類(拡張子)は1番以降のランダムさせる画像と同じである必要があります - CSSでは、画像のサイズと親要素のサイズをあらかじめ揃えておいてください
<!-- HTML --> <figure class="img_container"> <img id="random_image" src="http://example.com/random/1.jpg" /> </figure>
/* CSS */ .img_container { width : 16em; height : 12em; } #random_image { width : 16em; height : 12em; }
- imgSettingsで
// [画像の総枚数, 画像のid, フェード方法, フェード秒, ループ間隔], // [画像2の総枚数, 画像2のid, フェード方法, フェード秒, ループ間隔] [10, 'random_image', 'ease', '1.5s', '10s'], [10, 'random_image2', 'cubic-bezier(0,0,1,1)', '1500ms', '10s'], [24, '#random_photo', 'random', '2s', '15s']
といった形でランダム表示させる画像群の情報を持たせた配列を作成してください - 複数のページでランダム表示を使用したい場合もそれぞれの設定をまとめて記述できます
- 画像の総枚数は最後の画像の番号(最大値)です
- 画像idの"#"はあってもなくてもOKです
- フェード方法は、'random'を指定すればランダムに行われます
一意の値で固定したい場合は、CSS3のtransition-timing-functionに基づき、'ease'、'linear'、'ease-in'、'ease-out'、'ease-in-out'のキーワードか、'cubic-bezier(x1,y1,x2,y2)'で指定してください
なお、x1、y1、x2、y2はいずれも0~1の範囲内で収めてください
マイナス値や1より大きい値だと無視されます - フェード秒とループ間隔は、'1500ms'や'20s'などCSS3の<time>で指定してください
- 外部スクリプト化してHTMLから呼び出せばOKです
JavaScriptソース(最終更新:2016/2/5)
/**
* imgFader Ver 4.1.1
* 画像をフェードさせながらランダムに入れ替え
* Copyright (c) 2015-2016 Kazz
* http://asamuzak.jp
* Dual licensed under MIT or GPL
* http://asamuzak.jp/license
*/
(function(_win, _doc) {
"use strict";
var imgFaderSettings = [
// ランダム表示する画像群の配列(画像群毎にカンマ区切りで配列を追加)
// [画像の総枚数, 画像のid, フェード方法, フェード秒, ループ間隔]
// 例)
// [10, "random_image", "random", "1.5s", "5s"],
// [10, "random_image2", "ease", "1500ms", "5s"],
// [24, "#random_photo", "random", "2s", "10s"]
];
function isType(o, t) {
return (o = o && Object.prototype.toString.call(o).slice(8, -1)) &&
(t ? new RegExp("^" + t + "$", "i").test(o) : o);
}
/*
* setZeroTimeout() (revised by Kazz)
* Original: David Baron's weblog: setTimeout with a shorter delay
* http://dbaron.org/log/20100309-faster-timeouts
*/
var _Z = {};
function setZeroTimeout(o, p) {
isType(o, "Function") && isType(p, "String") && (
!_Z[p] && (_Z[p] = o),
_win.postMessage(p, "*")
);
}
function clearZeroTimeout(p) {
isType(p, "String") && _Z[p] && (_Z[p] = null);
}
function handleZeroTimeoutMessage(evt) {
var x = evt.data, y = _Z[x];
y && evt.source === _win && (
evt.stopPropagation(),
clearZeroTimeout(x),
y()
);
}
_win.addEventListener("message", handleZeroTimeoutMessage, true);
function imgFader() {
var aObj = {},
_C = /Chrome\/4[012]\.(?!.+Edge)/.test(_win.navigator.userAgent); // Chromeのバグへの暫定処置
function animateFade(o, x1, y1, x2, y2) {
function getBezierSplineAtP(x1, y1, x2, y2, p) {
var x, y, a, b, c, i;
if(x1 === y1 && x2 === y2) {
x = p;
}
else {
for(y = p, a = (1 - 3 * (x2 - x1)), b = (3 * (x2 - 2 * x1)), c = (3 * x1), i = 0; i < 4; i++) {
x = 3 * a * y * y + 2 * b * y + c;
if(x === 0) {
break;
}
y -= (((a * y + b) * y + c) * y - p) / x;
}
x = (((1 - 3 * (y2 - y1)) * y + 3 * (y2 - 2 * y1)) * y + 3 * y1) * y;
}
return x.toFixed(4);
}
var x, y = _doc.getElementById(o.id);
if(y) {
x = _win.performance && _win.performance.now ? _win.performance.now() : new Date().getTime();
o.aStart === 0 && (o.aStart = x);
x = (x - o.aStart) / o.aDuration * 1;
if(x >= 0 && x <= 1) {
y.style.setProperty("opacity", (1 - (getBezierSplineAtP(x1, y1, x2, y2, x) * 1)) + "", "");
setZeroTimeout(function() { animateFade(o, x1, y1, x2, y2); }, o.id);
}
else {
y.setAttribute("src", setDigit(o));
y.style.setProperty("opacity", "1", "");
o.aStart = 0;
setNextImg(o);
}
}
}
function setDigit(o) {
var l = o.aDigit.length, x = o.aNext + "", i;
if(x.length < l) {
for(i = 1; i < l; i++) {
x = "0" + x;
}
}
return o.aSrc + x + o.aExt;
}
function setNextImg(o) {
function setFunc() {
var a = [
"0.25,0.1,0.25,1",
"0,0,1,1",
"0.42,0,1,1",
"0,0,0.58,1",
"0.42,0,0.58,1",
"0.47,0,0.745,0.715",
"0.39,0.575,0.565,1",
"0.445,0.05,0.55,0.95",
"0.55,0.085,0.68,0.53",
"0.25,0.46,0.45,0.94",
"0.455,0.03,0.515,0.955",
"0.55,0.055,0.675,0.19",
"0.215,0.61,0.355,1",
"0.645,0.045,0.355,1"
];
return "cubic-bezier(" + a[Math.floor(Math.random() * a.length)] + ")";
}
var x = o.aMax, y = o.aNext, z = Math.floor(Math.random() * x) + 1,
x1, y1, x2, y2;
while(z === y) {
z = Math.floor(Math.random() * x) + 1;
}
o.aNext = z;
z = o.aFunc === "random" ? setFunc() : o.aFunc;
x = /cubic\-bezier\(\s*([01]?(?:\.[0-9]+)?)\s*,\s*([01]?(?:\.[0-9]+)?)\s*,\s*([01]?(?:\.[0-9]+)?)\s*,\s*([01]?(?:\.[0-9]+)?)\s*\)/.exec(z);
x && (x1 = x[1] * 1, y1 = x[2] * 1, x2 = x[3] * 1, y2 = x[4] * 1);
if(x && x1 <= 1 && y1 <= 1 && x2 <= 1 && y2 <= 1) {
y = _doc.getElementById(o.id);
if(y) {
y.parentNode.setAttribute("style","background-image:url(" + setDigit(o) + ");background-size:100% 100%;");
if(_win.getComputedStyle(y, "").animationTimingFunction && !_C) {
y.style.setProperty("animation-timing-function", z, "");
y.classList.add("imgFader");
}
else {
o.aStart !== 0 && (o.aStart = 0);
setTimeout(function() {
animateFade(o, x1, y1, x2, y2);
}, o.aDelay);
}
}
}
}
function runImgFader(o) {
if(o.aDigit) {
o.aStart = 0;
setNextImg(o);
}
else {
var x = _win.performance && _win.performance.now ?
_win.performance.now() : new Date().getTime();
(o.aStart === 0 || o.aStart > 0 && (x - o.aStart < o.aDelay)) && (
o.aStart === 0 && (o.aStart = x),
setZeroTimeout(function() {
runImgFader(o);
}, o.id)
);
}
}
function padDigit(o) {
function setDefaultDigit(v) {
var x;
o.aDigit = v;
if(o.aNext > 0) {
x = _doc.getElementById(o.id);
x && (
o.aNext = Math.floor(Math.random() * o.aMax) + 1,
x.setAttribute("src", setDigit(o))
);
}
}
function requestImageHeader(u, c, v) {
var x = new Image();
x.addEventListener("load", function(evt) {
c(v ? v : evt.target);
}, false);
x.src = u;
}
var p = (function(m, n) {
for(var i = 1, l = m.length; i < l; i++) {
n = "0" + n;
}
return n;
})(o.aMax + "", "1"),
q = o.aNext + "",
y, z;
switch(true) {
case /^[0-9]$/.test(q):
setDefaultDigit("1");
break;
case /^0(?:[0-9]){1,}$/.test(q) && q.length === p.length:
setDefaultDigit(p);
break;
default:
y = o.aSrc;
z = o.aExt;
requestImageHeader(y + "1" + z, setDefaultDigit, "1");
p.length > 1 && requestImageHeader(y + p + z, setDefaultDigit, p);
}
}
function removeStyleProp(evt) {
var x = evt.target,
y = aObj[x.id],
z = /animationend/.test(evt.type);
x.setAttribute("src", z ? setDigit(y) : y.aFirst);
x.classList.remove("imgFader");
z ?
setNextImg(y) :
x.style.removeProperty("animation-timing-function");
}
(function(z) {
function convKeywordToBezier(k) {
switch(k) {
case "random":
break;
case "ease":
k = "cubic-bezier(0.25,0.1,0.25,1)";
break;
case "linear":
k = "cubic-bezier(0,0,1,1)";
break;
case "ease-in":
k = "cubic-bezier(0.42,0,1,1)";
break;
case "ease-out":
k = "cubic-bezier(0,0,0.58,1)";
break;
case "ease-in-out":
k = "cubic-bezier(0.42,0,0.58,1)";
break;
default:
k = /cubic\-bezier/.test(k) ? k : false;
}
return k;
}
function setEvents(o) {
var x = _doc.getElementById(o.id);
if(x) {
if(_win.requestAnimationFrame && !_C) {
x.addEventListener("error", removeStyleProp, false);
x.addEventListener("animationend", removeStyleProp, false);
}
else {
x.addEventListener("error", function(evt) {
var a = evt.target, b = aObj[a.id];
a.setAttribute("src", b.aFirst);
a.style.removeProperty("opacity");
}, false);
}
_win.addEventListener("load", function() {
runImgFader(o);
}, false);
}
}
var y;
if(Array.isArray(z)) {
if(_win.requestAnimationFrame && !_C) {
y = _doc.createElement("style");
_doc.querySelector("head").appendChild(y);
y = y.sheet;
y.insertRule("@keyframes imgFader {from{opacity:1;}to{opacity:0;}}", y.cssRules.length);
}
for(var i = 0, l = z.length; i < l; i++) {
var a = z[i];
if(Array.isArray(a) && a.length === 5) {
var b = isFinite(a[0] * 1) ? a[0] * 1 : -1,
c = _doc.getElementById(a[1].replace(/^#/,""));
var d = c && c.src.match(/^((?:.+)\/(?:[^\/]+[^\/0-9])?)([0-9]+)(\.[a-zA-Z0-9]+)$/);
if(b > 1 && c && d) {
var p = d[1],
q = d[2] * 1,
r = d[3],
s = convKeywordToBezier(a[2]),
t = (d = /^([0-9]*(?:\.[0-9]+)?)(m?s)$/.exec(a[3])) &&
/ms/.test(d[2]) ? d[1] * 1 : d[1] * 1000,
u = (d = /^([0-9]*(?:\.[0-9]+)?)(m?s)$/.exec(a[4])) &&
/ms/.test(d[2]) ? d[1] * 1 : d[1] * 1000;
if(s && t && u) {
d = c.id;
aObj[d] = {
id: d,
aMax: b,
aFirst: c.src,
aSrc: p,
aNext: q,
aExt: r,
aFunc: s,
aDuration: t,
aDelay: u,
aDigit: null,
aStart: 0
};
y && y.insertRule("#" + d + ".imgFader{animation:imgFader " + t + "ms " + (s !== "random" ? s + " " : "") + u + "ms;}", y.cssRules.length);
setEvents(aObj[d]);
padDigit(aObj[d]);
}
}
}
}
}
})(imgFaderSettings);
}
_doc.addEventListener("DOMContentLoaded", imgFader, false);
})(window, document);
"♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人"へのTwitter上でのコメントやRT
8件のツイートがあります。
ツイート 1
asamuzaK.jp : ♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人 ~ ランダムな画像をランダムにフェードさせながら入れ替える Ver.4 http://t.co/1jHxp0yV7V
ツイート 2
ベジェ曲線から値を取得する関数を整理してみた http://t.co/6JNbw7XvxQ http://t.co/1jHxp0yV7V
ツイート 3
Androidブラウザ(4.0)だと画像入れ替え時にフェードしていなかった…orz 入れ替え自体は正常に行われている asamuzaK.jp : ♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人 http://t.co/1jHxp0yV7V
ツイート 4
気が変わってPromiseをこの関数で使うのはやめた… asamuzaK.jp : ♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人 http://t.co/1jHxp0yV7V
ツイート 5
これだ asamuzaK.jp : ♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人 http://t.co/1jHxp0yV7V
ツイート 6
Edgeが過去のChrome向けのバグ対策に引っかからないように微修正 asamuzaK.jp : ♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人 http://t.co/1jHxp0yV7V
ツイート 7
教えていただいた正規表現で再修正しました https://t.co/DBkqLuGJmU ついでにこちらも直しておきましたw https://t.co/1jHxp0yV7V https://t.co/oF54yPsEuS
ツイート 8
こちらも一部書き直し asamuzaK.jp : ♪フェードイン フェードイン たちまち溢れる神秘の力 (c) 子門真人 ~ ランダムな画像をランダムにフェードさせながら入れ替える Ver.4 https://t.co/1jHxp0yV7V