import com.google.gwt.query.client.plugins.effects.PropertiesAnimation;
import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing;
import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve;
+import com.google.gwt.query.client.plugins.effects.TransitionsAnimation;
+import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation;
/**
* Effects plugin for Gwt Query.
// Each Animation is associated to one element
protected Element e;
protected Properties prps;
-
+
protected GQAnimation setElement(Element element) {
e = element;
return this;
}
protected GQAnimation setProperties(Properties properties) {
- prps = properties;
+ prps = properties == null ? Properties.create() : properties;
return this;
}
protected void onStart() {
public static final int SLOW = 600;
}
-
public static final Class<Effects> Effects = GQuery.registerPlugin(
Effects.class, new Plugin<Effects>() {
public Effects init(GQuery gq) {
public Effects animate(Object stringOrProperties, final int duration,
final Easing easing, final Function... funcs) {
+
final Properties p = (stringOrProperties instanceof String)
? $$((String) stringOrProperties) : (Properties) stringOrProperties;
for (Element e: elements()) {
- queueAnimation(e, new PropertiesAnimation(easing, e, p, funcs), duration);
+ if (Fx.css3) {
+ new TransitionsAnimation(easing, e, p, funcs).run(duration);
+ } else {
+ queueAnimation(e, new PropertiesAnimation(easing, e, p, funcs), duration);
+ }
}
return this;
}
+ private static native void set(Element e) /*-{
+ $wnd.eee = e;
+ }-*/;
+
/**
*
* The animate() method allows you to create animation effects on any numeric
final ClipAnimation.Corner c, final ClipAnimation.Direction d,
final int duration, final Function... f) {
for (Element e : elements()) {
- queueAnimation(e, new ClipAnimation(e, a, c, d, f), duration);
+ if (Fx.css3) {
+ new TransitionsClipAnimation(e, a, c, d, null, null, f).run(duration);
+ } else {
+ queueAnimation(e, new ClipAnimation(e, a, c, d, f), duration);
+ }
}
return this;
}
public Effects fadeOut(int millisecs, Function... f) {
return animate("opacity: 'hide'", millisecs, f);
};
-
+
/**
* Fade the opacity of all matched elements to a specified opacity and firing
* an optional callback after completion. Only the opacity is adjusted for
public Effects fadeTo(double opacity, Function... f) {
return fadeTo(Speed.DEFAULT, opacity, f);
}
-
+
/**
* Fade the opacity of all matched elements to a specified opacity and firing
* an optional callback after completion. Only the opacity is adjusted for
*/
package com.google.gwt.query.client.plugins.effects;
-
import com.google.gwt.dom.client.Element;
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.GQuery;
direction = Direction.valueOf(getNormalizedValue("clip-direction", p));
} catch (Exception e) {
}
- action = Action.TOGGLE;
try {
action = Action.valueOf(getNormalizedValue("clip-action", p));
} catch (Exception e) {
}
-
- this.funcs = funcs;
- e = elem;
g = GQuery.$(e).as(Effects.Effects);
}
- private String getNormalizedValue(String value, Properties p) {
+ private static String getNormalizedValue(String value, Properties p) {
return JsUtils.hyphenize(p.getStr("clip-direction")).replace("-", "_").toUpperCase();
}
this.action = a;
this.corner = c;
this.direction = d;
- this.funcs = funcs;
- e = elem;
g = GQuery.$(e).as(Effects.Effects);
}
bottom = h;
}
- String rect = top + "px " + right + "px " + bottom + "px " + left + "px";
- g.css("clip", "rect(" + rect + ")");
+ g.css("clip", "rect(" + top + "px " + right + "px " + bottom + "px " + left + "px)");
}
}
*/
public static boolean off = false;
+ public static boolean css3 = Transitions.transition != null;
+
/**
* A pojo to store css3 transition values.
*/
protected static final RegExp REGEX_SYMBOL_NUMBER_UNIT = RegExp.compile("^([+-]=)?([0-9+-.]+)(.*)?$");
protected static final RegExp REGEX_NON_PIXEL_ATTRS =
- RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|^\\$", "i");
+ RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|scale|rotation|^\\$", "i");
private static final RegExp REGEX_COLOR_ATTR = RegExp.compile(".*color$", "i");
protected Easing easing;
protected JsObjectArray<Fx> effects;
- protected Function[] funcs;
+ private Function[] funcs;
private Effects g;
public PropertiesAnimation(Element elem, Properties p, Function... funcs) {
/**
* Transitions and transformation plugin for gQuery.
- *
+ *
* It is inspired on jquery.transit (http://github.com/rstacruz/jquery.transit)
*
* Usage examples:
- * <pre>
+ * <pre>
$("#foo")
.transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, "easeOutBack", 0)
* </pre>
*/
public class Transitions extends GQuery {
-
+
/**
* A dictionary class with all the properties of an element transform
* which is able to return the correct syntax for setting css properties.
*/
public static class Transform {
-
+
private static final RegExp transform3dRegex = RegExp.compile("^(rotate([XY]|3d)|perspective)$");
-
+
private HashMap<String, List<String>> map = new HashMap<String, List<String>>();
public Transform(String s) {
parse(s);
}
-
- public List<String> get(String prop) {
- return map.get(prop);
+
+ public String get(String prop) {
+ return listToStr(map.get(prop), ",");
+ }
+
+ private String listToStr(List<String> l, String sep) {
+ String v = "";
+ if (l != null) {
+ for (String s : l) {
+ v += (v.isEmpty() ? "" : sep) + s;
+ }
+ }
+ return v;
}
-
+
private void parse(String s) {
if (s != null) {
RegExp re = RegExp.compile("([a-zA-Z0-9]+)\\((.*?)\\)", "g");
}
}
}
-
+
public void set(String prop, String ...val) {
setter(prop, val);
}
-
+
public void setFromString(String prop, String ...val) {
if (val.length == 1 && val[0] instanceof String) {
String[] vals = ((String)val[0]).split("[\\s*,\\s*]");
set(prop, val);
}
}
-
+
private void setter(String prop, String ...val) {
if (prop.matches("(rotate[XY]?|skew[XY])")) {
map.put(prop, unit(val[0], "deg"));
map.put("translate", Arrays.asList(map.get("translateX").get(0), map.get("translateY").get(0)));
}
}
-
+
/**
* Converts the dictionary to a transition css string.
*/
String ret = "";
for (Entry<String, List<String>> e: map.entrySet()) {
if (has3d || !transform3dRegex.test(e.getKey())) {
- String v = "";
- for (String s : e.getValue()) {
- v += (v.isEmpty() ? "" : ",") + s;
- }
+ String v = listToStr(e.getValue(), ",");
ret += (ret.isEmpty() ? "" : " ") + e.getKey() + "(" + v + ")";
}
}
return ret;
}
-
+
private List<String> unit(String val, String unit) {
return Arrays.asList(val + (val.endsWith(unit) ? "" : unit));
}
}
-
+
// Used to check supported properties in the browser
private static Style divStyle = DOM.createDiv().getStyle();
-
+
private static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : "";
private static final String transform = getVendorPropertyName("transform");
private static final String TRANSFORM = "_t_";
private static final String transformOrigin = getVendorPropertyName("transformOrigin");
-
+
protected static final RegExp transformRegex = RegExp.compile("^(scale|translate|rotate([XY]|3d)?|perspective|skew[XY]|x|y)$");
- private static final String transition = getVendorPropertyName("transition");
-
+ protected static final String transition = getVendorPropertyName("transition");
+
private static final String transitionDelay = getVendorPropertyName("transitionDelay");
private static final String transitionEnd = browser.mozilla || browser.msie ? "transitionend" : (prefix + "transitionEnd");
-
+
public static boolean has3d = supportsTransform3d();
-
+
public static final Class<Transitions> Transitions = GQuery.registerPlugin(
Transitions.class, new Plugin<Transitions>() {
public Transitions init(GQuery gq) {
return new Transitions(gq);
}
});
-
+
private static String getVendorPropertyName(String prop) {
// we prefer vendor specific names by default
String vendorProp = JsUtils.camelize("-" + prefix + "-" + prop);
}
return null;
}
-
+
private static String property(String prop) {
if (transformRegex.test(prop)) {
return transform;
}
return prop.replaceFirst("^(margin|padding).+$", "$1");
}
-
+
private static boolean supportsTransform3d() {
String rotate = "rotateY(1deg)";
divStyle.setProperty(transform, rotate);
rotate = divStyle.getProperty(transform);
return rotate != null && !rotate.isEmpty();
}
-
+
protected Transitions(GQuery gq) {
super(gq);
}
- @Override
+ @Override
public String css(String prop, boolean force) {
if ("transform".equals(prop)) {
- Transform t = data(TRANSFORM);
- return t == null ? "" : t.toString();
+ return isEmpty() ? "" : getTransform(get(0), null).toString();
} else if ("transformOrigin".equals(prop)) {
return super.css(transformOrigin, force);
} else if ("transition".equals(prop)) {
return super.css(transition, force);
+ } else if (transformRegex.test(prop)) {
+ return isEmpty() ? "" : getTransform(get(0), null).get(prop);
} else {
- return super.css(prop, force);
+ String ret = super.css(prop, force);
+ return ret;
}
}
-
- @Override
+
+ @Override
public Transitions css(String prop, String value) {
if ("transform".equals(prop)) {
for (Element e : elements()) {
}
return this;
}
-
+
private List<String> filterPropertyNames(Properties p) {
List<String> ret = new ArrayList<String>();
for (String s : p.keys()) {
if (m != null) {
c = m;
}
- // chrome needs transition:-webkit-transform instead of transition:transform
+ // chrome needs transition:-webkit-transform instead of transition:transform
c = JsUtils.hyphenize(c);
if (!ret.contains(c)) {
ret.add(c);
}
return ret;
}
-
+
private Transform getTransform(Element e, String initial) {
Transform t = data(e, TRANSFORM);
if (t == null || initial != null && !initial.isEmpty() ) {
}
return t;
}
-
+
/**
* The transition() method allows you to create animation effects on any numeric HTML Attribute,
* CSS property, or color using CSS3 transformations and transitions.
- *
+ *
* It works similar to animate(), supports chainning and queueing and an extra parameter for
* delaying the animation.
*
if (isEmpty()) {
return this;
}
-
+
final Properties p = (stringOrProperties instanceof String) ? $$((String) stringOrProperties) : (Properties) stringOrProperties;
final String oldTransitions = css(transition);
if (easing == null) {
easing = EasingCurve.ease;
}
-
+
String attribs = duration + "ms" + " " + easing.toString() + " " + delay + "ms";
List<String> props = filterPropertyNames(p);
String value = "";
for (String s : props) {
value += (value.isEmpty() ? "" : ", ") + s + " " + attribs;
}
-
+
final String transitionValue = value;
// Use gQuery queue, so as we can chain transitions, animations etc.
$(this)
// Configure animation using transition property
.css(transition, transitionValue)
- // Set all css properties for this transition using the css method in this class
- .as(Transitions).css(p)
- // prevent memory leak
- .removeData(TRANSFORM);
+ // Set all css properties for this transition using the css method in this class
+ .as(Transitions).css(p);
}});
-
+
// restore oldTransitions in the element, and use the queue to prevent more effects being run.
// TODO: Use transitionEnd events once GQuery supports non-bit events
delay(duration + delay, new Function(){public void f() {
.css(transition, oldTransitions)
.each(funcs);
}});
-
+
return this;
}
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.Properties;
import com.google.gwt.query.client.js.JsObjectArray;
+import com.google.gwt.query.client.plugins.effects.ClipAnimation.Action;
+import com.google.gwt.query.client.plugins.effects.ClipAnimation.Corner;
+import com.google.gwt.query.client.plugins.effects.ClipAnimation.Direction;
import com.google.gwt.query.client.plugins.effects.Fx.TransitFx;
import com.google.gwt.regexp.shared.MatchResult;
* using CSS3 transitions
*/
public class TransitionsAnimation extends PropertiesAnimation {
-
+
+ public static class TransitionsClipAnimation extends TransitionsAnimation {
+
+ private Action action;
+ private Corner corner;
+ private Direction direction;
+ private Action currentAction;
+
+ public TransitionsClipAnimation(Element elem, Action a, Corner c, Direction d, Easing easing,
+ Properties p, final Function... funcs) {
+ super(easing, elem, p, funcs);
+ this.action = a;
+ this.corner = c;
+ this.direction = d;
+ }
+
+ public void onStart() {
+ boolean hidden = !g.isVisible();
+
+ super.onStart();
+
+ currentAction = action != Action.TOGGLE ? action : hidden ? Action.SHOW : Action.HIDE;
+ int bit = currentAction == Action.HIDE ? 1 : 0;
+
+ String originX = "left", originY = "top";
+ int scaleXini = 0^bit, scaleYini = scaleXini;
+ int scaleXend = 1^bit, scaleYend = scaleXend;
+
+ if (direction == Direction.VERTICAL) {
+ scaleXini = scaleXend = 1;
+ }
+ if (direction == Direction.HORIZONTAL) {
+ scaleYini = scaleYend = 1;
+ }
+ if (corner == Corner.CENTER) {
+ originX = originY = "center";
+ }
+ if (corner == Corner.TOP_RIGHT || corner == Corner.BOTTOM_RIGHT) {
+ originX = "right";
+ }
+ if (corner == Corner.BOTTOM_LEFT || corner == Corner.BOTTOM_RIGHT) {
+ originY = "bottom";
+ }
+
+ g.show().css("transformOrigin", originX + " " + originY);
+
+ effects.add(new TransitFx("scale", "", scaleXini + " " + scaleYini, scaleXend + " " + scaleYend, ""));
+ }
+
+ @Override
+ public void onComplete() {
+ super.onComplete();
+ if (currentAction == Action.HIDE) {
+ g.hide();
+ }
+ g.css("transformOrigin", "");
+ g.css("transform", "scale(1 1)");
+ }
+ }
+
public static Fx computeFxProp(Element e, String key, String val, boolean hidden) {
Transitions g = $(e).as(Transitions.Transitions);
String unit = "";
String cur = g.css(key, true);
String trsStart = cur, trsEnd = trsStart;
-
+
if ("show".equals(val)) {
g.saveCssAttrs(key);
trsStart = "0";
} else if ("hide".equals(val)) {
- if (hidden) {
- return null;
- }
g.saveCssAttrs(key);
trsEnd = "0";
} else {
MatchResult parts = REGEX_SYMBOL_NUMBER_UNIT.exec(val);
if (parts != null) {
unit = REGEX_NON_PIXEL_ATTRS.test(key) || Transitions.transformRegex.test(key) ? "" : "px";
-
+
String part1 = parts.getGroup(1);
String part2 = parts.getGroup(2);
String part3 = parts.getGroup(3);
trsEnd = "" + Double.parseDouble(part2);
-
+
if (unit.isEmpty() && part3 != null) {
unit = part3;
}
if (trsStart.isEmpty()) {
- trsStart = "0";
- }
-
- if (!trsStart.endsWith(unit)) {
- trsStart += unit;
+ trsStart = key.matches("scale") ? "1" : "0";
}
if (part1 != null && !part1.isEmpty()) {
trsEnd = "" + (st + (n*en));
}
} else {
- trsStart = trsEnd = val;
+ trsStart = "";
+ trsEnd = val;
}
}
return new TransitFx(key, val, trsStart, trsEnd, unit);
}
- private Transitions g;
-
+ protected Transitions g;
+
public TransitionsAnimation(Element elem, Properties p, Function... funcs) {
this(null, elem, p, funcs);
}
Properties p = $$();
for (int i = 0; i < effects.length(); i++) {
TransitFx fx = (TransitFx)effects.get(i);
- p.set(fx.cssprop, (isStart ? fx.transitStart : fx.transitEnd) + fx.unit);
+ String val = isStart ? fx.transitStart : fx.transitEnd;
+ if (!val.isEmpty()) {
+ p.set(fx.cssprop, val + fx.unit);
+ }
}
return p;
}
}
}
+ @Override
+ public void onUpdate(double progress) {
+ }
+
@Override
public void run(int duration) {
onStart();
Properties p = getFxProperties(true);
g.css(p);
+ // TODO: Reflow, it seems it is not needed in chrome and FF, check other browsers
+ // g.css("offsetHeight");
p = getFxProperties(false);
- g.transition(p, duration - 150, easing, 0, new Function(){public void f() {
+ g.transition(p, duration, easing, 0, new Function(){public void f() {
onComplete();
}});
}