Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
28f890e
feat: add 3d rotaion
Jun 13, 2018
aca9bfa
feat: add 3d rotaion
Jun 13, 2018
f802825
feat: add 3d rotation
hamdiwanis Jun 14, 2018
8156388
rename Point interface to Point3D
hamdiwanis Jun 18, 2018
4139398
Merge branch 'master' into master
Jun 19, 2018
78dedc8
Merge branch 'master' into master
Sep 19, 2018
6e03aba
Merge branch 'master' into master
Sep 20, 2018
c78c240
refactor: add typings and android-animation code refactoring
Sep 20, 2018
3ed3e43
test:3d-animations test page added
Sep 20, 2018
e103172
refactor: fix tslint
Sep 21, 2018
1579812
test: animations demos with code and with keyframes
Sep 27, 2018
b8feb2b
fix: ios - make rotate(z) animations on rotate work again
Sep 27, 2018
8072b19
fix: apply all rotations together on ios
hamdiwanis Sep 27, 2018
dbaf28c
fix: animate rotations with view.animate on ios
hamdiwanis Sep 27, 2018
9296ba1
reafctor: 3d transform for IOS
Sep 28, 2018
c1d61b4
fix: ios rotate 360 deg
hamdiwanis Sep 28, 2018
a154a47
Merge remote-tracking branch 'upstream/master'
hamdiwanis Oct 7, 2018
36d942f
Merge branch 'master' into master
hamdiwanis Oct 8, 2018
ef3df2a
chore: fix tslint
Oct 8, 2018
6e8723c
Merge branch 'master' into master
hamdiwanis Nov 9, 2018
ebb1aed
Merge branch 'master' into master
hamdiwanis Nov 27, 2018
a4b04da
Merge branch 'master' into master
dtopuzov Nov 30, 2018
72547d5
Merge branch 'master' into master
hamdiwanis Dec 6, 2018
ffdf351
Merge branch 'master' into master
hamdiwanis Dec 15, 2018
dc2b876
Merge branch 'master' into master
hamdiwanis Dec 27, 2018
e2ea817
Merge branch 'master' into master
hamdiwanis Jan 7, 2019
9071d76
Merge branch 'master' into master
hamdiwanis Feb 24, 2019
ec66dd9
Merge branch 'master' into master
hamdiwanis Mar 5, 2019
73769f4
Merge branch 'master' into master
hamdiwanis Mar 6, 2019
653495b
Merge branch 'master' into master
hamdiwanis Mar 22, 2019
99e3a78
Merge branch 'master' into master
hamdiwanis Mar 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions e2e/animation/app/3d-rotate/page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { EventData, Page } from "tns-core-modules/ui/page";
import { View } from "tns-core-modules/ui/core/view";
import { Point3D } from "tns-core-modules/ui/animation/animation";

let view: View;

export function pageLoaded(args: EventData) {
const page = <Page>args.object;
view = page.getViewById<View>("view");
}

export function onAnimateX(args: EventData) {
rotate({ x: 360, y: 0, z: 0 });
}

export function onAnimateY(args: EventData) {
rotate({ x: 0, y: 360, z: 0 });
}

export function onAnimateZ(args: EventData) {
rotate({ x: 0, y: 0, z: 360 });
}

export function onAnimateXYZ(args: EventData) {
rotate({ x: 360, y: 360, z: 360 });
}

function rotate(rotate: Point3D) {
view.animate({
rotate,
duration: 1000
}).then(reset);
}

function reset() {
view.rotate = 0;
view.rotateX = 0;
view.rotateY = 0;
}
24 changes: 24 additions & 0 deletions e2e/animation/app/3d-rotate/page.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
<ActionBar title="Rotate" />

<GridLayout rows="auto auto auto auto *" columns="* * *">
<Image src="~/res/icon_100x100.png" width="30" height="30" col="0" row="0" rotateX="60"/>
<Image src="~/res/icon_100x100.png" width="30" height="30" col="1" row="0" rotateY="60"/>
<Image src="~/res/icon_100x100.png" width="30" height="30" col="2" row="0" rotate="60"/>

