mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Add new keyframes proof of concept
This commit is contained in:
64
core/src/utils/animation-old/animation-interface.ts
Normal file
64
core/src/utils/animation-old/animation-interface.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
export interface AnimationController {
|
||||
create(animationBuilder?: AnimationBuilder, baseEl?: any, opts?: any): Promise<Animation>;
|
||||
}
|
||||
|
||||
export interface Animation {
|
||||
new (): any;
|
||||
parent: Animation | undefined;
|
||||
hasChildren: boolean;
|
||||
addElement(el: Node | Node[] | NodeList): Animation;
|
||||
add(childAnimation: Animation): Animation;
|
||||
duration(milliseconds: number): Animation;
|
||||
easing(name: string): Animation;
|
||||
easingReverse(name: string): Animation;
|
||||
getDuration(opts?: PlayOptions): number;
|
||||
getEasing(): string;
|
||||
from(prop: string, val: any): Animation;
|
||||
to(prop: string, val: any, clearProperyAfterTransition?: boolean): Animation;
|
||||
fromTo(prop: string, fromVal: any, toVal: any, clearProperyAfterTransition?: boolean): Animation;
|
||||
beforeAddClass(className: string): Animation;
|
||||
beforeRemoveClass(className: string): Animation;
|
||||
beforeStyles(styles: { [property: string]: any; }): Animation;
|
||||
beforeClearStyles(propertyNames: string[]): Animation;
|
||||
beforeAddRead(domReadFn: () => void): Animation;
|
||||
beforeAddWrite(domWriteFn: () => void): Animation;
|
||||
afterAddClass(className: string): Animation;
|
||||
afterRemoveClass(className: string): Animation;
|
||||
afterStyles(styles: { [property: string]: any; }): Animation;
|
||||
afterClearStyles(propertyNames: string[]): Animation;
|
||||
play(opts?: PlayOptions): void;
|
||||
playSync(): void;
|
||||
playAsync(opts?: PlayOptions): Promise<Animation>;
|
||||
reverse(shouldReverse?: boolean): Animation;
|
||||
stop(stepValue?: number): void;
|
||||
progressStart(): void;
|
||||
progressStep(stepValue: number): void;
|
||||
progressEnd(shouldComplete: boolean, currentStepValue: number, dur: number): void;
|
||||
onFinish(callback: (animation?: Animation) => void, opts?: {oneTimeCallback?: boolean, clearExistingCallbacks?: boolean}): Animation;
|
||||
destroy(): void;
|
||||
isRoot(): boolean;
|
||||
hasCompleted: boolean;
|
||||
}
|
||||
|
||||
export type AnimationBuilder = (Animation: Animation, baseEl: any, opts?: any) => Promise<Animation>;
|
||||
|
||||
export interface PlayOptions {
|
||||
duration?: number;
|
||||
promise?: boolean;
|
||||
}
|
||||
|
||||
export interface EffectProperty {
|
||||
effectName: string;
|
||||
trans: boolean;
|
||||
wc?: string;
|
||||
to?: EffectState;
|
||||
from?: EffectState;
|
||||
[state: string]: any;
|
||||
}
|
||||
|
||||
export interface EffectState {
|
||||
val: any;
|
||||
num: number;
|
||||
effectUnit: string;
|
||||
}
|
||||
1253
core/src/utils/animation-old/animator.ts
Normal file
1253
core/src/utils/animation-old/animator.ts
Normal file
File diff suppressed because it is too large
Load Diff
10
core/src/utils/animation-old/index.ts
Normal file
10
core/src/utils/animation-old/index.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Animation, AnimationBuilder } from '../../interface';
|
||||
|
||||
import { Animator } from './animator';
|
||||
|
||||
export function create(animationBuilder?: AnimationBuilder, baseEl?: any, opts?: any): Promise<Animation> {
|
||||
if (animationBuilder) {
|
||||
return animationBuilder(Animator as any, baseEl, opts);
|
||||
}
|
||||
return Promise.resolve(new Animator() as any);
|
||||
}
|
||||
30
core/src/utils/animation-old/transition-end.ts
Normal file
30
core/src/utils/animation-old/transition-end.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
export function transitionEnd(el: HTMLElement | null, callback: (ev?: TransitionEvent) => void) {
|
||||
let unRegTrans: (() => void) | undefined;
|
||||
const opts: any = { passive: true };
|
||||
|
||||
function unregister() {
|
||||
if (unRegTrans) {
|
||||
unRegTrans();
|
||||
}
|
||||
}
|
||||
|
||||
function onTransitionEnd(ev: Event) {
|
||||
if (el === ev.target) {
|
||||
unregister();
|
||||
callback(ev as TransitionEvent);
|
||||
}
|
||||
}
|
||||
|
||||
if (el) {
|
||||
el.addEventListener('webkitTransitionEnd', onTransitionEnd, opts);
|
||||
el.addEventListener('transitionend', onTransitionEnd, opts);
|
||||
|
||||
unRegTrans = () => {
|
||||
el.removeEventListener('webkitTransitionEnd', onTransitionEnd, opts);
|
||||
el.removeEventListener('transitionend', onTransitionEnd, opts);
|
||||
};
|
||||
}
|
||||
|
||||
return unregister;
|
||||
}
|
||||
260
core/src/utils/animation/animation.ts
Normal file
260
core/src/utils/animation/animation.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
// TODO: Add validation
|
||||
// TODO: More tests
|
||||
|
||||
const addElement = (animationElements: any[], el: Node | Node[] | NodeList | undefined | null) => {
|
||||
if (el != null) {
|
||||
const nodeList = el as NodeList;
|
||||
if (nodeList.length >= 0) {
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
animationElements.push((el as any)[i]);
|
||||
}
|
||||
} else {
|
||||
animationElements.push(el);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addAnimation = (parentAnimation: Animation, childAnimations: Animation[], animationToAdd: Animation | Animation[] | undefined | null) => {
|
||||
if (animationToAdd != null) {
|
||||
const animationsToAdd = animationToAdd as Animation[];
|
||||
if (animationsToAdd.length >= 0) {
|
||||
for (const animation of animationsToAdd) {
|
||||
animation.parentAnimation = parentAnimation;
|
||||
childAnimations.push(animation);
|
||||
}
|
||||
} else {
|
||||
(animationToAdd as Animation).parentAnimation = parentAnimation;
|
||||
childAnimations.push(animationToAdd as Animation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const addTarget = (animationElements: any[], target: string) => {
|
||||
const els = document.querySelectorAll(target);
|
||||
addElement(animationElements, els);
|
||||
};
|
||||
|
||||
const generateKeyframeString = (name: string | undefined, keyframes: any[] = []): string => {
|
||||
if (name === undefined) { console.warn('A name is required to generate keyframes'); }
|
||||
|
||||
const keyframeString = [`@keyframes ${name} {`];
|
||||
|
||||
keyframes.forEach(keyframe => {
|
||||
const offset = keyframe.offset;
|
||||
delete keyframe.offset;
|
||||
|
||||
const frameString = [];
|
||||
for (const property in keyframe) {
|
||||
if (keyframe.hasOwnProperty(property)) {
|
||||
frameString.push(`${property}: ${keyframe[property]};`);
|
||||
}
|
||||
}
|
||||
|
||||
keyframeString.push(`${offset * 100}% { ${frameString.join(' ')} }`);
|
||||
});
|
||||
|
||||
return keyframeString.join(' ');
|
||||
};
|
||||
|
||||
export class Animation {
|
||||
private elements: Element[] = [];
|
||||
private childAnimations: Animation[] = [];
|
||||
|
||||
private _delay: number | undefined;
|
||||
private _duration: number | undefined;
|
||||
private _easing: string | undefined;
|
||||
private _iterations: number | undefined;
|
||||
|
||||
private _keyframes: any[] = [];
|
||||
private _keyframeString = '';
|
||||
|
||||
private initialized = false;
|
||||
|
||||
private stylesheet?: HTMLElement;
|
||||
|
||||
parentAnimation: Animation | undefined;
|
||||
|
||||
constructor(public _name: string | undefined) {}
|
||||
|
||||
getEasing(): string | undefined {
|
||||
if (this._easing !== undefined) { return this._easing; }
|
||||
if (this.parentAnimation && this.parentAnimation.getEasing() !== undefined) { return this.parentAnimation.getEasing(); }
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getDuration(): number | undefined {
|
||||
if (this._duration !== undefined) { return this._duration; }
|
||||
if (this.parentAnimation && this.parentAnimation.getDuration() !== undefined) { return this.parentAnimation.getDuration(); }
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getIterations(): number | undefined {
|
||||
if (this._iterations !== undefined) { return this._iterations; }
|
||||
if (this.parentAnimation && this.parentAnimation.getIterations() !== undefined) { return this.parentAnimation.getIterations(); }
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getDelay(): number | undefined {
|
||||
if (this._delay !== undefined) { return this._delay; }
|
||||
if (this.parentAnimation && this.parentAnimation.getDelay() !== undefined) { return this.parentAnimation.getDelay(); }
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getKeyframes(): any[] {
|
||||
return this._keyframes;
|
||||
}
|
||||
|
||||
name(name: string): Animation {
|
||||
this._name = name;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
delay(delay: number): Animation {
|
||||
this._delay = delay;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
easing(easing: string): Animation {
|
||||
this._easing = easing;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
duration(duration: number): Animation {
|
||||
this._duration = duration;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
iterations(iterations: number): Animation {
|
||||
this._iterations = iterations;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addElement(el: Node | Node[] | NodeList | undefined | null): Animation {
|
||||
addElement(this.elements, el);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addTarget(target: string): Animation {
|
||||
addTarget(this.elements, target);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
addAnimation(childAnimation: Animation | undefined | null): Animation {
|
||||
addAnimation(this, this.childAnimations, childAnimation);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
keyframes(keyframes: any[]): Animation {
|
||||
this._keyframes = keyframes;
|
||||
this._keyframeString = generateKeyframeString(this._name, keyframes);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private initializeAnimation(): void {
|
||||
if (!this.stylesheet) {
|
||||
const stylesheet = document.createElement('style');
|
||||
stylesheet.appendChild(document.createTextNode(this._keyframeString));
|
||||
|
||||
document.querySelector('head')!.appendChild(stylesheet);
|
||||
|
||||
this.stylesheet = stylesheet;
|
||||
}
|
||||
|
||||
const animationName = this._name;
|
||||
const animationDuration = this.getDuration();
|
||||
const animationEasing = this.getEasing();
|
||||
const animationIterationCount = this.getIterations();
|
||||
const animationDelay = this.getDelay();
|
||||
|
||||
this.elements.forEach(element => {
|
||||
if (animationName !== undefined) {
|
||||
(element as HTMLElement).style.animationName = animationName;
|
||||
}
|
||||
|
||||
if (animationDuration !== undefined) {
|
||||
(element as HTMLElement).style.animationDuration = `${animationDuration}ms`;
|
||||
}
|
||||
|
||||
if (animationEasing !== undefined) {
|
||||
(element as HTMLElement).style.animationTimingFunction = animationEasing;
|
||||
}
|
||||
|
||||
if (animationIterationCount !== undefined) {
|
||||
(element as HTMLElement).style.animationIterationCount = (animationIterationCount === Infinity) ? 'infinite' : animationIterationCount.toString();
|
||||
}
|
||||
|
||||
if (animationDelay !== undefined) {
|
||||
(element as HTMLElement).style.animationDelay = `${animationDelay}ms`;
|
||||
}
|
||||
});
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
playStep(step: number): Animation {
|
||||
if (!this.initialized) {
|
||||
this.initializeAnimation();
|
||||
}
|
||||
|
||||
this.childAnimations.forEach(animation => {
|
||||
animation.playStep(step);
|
||||
});
|
||||
|
||||
this.pause();
|
||||
|
||||
if (this.getDuration() !== undefined) {
|
||||
const animationDuration = `-${this.getDuration()! * step}ms`;
|
||||
|
||||
this.elements.forEach(element => {
|
||||
(element as HTMLElement).style.animationDelay = animationDuration;
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
pause(): Animation {
|
||||
if (!this.initialized) {
|
||||
this.initializeAnimation();
|
||||
}
|
||||
|
||||
this.childAnimations.forEach(animation => {
|
||||
animation.pause();
|
||||
});
|
||||
|
||||
this.elements.forEach(element => {
|
||||
(element as HTMLElement).style.animationPlayState = 'paused';
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
play(): Animation {
|
||||
if (!this.initialized) {
|
||||
this.initializeAnimation();
|
||||
}
|
||||
|
||||
this.childAnimations.forEach(animation => {
|
||||
animation.play();
|
||||
});
|
||||
|
||||
this.elements.forEach(element => {
|
||||
(element as HTMLElement).style.animationPlayState = 'running';
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
221
core/src/utils/animation/test/animation.spec.ts
Normal file
221
core/src/utils/animation/test/animation.spec.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
import { Animation } from '../animation';
|
||||
|
||||
describe('Animation Class', () => {
|
||||
|
||||
describe('addElement()', () => {
|
||||
let animation;
|
||||
beforeEach(() => {
|
||||
animation = new Animation();
|
||||
});
|
||||
|
||||
it('should add 1 element', () => {
|
||||
const el = document.createElement('p');
|
||||
animation.addElement(el);
|
||||
|
||||
expect(animation.elements.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add multiple elements', () => {
|
||||
const els = [
|
||||
document.createElement('p'),
|
||||
document.createElement('p'),
|
||||
document.createElement('p')
|
||||
];
|
||||
|
||||
animation.addElement(els);
|
||||
|
||||
expect(animation.elements.length).toEqual(els.length);
|
||||
});
|
||||
|
||||
it('should not error when trying to add null or undefined', () => {
|
||||
const el = document.createElement('p');
|
||||
animation.addElement(el);
|
||||
|
||||
animation.addElement(null);
|
||||
animation.addElement(undefined);
|
||||
|
||||
expect(animation.elements.length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addTarget()', () => {
|
||||
let animation;
|
||||
beforeEach(() => {
|
||||
animation = new Animation();
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('should add a target', () => {
|
||||
document.body.appendChild(document.createElement('p'));
|
||||
|
||||
animation.addTarget('p');
|
||||
expect(animation.elements.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('should add multiple targets of the same type', () => {
|
||||
document.body.appendChild(document.createElement('p'));
|
||||
document.body.appendChild(document.createElement('p'));
|
||||
|
||||
animation.addTarget('p');
|
||||
expect(animation.elements.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('should add multiple targets of different types', () => {
|
||||
document.body.appendChild(document.createElement('p'));
|
||||
document.body.appendChild(document.createElement('p'));
|
||||
document.body.appendChild(document.createElement('span'));
|
||||
|
||||
animation.addTarget('p, span');
|
||||
expect(animation.elements.length).toEqual(3);
|
||||
});
|
||||
|
||||
it('should not error when trying to add null or undefined', () => {
|
||||
animation.addTarget('p');
|
||||
expect(animation.elements.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addAnimation()', () => {
|
||||
let animation;
|
||||
beforeEach(() => {
|
||||
animation = new Animation();
|
||||
});
|
||||
|
||||
it('should add 1 animation', () => {
|
||||
const newAnimation = new Animation();
|
||||
animation.addAnimation(newAnimation);
|
||||
|
||||
expect(animation.childAnimations.length).toEqual(1);
|
||||
expect(animation.childAnimations[0].parentAnimation).toEqual(animation);
|
||||
});
|
||||
|
||||
it('should add multiple animations', () => {
|
||||
animation.addAnimation([new Animation(), new Animation(), new Animation()]);
|
||||
|
||||
expect(animation.childAnimations.length).toEqual(3);
|
||||
expect(animation.childAnimations[0].parentAnimation).toEqual(animation);
|
||||
expect(animation.childAnimations[1].parentAnimation).toEqual(animation);
|
||||
expect(animation.childAnimations[2].parentAnimation).toEqual(animation);
|
||||
});
|
||||
|
||||
it('should not error when trying to add null or undefined', () => {
|
||||
animation.addAnimation(null);
|
||||
animation.addAnimation(undefined);
|
||||
|
||||
expect(animation.childAnimations.length).toEqual(0);
|
||||
})
|
||||
});
|
||||
|
||||
describe('keyframes()', () => {
|
||||
let animation;
|
||||
beforeEach(() => {
|
||||
animation = new Animation('my-animation');
|
||||
});
|
||||
|
||||
it('should generate a keyframe', () => {
|
||||
animation.keyframes([
|
||||
{ transform: 'scale(1)', opacity: 1, offset: 0 },
|
||||
{ transform: 'scale(0.5)', opacity: 0.5, offset: 0.5 },
|
||||
{ transform: 'scale(0)', opacity: 0, offset: 1 }
|
||||
]);
|
||||
|
||||
expect(animation._keyframes.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Animation Config Methods', () => {
|
||||
let animation;
|
||||
beforeEach(() => {
|
||||
animation = new Animation();
|
||||
});
|
||||
|
||||
it('should get undefined when easing not set', () => {
|
||||
expect(animation.getEasing()).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should get parent easing when child easing is not set', () => {
|
||||
const childAnimation = new Animation();
|
||||
animation.addAnimation(childAnimation);
|
||||
childAnimation.easing('linear');
|
||||
|
||||
expect(childAnimation.getEasing()).toEqual('linear');
|
||||
});
|
||||
|
||||
it('should get prefer child easing over parent easing', () => {
|
||||
const childAnimation = new Animation();
|
||||
childAnimation.easing('linear');
|
||||
|
||||
animation.addAnimation(childAnimation);
|
||||
animation.easing('ease-in-out');
|
||||
|
||||
expect(childAnimation.getEasing()).toEqual('linear');
|
||||
});
|
||||
|
||||
it('should get undefined when duration not set', () => {
|
||||
expect(animation.getDuration()).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should get parent duration when child duration is not set', () => {
|
||||
const childAnimation = new Animation();
|
||||
animation.addAnimation(childAnimation);
|
||||
childAnimation.duration(500);
|
||||
|
||||
expect(childAnimation.getDuration()).toEqual(500);
|
||||
});
|
||||
|
||||
it('should get prefer child duration over parent duration', () => {
|
||||
const childAnimation = new Animation();
|
||||
childAnimation.duration(500);
|
||||
|
||||
animation.addAnimation(childAnimation);
|
||||
animation.duration(1000);
|
||||
|
||||
expect(childAnimation.getDuration()).toEqual(500);
|
||||
});
|
||||
|
||||
it('should get undefined when delay not set', () => {
|
||||
expect(animation.getDelay()).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should get parent delay when child delay is not set', () => {
|
||||
const childAnimation = new Animation();
|
||||
animation.addAnimation(childAnimation);
|
||||
childAnimation.delay(500);
|
||||
|
||||
expect(childAnimation.getDelay()).toEqual(500);
|
||||
});
|
||||
|
||||
it('should get prefer child delay over parent delay', () => {
|
||||
const childAnimation = new Animation();
|
||||
childAnimation.delay(500);
|
||||
|
||||
animation.addAnimation(childAnimation);
|
||||
animation.delay(1000);
|
||||
|
||||
expect(childAnimation.getDelay()).toEqual(500);
|
||||
});
|
||||
|
||||
it('should get undefined when iterations not set', () => {
|
||||
expect(animation.getIterations()).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should get parent iterations when child iterations is not set', () => {
|
||||
const childAnimation = new Animation();
|
||||
animation.addAnimation(childAnimation);
|
||||
childAnimation.iterations(2);
|
||||
|
||||
expect(childAnimation.getIterations()).toEqual(2);
|
||||
});
|
||||
|
||||
it('should get prefer child iterations over parent iterations', () => {
|
||||
const childAnimation = new Animation();
|
||||
childAnimation.iterations(2);
|
||||
|
||||
animation.addAnimation(childAnimation);
|
||||
animation.iterations(1);
|
||||
|
||||
expect(childAnimation.getIterations()).toEqual(2);
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
173
core/src/utils/animation/test/basic/index.html
Normal file
173
core/src/utils/animation/test/basic/index.html
Normal file
@@ -0,0 +1,173 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Animation - Basic</title>
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<script type="module">
|
||||
import { Animation as IonicAnimation } from '../../../../dist/collection/utils/animation/animation.js';
|
||||
import { createGesture } from '../../../../dist/ionic/index-a098653b.js';
|
||||
|
||||
window.IonicAnimation = IonicAnimation;
|
||||
|
||||
function clamp(val) {
|
||||
if (val > 1) {
|
||||
return 1;
|
||||
} else if (val < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
const squareA = document.querySelectorAll('.square-a');
|
||||
const squareB = document.querySelectorAll('.square-b');
|
||||
const squareC = document.querySelectorAll('.square-c');
|
||||
|
||||
const track = document.querySelector('.track');
|
||||
const cursor = document.querySelector('.track .cursor');
|
||||
|
||||
const rootAnimation = new IonicAnimation();
|
||||
const animationA = new IonicAnimation('animation-a');
|
||||
const animationB = new IonicAnimation('animation-b');
|
||||
const animationC = new IonicAnimation('animation-c');
|
||||
|
||||
const gesture = createGesture({
|
||||
el: track,
|
||||
gestureName: 'drag',
|
||||
gesturePriority: 100,
|
||||
treshold: 5,
|
||||
onStart: () => {},
|
||||
onMove: (ev) => {
|
||||
const start = ev.startX;
|
||||
const width = track.clientWidth;
|
||||
|
||||
const lower = start;
|
||||
const upper = width - start;
|
||||
|
||||
const current = clamp((ev.currentX - lower) / upper);
|
||||
|
||||
rootAnimation.playStep(current);
|
||||
cursor.style.transform = `translateX(${ev.currentX - 10}px)`;
|
||||
},
|
||||
onEnd: (ev) => {
|
||||
rootAnimation.playStep(0);
|
||||
cursor.style.transform = `translateX(${0}px)`;
|
||||
}
|
||||
});
|
||||
|
||||
gesture.setDisabled(false);
|
||||
|
||||
animationA
|
||||
.addElement(squareA)
|
||||
.duration(2000)
|
||||
.delay(5000)
|
||||
.easing('linear')
|
||||
.iterations(Infinity)
|
||||
.keyframes([
|
||||
{ transform: 'scale(1) rotate(0deg)', opacity: 1, offset: 0 },
|
||||
{ transform: 'scale(1.5) rotate(45deg)', opacity: 0.5, offset: 0.5 },
|
||||
{ transform: 'scale(1) rotate(0deg)', opacity: 1, offset: 1 }
|
||||
]);
|
||||
|
||||
animationB
|
||||
.addElement(squareB)
|
||||
.duration(500)
|
||||
.delay(2000)
|
||||
.easing('ease-in-out')
|
||||
.iterations(Infinity)
|
||||
.keyframes([
|
||||
{ transform: 'scale(1) rotate(0deg)', opacity: 1, offset: 0 },
|
||||
{ transform: 'scale(0.5) rotate(-45deg)', opacity: 0.5, offset: 0.5 },
|
||||
{ transform: 'scale(1) rotate(0deg)', opacity: 1, offset: 1 }
|
||||
]);
|
||||
|
||||
animationC
|
||||
.addElement(squareC)
|
||||
.duration(2000)
|
||||
.delay(500)
|
||||
.easing('ease-in-out')
|
||||
.iterations(Infinity)
|
||||
.keyframes([
|
||||
{ transform: 'scale(1) skew(0deg)', opacity: 1, offset: 0 },
|
||||
{ transform: 'scale(1.5) skew(15deg)', opacity: 0.5, offset: 0.5 },
|
||||
{ transform: 'scale(1) skew(0deg)', opacity: 1, offset: 1 }
|
||||
]);
|
||||
|
||||
rootAnimation.addAnimation([animationA, animationB, animationC]);
|
||||
rootAnimation.play();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.square {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: rgba(0, 0, 255, 0.5);
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
margin-left: 25px;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.track {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background: rgba(0, 255, 0, 0.5);
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
user-select: none;
|
||||
cursor: ew-resize;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.track .cursor {
|
||||
pointer-events: none;
|
||||
width: 10px;
|
||||
height: 100px;
|
||||
background: rgba(255, 0, 0, 0.5);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Animations</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<div class="ion-padding">
|
||||
<div class="track">
|
||||
Drag along the track to animate the elements
|
||||
<div class="cursor"></div>
|
||||
</div>
|
||||
<div class="square square-a">
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div class="square square-b">
|
||||
Hello
|
||||
</div>
|
||||
|
||||
<div class="square square-c">
|
||||
Hello
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
112
core/src/utils/animation/test/grid/index.html
Normal file
112
core/src/utils/animation/test/grid/index.html
Normal file
@@ -0,0 +1,112 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Animation - Grid</title>
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../scripts/testing/scripts.js"></script>
|
||||
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
<script type="module">
|
||||
import { Animation as IonicAnimation } from '../../../../dist/collection/utils/animation/animation.js';
|
||||
import { createGesture } from '../../../../dist/ionic/index-a098653b.js';
|
||||
|
||||
window.IonicAnimation = IonicAnimation;
|
||||
|
||||
const grid = document.querySelector('.grid-container');
|
||||
|
||||
let dotsString = '';
|
||||
for (let i = 0; i < 360; i++) {
|
||||
dotsString += '<div class="dot"></div>';
|
||||
}
|
||||
grid.innerHTML = dotsString;
|
||||
|
||||
const dots = document.querySelectorAll('.dot');
|
||||
const rootAnimation = new IonicAnimation();
|
||||
|
||||
rootAnimation
|
||||
.duration(500)
|
||||
.easing('ease-in-out')
|
||||
.iterations(Infinity);
|
||||
|
||||
dots.forEach((dot, i) => {
|
||||
const animation = new IonicAnimation(`dot-${i}`);
|
||||
animation
|
||||
.addElement(dot)
|
||||
.delay(i * 10)
|
||||
.keyframes([
|
||||
{ transform: 'scale(1)', offset: 0 },
|
||||
{ transform: 'scale(2)', offset: 0.5 },
|
||||
{ transform: 'scale(1)', offset: 1 }
|
||||
]);
|
||||
|
||||
rootAnimation.addAnimation(animation);
|
||||
});
|
||||
|
||||
document.querySelector('.pause').addEventListener('click', () => {
|
||||
rootAnimation.pause();
|
||||
});
|
||||
|
||||
document.querySelector('.play').addEventListener('click', () => {
|
||||
rootAnimation.play();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.grid-container {
|
||||
width: 330px;
|
||||
height: 470px;
|
||||
background: rgba(0, 0, 255, 0.5);
|
||||
}
|
||||
|
||||
.dot {
|
||||
--width: 8px;
|
||||
width: var(--width);
|
||||
height: var(--width);
|
||||
border-radius: var(--width);
|
||||
background: rgba(0, 255, 0, 1);
|
||||
float: left;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.dot:nth-of-type(2n) {
|
||||
background: rgba(255, 0, 0, 1);
|
||||
}
|
||||
|
||||
.dot:nth-of-type(3n) {
|
||||
background: rgba(0, 0, 255, 1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Animations</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button class="pause">Pause</ion-button>
|
||||
<ion-button class="play">Play</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<div class="ion-padding">
|
||||
<div class="grid-container">
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
<div class="dot"></div>
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user