tween24
Version:
Tween24.js is animation library that enables fast coding using method chains.
337 lines (305 loc) • 14.4 kB
text/typescript
import { Tween24 } from "./Tween24";
import { Ease24 } from "./index";
import { Sort24 } from "./index";
import { Event24 } from "./Event24";
import { Text24 } from "./utils/Text24";
import { HTMLUtil } from "./utils/HTMLUtil";
import { ButtonTween24 } from "./ButtonTween24";
export class Button24 {
private static _DEFAULT_IN_EVENT :string = Event24.MOUSE_ENTER;
private static _DEFAULT_OUT_EVENT:string = Event24.MOUSE_LEAVE;
private _targetQuery :string;
private _inEventType :string;
private _outEventType :string;
private _templates :ButtonTween24[];
private _inTweens :Tween24[];
private _outTweens :Tween24[];
private _stopInTweens :Tween24[];
private _stopOutTweens :Tween24[];
private _inEvent :Event24|null;
private _outEvent :Event24|null;
private _stopInEvent :Event24|null;
private _stopOutEvent :Event24|null;
constructor(targetQuery:string, inEventType:string, outEventType:string, templates:ButtonTween24[]) {
this._targetQuery = targetQuery;
this._templates = templates;
this._inEventType = inEventType;
this._outEventType = outEventType;
this._inTweens = [];
this._outTweens = [];
this._stopInTweens = [];
this._stopOutTweens = [];
this._inEvent = null;
this._outEvent = null;
this._stopInEvent = null;
this._stopOutEvent = null;
let needResizse:boolean = false;
for (const template of templates) {
if (template.inTween ) this._inTweens .push(template.inTween);
if (template.outTween ) this._outTweens .push(template.outTween);
if (template.stopInTween ) this._stopInTweens .push(template.stopInTween);
if (template.stopOutTween) this._stopOutTweens.push(template.stopOutTween);
needResizse ||= template.needResize;
}
if (needResizse) this.resizeAndReset();
this._addEvent();
}
private _addEvent = () => {
if (this._inTweens .length) this._inEvent = Event24.add(this._targetQuery, this._inEventType , Tween24.parallel(...this._inTweens));
if (this._outTweens.length) this._outEvent = Event24.add(this._targetQuery, this._outEventType, Tween24.parallel(...this._outTweens));
if (this._stopInTweens .length) this._stopInEvent = Event24.add(this._targetQuery, this._inEventType , Tween24.parallel(...this._stopInTweens )).addStopEvent(this._outEventType);
if (this._stopOutTweens.length) this._stopOutEvent = Event24.add(this._targetQuery, this._outEventType, Tween24.parallel(...this._stopOutTweens)).addStopEvent(this._inEventType);
}
private _onResize = (event:Event) => {
this.reset();
}
private _onResizeTemplate = () => {
for (const template of this._templates) {
template.onResize();
}
}
/**
* アニメーションを設定し直します。
* @memberof Button24
*/
reset = () => {
Tween24.serial(
Tween24.func(Event24.removeAllByTarget, this._targetQuery),
Tween24.func(this._onResizeTemplate),
Tween24.wait(0.01),
Tween24.func(this._addEvent)
).play();
}
/**
* ウィンドウのりサイズ時に、アニメーションを設定し直します。
* @memberof Button24
*/
resizeAndReset = ():Button24 => {
window.addEventListener("resize", this._onResize, false);
return this;
}
/**
* ウィンドウのりサイズ時に、アニメーションを設定し直す設定を解除します。
* @memberof Button24
*/
removeResize = ():Button24 => {
window.removeEventListener("resize", this._onResize, false);
return this;
}
/**
* アニメーションの willChange を有効にするか設定します。
* 有効にすると強力な最適化をブラウザーが行い、アニメーションが滑らかになります。
* @param {boolean} [use=true] willChange を有効にするか
* @memberof Button24
*/
willChange = (use:boolean = true):Button24 => {
this._inEvent ?.willChange(use);
this._outEvent ?.willChange(use);
this._stopInEvent ?.willChange(use);
this._stopOutEvent?.willChange(use);
return this;
}
// ------------------------------------------
//
// Static method
//
// ------------------------------------------
/**
* テンプレートを指定して、ボタンアニメーションを設定します。
* @static
* @param {string} targetQuery
* @param {...ButtonTween24[]} templates
* @return {Button24} {Button24}
* @memberof Button24
*/
static set(targetQuery:string, ...templates:ButtonTween24[]):Button24 {
const btn:Button24 = new Button24(targetQuery, Button24._DEFAULT_IN_EVENT, Button24._DEFAULT_OUT_EVENT, templates);
return btn;
}
/**
* ボタンのテキストに、色を変えるアニメーションを設定します。
* @static
* @param {string} targetQuery アニメーションの対象を指定するクエリ
* @param {string} colorCode 変更後の色のカラーコード
* @return {ButtonTween24} {ButtonTween24}
* @memberof Button24
*/
static _ColorChange(targetQuery:string, colorCode:string):ButtonTween24 {
const template:ButtonTween24 = new ButtonTween24();
const targets:HTMLElement[] = HTMLUtil.querySelectorAll(targetQuery);
template.setStopInTween (Tween24.tween(targetQuery, 0.3, Ease24._4_QuartOut).color(colorCode));
template.setStopOutTween(
Tween24.serial(
Tween24.prop(targetQuery).color(colorCode),
Tween24.tween(targetQuery, 0.6, Ease24._4_QuartOut).color(window.getComputedStyle(targets[0]).color)
)
);
return template;
}
/**
* ボタンのテキストに、1文字ずつロールアップするアニメーションを設定します。
* @static
* @param {string} targetQuery アニメーションの対象を指定するクエリ
* @param {number} [lagTotalTime=0.2] 遅延再生のトータル遅延時間
* @param {Function} [sort=Sort24._Normal] 再生順を指定するソート関数
* @return {ButtonTween24} {ButtonTween24}
* @memberof Button24
*/
static _TextRollUp(targetQuery:string, lagTotalTime:number = 0.2, sort:Function = Sort24._Normal):ButtonTween24 {
const template:ButtonTween24 = new ButtonTween24();
const targets:HTMLElement[] = HTMLUtil.querySelectorAll(targetQuery);
const createText:Function = function() {
for (const target of targets) {
const text:Text24 = Text24.getInstance(target) || new Text24(target, target.textContent?.trim() || "", true, true);
}
}
createText();
template.setInTween(
Tween24.serial(
Tween24.propText(targetQuery).y("100%"),
Tween24.lagTotalSort(lagTotalTime, sort,
Tween24.tweenTextVelocity(targetQuery, 40, Ease24._6_ExpoOut).y(0)
)
)
);
template.setResizeFunc(function():void {
Text24.removeByTarget(targetQuery);
createText();
});
template.needResize = true;
return template;
}
/**
* ボタンのテキストに、1文字ずつロールアップして戻るアニメーションを設定します。
* @static
* @param {string} targetQuery アニメーションの対象を指定するクエリ
* @param {number} [lagTotalTime=0.2] 遅延再生のトータル遅延時間
* @param {Function} [sort=Sort24._Normal] 再生順を指定するソート関数
* @return {ButtonTween24} {ButtonTween24}
* @memberof Button24
*/
static _TextRollUpDown(targetQuery:string, lagTotalTime:number = 0.2, sort:Function = Sort24._Normal):ButtonTween24 {
const template:ButtonTween24 = new ButtonTween24();
const targets:HTMLElement[] = HTMLUtil.querySelectorAll(targetQuery);
const createText:Function = () => {
for (const target of targets) {
const text:Text24 = Text24.getInstance(target) || new Text24(target, target.textContent?.trim() || "", true, true);
}
}
createText();
template.setStopInTween(
Tween24.serial(
Tween24.propText(targetQuery).y("100%"),
Tween24.lagTotalSort(lagTotalTime, sort,
Tween24.tweenTextVelocity(targetQuery, 40, Ease24._6_ExpoOut).y(0)
)
)
);
template.setStopOutTween(
Tween24.serial(
Tween24.propText(targetQuery).y(0),
Tween24.lagTotalSort(lagTotalTime, sort,
Tween24.tweenTextVelocity(targetQuery, 40, Ease24._6_ExpoOut).y("100%")
),
Tween24.propText(targetQuery).y(0)
)
);
template.setResizeFunc(() => {
Text24.removeByTarget(targetQuery);
createText();
});
template.needResize = true;
return template;
}
/**
* ボタンの矢印に、フェードしながらスライドインして戻るアニメーションを設定します。
* @static
* @param {string} targetQuery アニメーションの対象を指定するクエリ
* @param {(number|string)} [startX="-80%"] 矢印のアニメーションの開始X座標
* @return {ButtonTween24} {ButtonTween24}
* @memberof Button24
*/
static _FadeAndBackArrow(targetQuery:string, startX:number|string = "-80%"):ButtonTween24 {
const template:ButtonTween24 = new ButtonTween24();
template.setStopInTween(
Tween24.serial(
Tween24.prop(targetQuery).x(startX).opacity(0),
Tween24.tween(targetQuery, 0.4, Ease24._4_QuartOut).x(0).opacity(1)
)
);
template.setStopOutTween(
Tween24.parallel(
Tween24.tween(targetQuery, 0.12, Ease24._Linear).opacity(0),
Tween24.tween(targetQuery, 0.6, Ease24._4_QuartOut).x(startX)
)
);
Tween24.prop(targetQuery).x(startX).opacity(0).play();
template.needResize = true;
return template;
}
static _UnderlinedAndBack(targetQuery:string, borderWidth:number = 1, borderStyle:string = "solid", borderColor:string = "none"):ButtonTween24 {
const className = "tw-underlined";
const targets:HTMLElement[] = HTMLUtil.querySelectorAll(targetQuery);
let containerList = new Map<HTMLElement, HTMLSpanElement>();
for (const target of targets) {
const displayStyle = target.style.display;
const container = document.createElement("span");
container.style.display = "block";
container.style.position = "absolute";
// container.style.overflow = "hidden";
container.className = className;
// 幅を取得して親Spanに設定
target.style.display = "inline-block";
container.style.width = target.clientWidth + "px";
target.style.display = displayStyle;
// 子Span作成
const span = document.createElement("span");
const color = borderColor == "none" ? HTMLUtil.getComputedStyle(target).color: borderColor;
span.style.position = "absolute";
span.style.left = "0";
span.style.bottom = "0";
span.style.width = "100%";
span.style.borderBottom = `${borderStyle} ${borderWidth}px ${color}`;
// span.style.setProperty("clip-path", "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)");
// span.style.setProperty("mask-size", "50%");
span.style.setProperty("clip-path", "inset(0% 50% 0% 0%)");
// span.style.setProperty("mask-position", "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)");
container.appendChild(span);
target.appendChild(container);
containerList.set(target, container);
}
const template:ButtonTween24 = new ButtonTween24();
const tweenQuery = targetQuery + ` span.${className} span`;
// const tweenQuery = targetQuery + ` span.${className}`;
template.setStopInTween(
Tween24.serial(
// Tween24.prop(tweenQuery).width(0),
// Tween24.tween(tweenQuery, 0.4, Ease24._5_QuintOut).width("100%")
Tween24.prop(tweenQuery).style("mask-size", "0"),
Tween24.tween(tweenQuery, 0.4, Ease24._5_QuintOut).style("mask-size", "100%")
)
);
template.setStopOutTween(
Tween24.serial(
// Tween24.prop(tweenQuery).width("100%"),
// Tween24.tween(tweenQuery, 0.4, Ease24._4_QuartOut).width(0)
Tween24.prop(tweenQuery).style("mask-size", "100%"),
Tween24.tween(tweenQuery, 0.4, Ease24._5_QuintOut).style("mask-size", "0%")
)
);
template.setResizeFunc(() => {
for (const target of targets) {
// 幅を取得して親Spanに再設定
const container = containerList.get(target);
if (container) {
const displayStyle = target.style.display;
target.style.display = "inline-block";
container.style.width = target.clientWidth + "px";
target.style.display = displayStyle;
}
}
});
template.needResize = true;
return template;
}
}