<Button text="X" tap="onAnimateX" col="0" row="1"/>
<Button text="Y" tap="onAnimateY" col="1" row="1"/>
<Button text="Z" tap="onAnimateZ" col="2" row="1"/>

<Image src="~/res/icon_100x100.png" width="60" height="60" horizontalAlignment="center"
colSpan="3" row="2" rotate="60" rotateX="60" rotateY="60"/>

<Button text="XYZ" tap="onAnimateXYZ" row="3" colSpan="3"/>

<AbsoluteLayout width="300" height="300" clipToBounds="true" backgroundColor="LightGray" row="4" colSpan="3">
<Image id="view" src="~/res/icon_100x100.png"
width="100" height="100"
left="100" top="100"/>
</AbsoluteLayout>
</GridLayout>
</Page>
4 changes: 4 additions & 0 deletions e2e/animation/app/app.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import * as application from "tns-core-modules/application";

import { enable, setCategories, categories } from "tns-core-modules/trace"
setCategories(categories.Animation);
enable();

application.run({ moduleName: "app-root" });
75 changes: 75 additions & 0 deletions e2e/animation/app/css-animations/3d-rotate/page.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.rotate-x {
rotateX: 60;
}

.rotate-y {
rotateY: 60;
}

.rotate-z {
rotate: 60;
}

.original {
transform: none;
}

.animate-x {
animation-name: rotateX;
animation-duration: 2s;
animation-fill-mode: forwards;
}

.animate-y {
animation-name: rotateY;
animation-duration: 2s;
animation-fill-mode: forwards;
}

.animate-z {
animation-name: rotateZ;
animation-duration: 2s;
animation-fill-mode: forwards;
}

.animate-xyz-3d {
animation-name: rotateXYZ3D;
animation-duration: 2s;
animation-fill-mode: forwards;
}

.animate-xyz {
animation-name: rotateXYZ;
animation-duration: 2s;
animation-fill-mode: forwards;
}

@keyframes rotateX {
from { transform: none; }
50% { transform: rotateX(60) }
to { transform: none; }
}

@keyframes rotateY {
from { transform: none; }
50% { transform: rotateY(60) }
to { transform: none; }
}

@keyframes rotateZ {
from { transform: none; }
50% { transform: rotate(60) }
to { transform: none; }
}

@keyframes rotateXYZ3D {
from { transform: none; }
50% { transform: rotate3d(60, 60, 60) }
to { transform: none; }
}

@keyframes rotateXYZ {
from { transform: none; }
50% { transform: rotateX(60) rotateY(60) rotate(60) }
to { transform: none; }
}
35 changes: 35 additions & 0 deletions e2e/animation/app/css-animations/3d-rotate/page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { EventData, Page } from "tns-core-modules/ui/page";
import { View } from "tns-core-modules/ui/core/view";
import { Point3D } from "tns-core-modules/ui/animation/animation";

let view: View;

export function pageLoaded(args: EventData) {
const page = <Page>args.object;
view = page.getViewById<View>("view");
}

export function onAnimateX(args: EventData) {
view.className = "original";
view.className = "animate-x";
}

export function onAnimateY(args: EventData) {
view.className = "original";
view.className = "animate-y";
}

export function onAnimateZ(args: EventData) {
view.className = "original";
view.className = "animate-z";
}

export function onAnimateXYZ3D(args: EventData) {
view.className = "original";
view.className = "animate-xyz-3d";
}

export function onAnimateXYZ(args: EventData) {
view.className = "original";
view.className = "animate-xyz";
}
22 changes: 22 additions & 0 deletions e2e/animation/app/css-animations/3d-rotate/page.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
<ActionBar title="Rotate" />

<GridLayout rows="auto auto auto *" columns="* * *">
<Image src="~/res/icon_100x100.png" width="30" height="30" col="0" row="0" class="rotate-x"/>
<Image src="~/res/icon_100x100.png" width="30" height="30" col="1" row="0" class="rotate-y"/>
<Image src="~/res/icon_100x100.png" width="30" height="30" col="2" row="0" class="rotate-z"/>

<Button text="X" tap="onAnimateX" col="0" row="1"/>
<Button text="Y" tap="onAnimateY" col="1" row="1"/>
<Button text="Z" tap="onAnimateZ" col="2" row="1"/>

<Button text="XYZ" tap="onAnimateXYZ" row="2" col="0"/>
<Button text="XYZ-3D" tap="onAnimateXYZ3D" row="2" col="1"/>

<AbsoluteLayout width="300" height="300" clipToBounds="true" backgroundColor="LightGray" row="3" colSpan="3">
<Image id="view" src="~/res/icon_100x100.png"
width="100" height="100"
left="100" top="100" />
</AbsoluteLayout>
</GridLayout>
</Page>
1 change: 1 addition & 0 deletions e2e/animation/app/css-animations/page.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<Button text="settings" tap="onButtonTap"/>
<Button text="visual-states" tap="onButtonTap"/>
<Button text="initial-animation" tap="onButtonTap"/>
<Button text="3d-rotate" tap="onButtonTap"/>
</StackLayout>
</ScrollView>
</Page>
1 change: 1 addition & 0 deletions e2e/animation/app/home/home-page.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<Button text="infinite" tap="onButtonTap" />
<Button text="animation-curves" tap="onButtonTap" />
<Button text="css-animations" tap="onButtonTap" />
<Button text="3d-rotate" tap="onButtonTap" />
</StackLayout>
</ScrollView>

Expand Down
25 changes: 15 additions & 10 deletions tns-core-modules/matrix/matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@ import { TransformFunctionsInfo } from "../ui/animation/animation";

import { radiansToDegrees, degreesToRadians } from "../utils/number-utils";

export const getTransformMatrix = ({property, value}) =>
// TODO: Handle rotation over X and Y axis.
export const getTransformMatrix = ({ property, value }) =>
TRANSFORM_MATRIXES[property](value);

