You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Transform animation parser fails with eg. transform: 'scale(2,2)' #738
I posted about this accidentally to nativescript main issue board; since I have zeroed in on the root cause of why certain animations cause the element to disappear.
Here's the original issue I posted with isolated component example for verifying the issue and all other details: NativeScript/NativeScript#3937
In the comments you can see what I found out to be the cause.
Ok the STYLE_TRANSFORMATION_MAP explains why something like transform: "translateX(100px) translateY(100px)" only translates the y, as only using "translateX" or "translateY" defaults the other to 0.
So here as well I would need "translate(100px, 100px)", but that same parsing issue butchers the expression at the comma. So fixing that pretty much makes it all work, then one just needs to use the double value syntax.
There's something else seriously wrong. I prototyped a fix which handles each subsequent transform value in a way that it combines already applied values with the new one, which essentially fixes the original issues. So I can write like: transform: "scaleX(2) scaleY(3) translateX(100px) translateY(200px)" and it works.
BUT any initially applied transform causes the element to disappear. I can't attach the debugger in time, so I don't know what happens. If I put there another element I can use to trigger a state change, it will reveal the element, it will animate, and I can make it go back and forth between the states. The code example can be found in this post.
Here's the code that makes my syntax work
I hacked the "nativescript-angular/nativescript-angular/animations/utils.ts", typed directly in the built code - it's not typescript, but JavaScript.
Simple to spot the changes though - what I did was that if the "parseTransformation" reduce argument "transformation.property" already is a "base" version of the property being applied (eg. "transition" and "transitionX"), it will detect it and get the "mirror" value already applied, if applied. So when it applies "transitionX", it passes in "y" value if it was found set already.
var enums_1 = require("ui/enums");
var style_property_1 = require("ui/styling/style-property");
var TRANSFORM_MATCHER = new RegExp(/(.+)\((.+)\)/);
var TRANSFORM_SPLITTER = new RegExp(/[\s,]+/);
var TRANSFORM_PROPERTY_BASE_MATCHER = new RegExp(/(.+)([YX])/);
var TRANSFORM_PARTIAL_APPLICATION_MIRROR = Object.freeze({
x: 'y',
y: 'x'
});
var STYLE_TRANSFORMATION_MAP = Object.freeze({
"scale": function (value) { return ({ property: "scale", value: value }); },
"scale3d": function (value) { return ({ property: "scale", value: value }); },
"scaleX": function (value, preset) { return ({ property: "scale", value: { x: value, y: typeof(preset) != "undefined" ? preset : 1 } }); },
"scaleY": function (value, preset) { return ({ property: "scale", value: { x: typeof(preset) != "undefined" ? preset : 1, y: value } }); },
"translate": function (value) { return ({ property: "translate", value: value }); },
"translate3d": function (value) { return ({ property: "translate", value: value }); },
"translateX": function (value, preset) { return ({ property: "translate", value: { x: value, y: typeof(preset) != "undefined" ? preset : 0 } }); },
"translateY": function (value, preset) { return ({ property: "translate", value: { x: typeof(preset) != "undefined" ? preset : 0, y: value } }); },
"rotate": function (value) { return ({ property: "rotate", value: value }); },
"none": function (_value) { return [
{ property: "scale", value: { x: 1, y: 1 } },
{ property: "translate", value: { x: 0, y: 0 } },
{ property: "rotate", value: 0 },
]; },
});
var STYLE_CURVE_MAP = Object.freeze({
"ease": enums_1.AnimationCurve.ease,
"linear": enums_1.AnimationCurve.linear,
"ease-in": enums_1.AnimationCurve.easeIn,
"ease-out": enums_1.AnimationCurve.easeOut,
"ease-in-out": enums_1.AnimationCurve.easeInOut,
"spring": enums_1.AnimationCurve.spring,
});
function getAnimationCurve(value) {
if (!value) {
return enums_1.AnimationCurve.ease;
}
var curve = STYLE_CURVE_MAP[value];
if (curve) {
return curve;
}
var _a = TRANSFORM_MATCHER.exec(value) || [], _b = _a[1], property = _b === void 0 ? "" : _b, _c = _a[2], pointsString = _c === void 0 ? "" : _c;
var coords = pointsString.split(TRANSFORM_SPLITTER).map(stringToBezieCoords);
if (property !== "cubic-bezier" || coords.length !== 4) {
throw new Error("Invalid value for animation: " + value);
}
else {
return (_d = enums_1.AnimationCurve).cubicBezier.apply(_d, coords);
}
var _d;
}
exports.getAnimationCurve = getAnimationCurve;
function parseAnimationKeyframe(styles) {
var keyframeInfo = {};
keyframeInfo.duration = styles["offset"];
keyframeInfo.declarations = Object.keys(styles).reduce(function (declarations, prop) {
var value = styles[prop];
var kebapCaseProp = prop.split(/(?=[A-Z])/).join("-").toLowerCase();
var property = style_property_1.getPropertyByCssName(kebapCaseProp);
if (property) {
if (typeof value === "string" && property.valueConverter) {
value = property.valueConverter(value);
}
declarations.push({ property: property.name, value: value });
}
else if (typeof value === "string" && prop === "transform") {
declarations.push.apply(declarations, parseTransformation(value));
}
return declarations;
}, new Array());
return keyframeInfo;
}
exports.parseAnimationKeyframe = parseAnimationKeyframe;
function stringToBezieCoords(value) {
var result = parseFloat(value);
if (result < 0) {
return 0;
}
else if (result > 1) {
return 1;
}
return result;
}
function parseTransformation(styleString) {
return parseStyle(styleString)
.reduce(function (transformations, style) {
var partiallyAppliedTransformation = getPartiallyAppliedTransformationValue(transformations, style.property);
var transform = STYLE_TRANSFORMATION_MAP[style.property](style.value,partiallyAppliedTransformation);
if (Array.isArray(transform)) {
transformations.push.apply(transformations, transform);
}
else if (typeof transform !== "undefined") {
transformations.push(transform);
}
return transformations;
}, new Array());
}
function getPartiallyAppliedTransformationValue(transformations, property) {
var transformPropertyInfo = parseTransformPropertyInfo(property);
if(!transformPropertyInfo) return null;
var appliedTransformation = transformations.find(function(transformation) {
return transformation.property == transformPropertyInfo.basePropertyName;
});
return appliedTransformation ? appliedTransformation.value[transformPropertyInfo.subPropertyName] : null;
}
function parseTransformPropertyInfo(property) {
var match = property.match(TRANSFORM_PROPERTY_BASE_MATCHER);
return match ? {
basePropertyName: match[1],
subPropertyName: TRANSFORM_PARTIAL_APPLICATION_MIRROR[match[2].toLowerCase()]
} : null;
}
function parseStyle(text) {
return text.split(TRANSFORM_SPLITTER).map(stringToTransformation).filter(function (t) { return !!t; });
}
function stringToTransformation(text) {
var _a = TRANSFORM_MATCHER.exec(text) || [], _b = _a[1], property = _b === void 0 ? "" : _b, _c = _a[2], stringValue = _c === void 0 ? "" : _c;
if (!property) {
return;
}
var _d = stringValue.split(",").map(parseFloat), x = _d[0], y = _d[1];
if (x && y) {
return { property: property, value: { x: x, y: y } };
}
else {
var value = x;
if (stringValue.slice(-3) === "rad") {
value *= 180.0 / Math.PI;
}
return { property: property, value: value };
}
}
You gotta try this example to see my point
If you remove the ":enter" transition, the element is invisible. Click the debug button to trigger the first transition, and you get to toggle it normally. Note: the ":enter" is empty, to demonstrate the bare minimum required to keep the element visible.
In any case, the "inactive" state is not applied initially. Here's the example case:
Activity
skycaptainskycaptain commentedon Apr 4, 2017
Ok the STYLE_TRANSFORMATION_MAP explains why something like transform: "translateX(100px) translateY(100px)" only translates the y, as only using "translateX" or "translateY" defaults the other to 0.
So here as well I would need "translate(100px, 100px)", but that same parsing issue butchers the expression at the comma. So fixing that pretty much makes it all work, then one just needs to use the double value syntax.
skycaptainskycaptain commentedon Apr 4, 2017
There's something else seriously wrong. I prototyped a fix which handles each subsequent transform value in a way that it combines already applied values with the new one, which essentially fixes the original issues. So I can write like: transform: "scaleX(2) scaleY(3) translateX(100px) translateY(200px)" and it works.
BUT any initially applied transform causes the element to disappear. I can't attach the debugger in time, so I don't know what happens. If I put there another element I can use to trigger a state change, it will reveal the element, it will animate, and I can make it go back and forth between the states. The code example can be found in this post.
Here's the code that makes my syntax work
I hacked the "nativescript-angular/nativescript-angular/animations/utils.ts", typed directly in the built code - it's not typescript, but JavaScript.
Simple to spot the changes though - what I did was that if the "parseTransformation" reduce argument "transformation.property" already is a "base" version of the property being applied (eg. "transition" and "transitionX"), it will detect it and get the "mirror" value already applied, if applied. So when it applies "transitionX", it passes in "y" value if it was found set already.
You gotta try this example to see my point
If you remove the ":enter" transition, the element is invisible. Click the debug button to trigger the first transition, and you get to toggle it normally. Note: the ":enter" is empty, to demonstrate the bare minimum required to keep the element visible.
In any case, the "inactive" state is not applied initially. Here's the example case:
NickIliev commentedon Apr 5, 2017
regarding:
@skycaptainskycaptain we greatly appreciate all PRs made from our community members :)
Here is some contribution tips, but I would also recommend getting an opinion from either @vakrilov or @sis0k0 regarding the angular animations.
Ping @sis0k0 , @vakrilov , @PanayotCankov
fix(animations): use parsers from core modules
fix(animations): use parsers from core modules (#844)
srnaik commentedon Jun 20, 2017
Is there any example related to flip-flop animation in nativescript like below link
FLip-Flop Animation: