Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/thoda-dev/ffxiv-miniparse. A simple skin for the ACT overlay for Final Fantasy XIV. // Un simple skin pour l'overlay d'ACT pour Final Fantasy XIV.
Something went wrong. Try again.
ffxiv-miniparse spelltimer.html
18 kB · 487 lines
HTML
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488<html><head> <meta charset="utf-8" /> <title></title> <style> * { /* フォント (一部のフォントは上手く適用されない) */ font-family: "Meiryo"; font-size: 12px; }
body, html { margin: 0; }
body { margin: 0.2em; }
html { height: 100%;
/* 外枠 */ /*border: 1px solid rgba(0,0,0,0.1);*/ /* はみ出た内容はスクロールバーを表示させずに隠す * 今のところ、ブラウザへの入力はできないので表示させても無意味 */ overflow: hidden; /* 背景色 */ background-color: transparent; }
.resizeHandle { /* リサイズ用のハンドル * リサイズができる場所はウィンドウ右下の16x16ピクセルの場所 * この部分が完全に透明だとマウス入力が透過してしまってサイズを変更できなくなる */ background-image: url(handle.png); background-position: bottom right; background-repeat: no-repeat; box-sizing: border-box; }
* { color: #DED7BE; text-shadow: -1px 0 2px #795516, 0 1px 2px #795516, 1px 0 2px #795516, 0 -1px 2px #795516; font-weight: 300; /*white-space: nowrap;*/ }
#title { border-bottom: 1px solid #DED7BE; }
/* バーを囲う要素の設定 */ .progress-outer { box-sizing: border-box; position: relative;
/* 背景色 */ background-color: rgba(0, 0, 0, 0.2); /* 枠の色 */ border: 1px solid rgba(192, 192, 192, 0.75); /* 陰の色 */ box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.1); /* 角を丸くする */ border-radius: 3px; /* バーの高さ(指定しないとだめ) */ height: 2em; /* タイトルとの間隔 */ margin-top: 1px; }
.progress-outer:first-child { /* タイトルとの間隔 */ margin-top: 1px; }
/* バーの設定 */ .progress-bar { opacity: 0.75; background-color: purple; position: absolute; height: 100%; border-right: 1px solid rgba(255, 255, 255, 0.7); box-sizing: border-box; border-radius: 3px; }
/* バーに表示されるテキストの設定 */ .progress-text { position: absolute; width: 100%; display: table; table-layout: fixed; height: 100%; }
/* タイマー名のテキスト */ .label-left { display: table-cell; text-align: left; vertical-align: middle; padding-left: 0.5em; white-space: nowrap; }
/* 残り秒数のテキスト */ .label-right { display: table-cell; text-align: right; vertical-align: middle; padding-right: 0.5em; color: #E2EBF5; text-shadow: -1px 0 3px #217AA2, 0 1px 3px #217AA2, 1px 0 3px #217AA2, 0 -1px 3px #217AA2; font-weight: 300; white-space: nowrap; }
</style> <script src="jquery-2.1.1.min.js" type="text/javascript"></script> <script>
// // プラグイン側から以下のような ActXiv オブジェクトとしてデータが提供される // // var ActXiv = { // "timerFrames": [ // { // "name": "スペルタイマー名", // "key": "グループ名|スペルタイマー名", // "color": 色(0xAARRGGBB), // "startCount": タイマーの開始カウント, // "warningCount": タイマーの警告カウント, // "expireCount": タイマーの除去カウント, // "tooltip", "ツールチップ文字列", // "spellTimers": [ // { // "startTime": タイマーがカウントを開始した時刻(1970年1月1日からの経過秒数) // }, // ... // ] // }, // ... // ] // }; // // データの更新は 1 秒毎 // プラグインからの更新の通知はないので、ひたすらこちら側で更新し続ける //
/* // テスト用データ var ActXiv = { timerFrames: [ { "color": -16776961, // 0xFF0000FF "expireCount": -5, "key": " general|Timer1", "name": "Timer1", "startCount": 30, "tooltip": "", "warningCount": 10, "spellTimers": [ { "startTime": createTimestamp(-10) }, { "startTime": createTimestamp(-5) }, { "startTime": createTimestamp() }, ] }, { "color": -65536, // 0xFFFF0000 "expireCount": -5, "key": " general|Timer2", "name": "Timer2", "startCount": 20, "tooltip": "", "warningCount": 10, "spellTimers": [ { "startTime": createTimestamp(-10) }, { "startTime": createTimestamp(-5) }, { "startTime": createTimestamp() }, ] }, ] }; function createTimestamp(dSecs) { var jsDate = new Date(); var offsetMinutes = new Date().getTimezoneOffset(); var jsTime = jsDate.getTime() - offsetMinutes * 60 * 1000;
var delta = 0; if (typeof dSecs == "number") { delta = dSecs * 1000; }
return jsTime + delta; } */
// onOverlayStateUpdate イベントを購読 document.addEventListener("onOverlayStateUpdate", function (e) { if (!e.detail.isLocked) { displayResizeHandle(); } else { hideResizeHandle(); } });
function displayResizeHandle() { document.documentElement.classList.add("resizeHandle"); }
function hideResizeHandle() { document.documentElement.classList.remove("resizeHandle"); }
function initialize() { update(); setInterval("update()", 500); }
// ★表示の流れ // // ActXiv オブジェクトに新しいタイマーがないかチェック // → timerFrame.onlyMasterTicks && !timerFrame.absoluteTiming なら、最新のタイマーで上書き // → あったらバー作成&アニメーション開始(アニメーション時間はバーの残り時間) // → 作成したバーを残り時間に応じた場所に挿入 // → 作成済みのバーの中に期限切れのものがないかをチェック // → あったら除去 // → 最初に戻る
var bars = [];
// 表示要素の更新 function update() { if (typeof(ActXiv) == 'undefined') { return; }
var containerDiv = document.getElementById('spelltimer'); if (typeof(ActXiv.timerFrames) != 'undefined') { ActXiv.timerFrames.forEach(function (timerFrame) { // 1 つのみ許容&最新のタイマーで上書きされる設定の場合 if (timerFrame.spellTimers.length > 0 && timerFrame.onlyMasterTicks && !timerFrame.absoluteTiming) { // 最新のタイマーを捜す var latestSpellTimer; timerFrame.spellTimers.forEach(function (spellTimer) { if (typeof(latestSpellTimer) == 'undefined') { // 初回 latestSpellTimer = spellTimer; } else if (latestSpellTimer.startTime < spellTimer.startTime) { // 2 回目以降 latestSpellTimer = spellTimer; } }); // 最新のタイマーのみを処理にかける processActXivTimerEntry(containerDiv, timerFrame, latestSpellTimer); } else { // そうでない場合はすべてのタイマーを処理にかける timerFrame.spellTimers.forEach(function (spellTimer) { processActXivTimerEntry(containerDiv, timerFrame, spellTimer); }); } }); }
// バーの更新と期限切れバーの削除 var newBars = []; for (var i = 0; i < bars.length; i++) { if (!bars[i].spellTimer.getIsExpired()) { // 期限切れではない bars[i].updateBar(); // バー更新 newBars.push(bars[i]); } else { bars[i].removeBarElement(); // バーを親要素から削除 } } bars = newBars;
ActXiv = {}; }
function processActXivTimerEntry(container, _tf, _st) { var spellTimer = new SpellTimer(_tf, _st);
if (spellTimer.getIsExpired()) { return; // 渡されたデータが既に期限切れだった場合は何もせずに次へ };
var bar = getTimerBarFromList(spellTimer);
// リセットが必要な場合、既に存在するバーを消して作り直す if (typeof (bar) == 'undefined' && _tf.onlyMasterTicks && !_tf.absoluteTiming) { for (var i = bars.length - 1; i >= 0; i--) { if (bars[i].spellTimer.key == _tf.key) { bars[i].removeBarElement(); bars.splice(i, 1); } } }
if (typeof(bar) == 'undefined') { bar = new TimerBar(spellTimer);
// テキストの表示方法を設定 bar.setBarLabel(function (_st) { var nameText = _st.name; var remaining = _st.getRemaining(); var timerText; if (remaining <= 0) { timerText = "READY"; // カウントが0以下なら READY と表示 } else { timerText = _st.getRemaining().toFixed(0) + "s"; // それ以上ならカウントを表示 }
return "<span class='label-left'><span class='timer-name'>" + nameText + "</span>:</span>" + "<span class='label-right timer-remaining'>" + timerText + "</span>"; }); bar.useHTMLLabel = true; // HTML で表示する // 色設定 bar.setBarColor(getColorCodeFromNumber(bar.spellTimer.color)); // バーの高さ設定 //bar.setBarHeight(20); // 残り時間を考慮してリストに追加 var i; var inserted = false; for (i = 0; i < bars.length; i++) { if (spellTimer.getRemaining() < bars[i].spellTimer.getRemaining()) { bars.splice(i, 0, bar); inserted = true; break; } } if (!inserted) { bars.push(bar); }
// 並び順を考慮してコンテナに追加 var nextElement; if (bars[i + 1]) { nextElement = bars[i + 1].barElement; } container.insertBefore(bar.barElement, nextElement) } }
function getTimerBarFromList(spellTimer) { var uniqueName = TimerBar.createUniqueName(spellTimer); for (var i = 0; i < bars.length; i++) { if (bars[i].uniqueName == uniqueName) { return bars[i]; } } return; }
// SpellTimer オブジェクト var SpellTimer = (function (tf, st) { this.color = tf.color; this.expireCount = tf.expireCount; this.key = tf.key; this.name = tf.name; this.startCount = tf.startCount; this.tooltip = tf.tooltip; this.warningCount = tf.warningCount; this.startTime = st.startTime; }); SpellTimer.prototype = { getIsExpired: function () { if (this.getRemaining() < this.expireCount) { return true; } else { return false; } }, getElapsed: function() { return getElapsedSeconds(this.startTime); }, getRemaining: function () { return this.startCount - this.getElapsed(); } };
// TimerBar オブジェクト var TimerBar = (function (_spellTimer) {
this.spellTimer = _spellTimer;
this.uniqueName = TimerBar.createUniqueName(this.spellTimer); this.barElement = this._createProgressBarElement(); this.labelFunc = (function (_bar) { return ""; }); this.useHTMLLabel = false;
}); TimerBar.createUniqueName = function (spellTimer) { return "TBAR_" + spellTimer.name + "_" + spellTimer.startTime.toString(); } TimerBar.prototype = { setBarLabel: function (strOrFunc) { if (typeof (strOrFunc) == "function") { this.labelFunc = strOrFunc; } else { this.labelFunc = function () { return strOrFunc; }; } }, setBarColor: function (color) { this.barElement.children[0].style.backgroundColor = color; }, setBarHeight: function (height) { this.barElement.style.height = height; }, updateBar: function () { var text = this.labelFunc(this.spellTimer); if (this.useHTMLLabel) { this.barElement.children[1].innerHTML = text; } else { this.barElement.children[1].innerText = text; } }, _createProgressBarElement: function () { var outerDiv = document.createElement("div"); outerDiv.className = "progress-outer"; var barDiv = document.createElement("div"); barDiv.className = "progress-bar"; var textDiv = document.createElement("div"); textDiv.className = "progress-text";
outerDiv.appendChild(barDiv); outerDiv.appendChild(textDiv);
var percentage = Math.max(0, Math.min(1, this.spellTimer.getRemaining() / this.spellTimer.startCount)) * 100; barDiv.style.width = percentage.toFixed(2) + "%"; setTimeout(function(barDiv) { barDiv.style.backgroundColor = "#FF0000"; }, Math.max(0, (this.spellTimer.getRemaining() - this.spellTimer.warningCount) * 1000), barDiv);
$(barDiv).animate( { width: "0%" }, Math.max(0, this.spellTimer.getRemaining() * 1000), "linear");
return outerDiv; }, removeBarElement: function () { this.barElement.parentElement.removeChild(this.barElement); } };
function getElapsedSeconds(startTime) { var jsDate = new Date(); var offsetMinutes = new Date().getTimezoneOffset(); var jsTime = jsDate.getTime() - offsetMinutes * 60 * 1000;
return (jsTime - startTime) / 1000; }
function formatTimeSpan(seconds) {
}
function getColorCodeFromNumber(number) { // 各要素を取得 var alpha = ((number >> 24) & 0xFF) / 255.0; var red = (number >> 16) & 0xFF; var green = (number >> 8) & 0xFF; var blue = number & 0xFF;
// rgba(red, green, blue, alpha) return "rgba(" + red + ", " + green + ", " + blue + ", " + alpha + ")"; }
</script></head><body onload="initialize();">
<div id="title"> Timer </div>
<div id="spelltimer"> </div>
</body></html>