const TRANSFORM_MATRIXES = {
"scale": ({x, y}) => [
"scale": ({ x, y }) => [
x, 0, 0,
0, y, 0,
0, 0, 1,
],
"translate": ({x, y}) => [
"translate": ({ x, y }) => [
1, 0, x,
0, 1, y,
0, 0, 1,
],
"rotate": angleInDeg => {
const angleInRad = degreesToRadians(angleInDeg);
"rotate": ({ x, y, z}) => {
// TODO: Handle rotations over X and Y axis
const radZ = degreesToRadians(z);
const cosZ = Math.cos(radZ);
const sinZ = Math.sin(radZ);

return [
Math.cos(angleInRad), -Math.sin(angleInRad), 0,
Math.sin(angleInRad), Math.cos(angleInRad), 0,
cosZ, -sinZ, 0,
sinZ, cosZ, 0,
0, 0, 1,
]
},
Expand All @@ -43,6 +47,7 @@ export function multiplyAffine2d(m1: number[], m2: number[]): number[] {
]
}

// TODO: Decompose rotations over X and Y axis
export function decompose2DTransformMatrix(matrix: number[])
: TransformFunctionsInfo {

Expand All @@ -52,7 +57,7 @@ export function decompose2DTransformMatrix(matrix: number[])
const determinant = A * D - B * C;
const translate = { x: E || 0, y: F || 0 };

// rewrite with obj desctructuring using the identity matrix
// rewrite with obj destructuring using the identity matrix
let rotate = 0;
let scale = { x: 1, y: 1 };
if (A || B) {
Expand All @@ -62,12 +67,12 @@ export function decompose2DTransformMatrix(matrix: number[])
} else if (C || D) {
const R = Math.sqrt(C * C + D * D);
rotate = Math.PI / 2 - (D > 0 ? Math.acos(-C / R) : -Math.acos(C / R));
scale = { x: determinant / R, y: R };
scale = { x: determinant / R, y: R };
}

rotate = radiansToDegrees(rotate);

return { translate, rotate, scale };
return { translate, rotate: { x: 0, y: 0, z: rotate }, scale };
}

function verifyTransformMatrix(matrix: number[]) {
Expand Down
45 changes: 33 additions & 12 deletions tns-core-modules/ui/animation/animation-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
AnimationPromise as AnimationPromiseDefinition,
Animation as AnimationBaseDefinition,
AnimationDefinition,
Pair
Pair,
Point3D
} from ".";
import { View } from "../core/view";

Expand Down Expand Up @@ -87,7 +88,7 @@ export abstract class AnimationBase implements AnimationBaseDefinition {
protected _rejectAlreadyPlaying(): AnimationPromiseDefinition {
const reason = "Animation is already playing.";
traceWrite(reason, traceCategories.Animation, traceType.warn);

return <AnimationPromiseDefinition>new Promise<void>((resolve, reject) => {
reject(reason);
});
Expand Down Expand Up @@ -151,21 +152,33 @@ export abstract class AnimationBase implements AnimationBaseDefinition {
}

for (let item in animationDefinition) {
if (animationDefinition[item] === undefined) {
const value = animationDefinition[item];
if (value === undefined) {
continue;
}

if ((item === Properties.opacity ||
item === Properties.rotate ||
if (item === Properties.opacity ||
item === "duration" ||
item === "delay" ||
item === "iterations") && typeof animationDefinition[item] !== "number") {
throw new Error(`Property ${item} must be valid number. Value: ${animationDefinition[item]}`);
} else if ((item === Properties.scale || item === Properties.translate) &&
(typeof (<Pair>animationDefinition[item]).x !== "number" || typeof (<Pair>animationDefinition[item]).y !== "number")) {
throw new Error(`Property ${item} must be valid Pair. Value: ${animationDefinition[item]}`);
item === "iterations") {

if (typeof value !== "number") {
throw new Error(`Property ${item} must be valid number. Value: ${value}`);
}

} else if (item === Properties.scale || item === Properties.translate) {
const pair = <Pair>value;
if (typeof pair.x !== "number" || typeof pair.y !== "number") {
throw new Error(`Property ${item} must be valid Pair. Value: ${value}`);
}
} else if (item === Properties.backgroundColor && !Color.isValid(animationDefinition.backgroundColor)) {
throw new Error(`Property ${item} must be valid color. Value: ${animationDefinition[item]}`);
throw new Error(`Property ${item} must be valid color. Value: ${value}`);
} else if (item === Properties.rotate) {
const rotate: number | Point3D = value;
if ((typeof rotate !== "number") &&
!(typeof rotate.x === "number" && typeof rotate.y === "number" && typeof rotate.z === "number")) {
throw new Error(`Property ${rotate} must be valid number or Point3D. Value: ${value}`);
}
}
}

Expand Down Expand Up @@ -226,10 +239,18 @@ export abstract class AnimationBase implements AnimationBaseDefinition {

// rotate
if (animationDefinition.rotate !== undefined) {
// Make sure the value of the rotation property is always Point3D
let rotationValue: Point3D;
if (typeof animationDefinition.rotate === "number") {
rotationValue = { x: 0, y: 0, z: animationDefinition.rotate }
} else {
rotationValue = animationDefinition.rotate;
}

propertyAnimations.push({
target: animationDefinition.target,
property: Properties.rotate,
value: animationDefinition.rotate,
value: rotationValue,
duration: animationDefinition.duration,
delay: animationDefinition.delay,
iterations: animationDefinition.iterations,
Expand Down
Loading