jsで指定された秒数を掛けて長さを調節するcssアニメーション
2022-11-15
概要
指定したpx幅または%幅まで、特定の時間を掛けて伸びる(または縮む)単純なcssアニメーション
...のようなものを頻繁に行う機会があったようで(?) シンプルめなクラスとしてこさえたかった。
コード
先に使い方のイメージから。
インスタンス化する時、cssアニメを仕込みたいセレクタを与えます
{
// ※ css に記載されているであろう、
// ゲージの基礎デザインを組んだセレクタ名と同じものを指定
const _searchSelectorName = ".gauge"; // この要素名を対象
const _gaugeManager = new GaugeWidthKeyframeAnimationManager( _searchSelectorName );
// 紐づけする
_gaugeManager.setBindNode( _gaugeNode );
// 開始位置 , 終了位置 , アニメーション時間秒
// (100px 幅から 250px まで、5秒かけて伸びる)
_gaugeManager.startAnimation( "100px" , "250px" , 5);
}
なお、%指定も可
( ↓ 幅10% から 95% まで、5秒の時間を掛けて伸びる )
_gaugeManager.startAnimation( "10%" , "95%" , 5);
以下、先述の例で用いる単体のクラス。
これを使います
/**
* 任意の幅で開始⇔終了する横幅ゲージ操作を意図したCSS-keyframesアニメーションを動的?にアレコレする雰囲気のクラス
*/
class GaugeWidthKeyframeAnimationManager{
constructor(_selectorName){
const _baseCss = GaugeWidthKeyframeAnimationManager._innerSccRuleSearchFromSelectorName(_selectorName);
if(!_baseCss){
throw "セレクタ文字列から、参照先のCSSを見つけられませんでした";
}
this._cssRules = _baseCss;
this._targetNode;
this._keyframeRule;
}
/**
* セレクタ―名と合致するCSS定義を掘り出して内部に格納させておく。
* このメソッドはクラス外から呼ぶ事を想定していない
* @param {string} _selectorName
* @returns
*/
static _innerSccRuleSearchFromSelectorName(_selectorName){
const _TargetSelectorName = _selectorName;
for(let _s of document.styleSheets){
const _rules = _s.cssRules;
//console.log(_rules);
for(let _r of _rules){
//console.log(_r);
// @ts-ignore
const _selectorTxt = _r.selectorText;
//console.log(_selectorTxt);
if(_selectorTxt === _TargetSelectorName){
// ▼ CSSStyleRule または CSSKeyframesRule を返す
return _r;
}
}
}
};
/**
* 取り扱うノードをここで紐づける
* @param {*} _node
*/
setBindNode(_node){
this._targetNode = _node;
}
/**
* 御膳立てのち、実際にアニメーション諸々を行う事項系メソッド
* @param {string} _start 開始位置(単位付き必須)
* @param {string} _end 終了位置(単位付き必須)
* @param {string|number} _second 秒数
*/
startAnimation(_start , _end , _second){
// [1]. 単発の @keyframes を作成
const _keyFrameRandName = "kf"+(new Date()).getTime(); // ほぼ一意の名前にしとこ...(適当) 先頭が数値だとNGなので、適当な接頭辞を付けた
const _kfCssText = `@keyframes ${_keyFrameRandName}{0%{width:${_start};} 100%{width:${_end};}}`;
this._keyframeRule = _kfCssText;
// [2]. 既存のゲージターゲットデザインcss に [1] で作った物を呼び出す animation をセット
//const _txt = "animation: 10s linear 0s normal forwards running gauge_width;"
const _txt = `${_second}s linear 0s normal forwards running ${_keyFrameRandName}`;
const _rules = this._cssRules;
// [3]. 終了時にCSSを外すイベントを仕込んでおく
this._targetNode.addEventListener("animationend" , (_e)=>{
// 都度 @keyframes を document.styleSheets 内に積み上げ続ける感じになってしまうので、
// アニメーションが終わった時点で生成時と同じ名前の @keyframes を削除する。
// しかしただ削除しただけだと、横幅がリセットされてしまうので、.style で直接 width [n] へと書き換えてフィニッシュ
//console.log(_e);
if(_e.type === "animationend"){
const _delCssName = _e.animationName;
for(let _s of document.styleSheets){
const _rules = _s.cssRules;
for(let _c=0; _c < _rules.length; _c++){
const _r = _rules.item(_c);
// @ts-ignore
if(_r.name === _delCssName){
//console.log(`削除対象の@keyframes Index:${_c}`);
// 削除直前に、直接横幅を終了値で固定させる。
this._targetNode.style.width = `${_end}`;
_s.deleteRule(_c); // 削除
}
}
}
}
});
// CSSを適用
this._targetNode.style.animation = _txt;
_rules.parentStyleSheet?.insertRule( _kfCssText);
}
}
サンプル・動作確認コピペ用
下記コピペにて hoge.html
と main.js
の2ファイルをこさえたのち、
hoge.html
を開いてボタンを押すと cssアニメーションが始まります。
複数パターン動くべ? という感じにしたかったので、その辺も別処理を仕込みました。
html側
html内部に .gauge
という style を1つ放り込んでます
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
html{
height:250px;
width:100%;
}
/*
* ゲージ幅の基礎デザインCSS
* 今回用意したクラスに渡した引数と合わせる
* → そうする事で、このCSS情報がJS,クラス側で参照される
* 横幅は後付けの @keyframes で与えられるので、このstyle自体では width を設定しない事
* ( 固定したければ、このスタイルの親ノード側などで制限を掛ける運用が望ましい )
*/
.gauge{
border-bottom:2px solid #5050FF;
}
</style>
<title>ゲージ幅 @keyframes 的なヤツ</title>
</head>
<body>
<div>
<p>任意の開始位置→終了位置 で止まる 横幅操作系のCSSアニメーションを動的に作成適用させるクラスのサンプル<br>
構成は html 内部に書かれた style と <a href="./main.js" target="_blank">main.js</a> をそれぞれご覧いただければと。</p>
</div>
</body>
<script async src="main.js"></script>
</html>
js側
main.js
として作成します。
クラス部分は上記と重複するので削りました。
( 最初に紹介した GaugeWidthKeyframeAnimationManager
単体クラスをまるっと、以下のコード上部に貼り付ければOK )
// 【!】 先に GaugeWidthKeyframeAnimationManager クラスをここへコピペで貼り付けておいてください
// =================== 実処理デモ ====================================
{
// ただのサンプル用引数集合体。 % なのか px なのか、単位を忘れずに。
const _sampleParams = [
["0%","25%",3] ,
["25%","50%",3] ,
["50%","75%",3] ,
["75%","100%",3] ,
["0%","100%",5] ,
["80%","100%",3] ,
["20%","30%",2] ,
["300px","400px",3] , // px
["100px","250px",3] , // px
];
let _sampleIndex = 0;
// サンプルボタン作成
const _btn = document.createElement("Button");
_btn.textContent = "デモ用ボタン";
_btn.addEventListener("click",()=>{
// ボタン押すたび引数サンプル用の配列を引っ張り出すだけ。
if(_sampleIndex >= _sampleParams.length){
_sampleIndex = 0;
}
const _param = _sampleParams[_sampleIndex];
_sampleIndex++;
const _gaugeNode = document.createElement("div");
_gaugeNode.classList.add("gauge");
const _txt = `${_param[0]} → ${_param[1]} を ${_param[2]} 秒で再現`;
_gaugeNode.textContent = _txt;
document.body.appendChild( _gaugeNode );
// 使い方
// =============================================================
// ========== ▼ コア部分 =======================================
{
// ※ css に記載されているであろう、ゲージの基礎デザインを組んだセレクタ名と同じものを指定
const _searchSelectorName = ".gauge";
const _gaugeManager = new GaugeWidthKeyframeAnimationManager( _searchSelectorName );
// 紐づけする
_gaugeManager.setBindNode( _gaugeNode );
// 開始位置 , 終了位置 , アニメーション時間秒
_gaugeManager.startAnimation( _param[0] , _param[1] , _param[2]);
}
// ========== ▲ コア部分 =======================================
// =============================================================
});
document.body.appendChild(_btn);
}