![JAR search and dependency download from the Maven repository](/logo.png)
com.google.gwt.query.client.plugins.effects.Transitions Maven / Gradle / Ivy
/*
*
* Copyright 2013, The gwtquery team.
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.query.client.plugins.effects;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import com.google.gwt.core.client.Duration;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.GQuery;
import com.google.gwt.query.client.Properties;
import com.google.gwt.query.client.js.JsUtils;
import com.google.gwt.query.client.plugins.Plugin;
import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing;
import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve;
import com.google.gwt.regexp.shared.MatchResult;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
/**
* Transitions and transformation plugin for gQuery.
*
* It is inspired on jquery.transit (http://github.com/rstacruz/jquery.transit)
*
* Usage examples:
*
$("#foo")
.transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, "easeOutBack", 0)
.promise().done(new Function(){public void f() {
g1.transition("{x: +100}", 2000, "linear", 0);
}});
$("#bar")
.transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, EasingCurve.easeInBack)
.transition("{x: +100, width: +40px}", 2000, EasingCurve.easeOut);
*
*/
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> map = new HashMap>();
public Transform(String s) {
parse(s);
}
public String get(String prop) {
return listToStr(map.get(prop), ",");
}
private String listToStr(List 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");
for (MatchResult r = re.exec(s); r != null; r = re.exec(s)) {
setFromString(r.getGroup(1), r.getGroup(2));
}
}
}
public void set(String prop, String ...val) {
setter(prop, val);
}
public void setFromString(String prop, String ...val) {
if (val.length == 1) {
String[] vals = val[0].split("[\\s*,\\s*]");
set(prop, vals);
} else {
set(prop, val);
}
}
private void setter(String prop, String ...val) {
if (prop.matches("(rotate[XY]?|skew[XY])")) {
map.put(prop, unit(val[0], "deg"));
} else if ("scale".equals(prop)) {
String x = val.length < 1 ? "1" : val[0];
String y = val.length < 2 ? x : val[1];
map.put(prop, Arrays.asList(x, y));
} else if ("perspective".equals(prop)) {
map.put(prop, unit(val[0], "px"));
} else if ("x".equals(prop)) {
setter("translate", val[0], null);
} else if ("y".equals(prop)) {
setter("translate", null, val[0]);
} else if ("translate".equals(prop)) {
if (map.get("translateX") == null) {
map.put("translateX", unit("0", "px"));
}
if (val[0] != null) {
map.put("translateX", unit(val[0], "px"));
}
if (map.get("translateY") == null) {
map.put("translateY", unit("0", "px"));
}
if (val[1] != null) {
map.put("translateY", unit(val[1], "px"));
}
map.put("translate", Arrays.asList(map.get("translateX").get(0), map.get("translateY").get(0)));
}
}
/**
* Converts the dictionary to a transition css string.
*/
public String toString() {
// purposely using string addition, since my last tests demonstrate
// that string addition performs better than string builders in gwt-prod.
String ret = "";
for (Entry> e: map.entrySet()) {
if (has3d || !transform3dRegex.test(e.getKey())) {
String v = listToStr(e.getValue(), ",");
ret += (ret.isEmpty() ? "" : " ") + e.getKey() + "(" + v + ")";
}
}
return ret;
}
private List 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)$");
protected static final String transition = getVendorPropertyName("transition");
// passing an invalid transition property in chrome, makes disable all transitions in the element
private static final RegExp invalidTransitionNamesRegex = RegExp.compile("^(.*transform.*|duration|easing|delay|clip-.*)$");
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 = GQuery.registerPlugin(
Transitions.class, new Plugin() {
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);
if (JsUtils.hasProperty(divStyle, vendorProp)) {
return vendorProp;
}
if (JsUtils.hasProperty(divStyle, prop)) {
return prop;
}
String camelProp = JsUtils.camelize(prop);
if (JsUtils.hasProperty(divStyle, camelProp)) {
return camelProp;
}
return null;
}
private static String property(String prop) {
if (transformRegex.test(prop)) {
return transform;
}
return prop.replaceFirst("^(margin|padding).+$", "$1");
}
private static boolean supportsTransform3d() {
if (transform == null) {
return false;
}
String rotate = "rotateY(1deg)";
divStyle.setProperty(transform, rotate);
rotate = divStyle.getProperty(transform);
return rotate != null && !rotate.isEmpty();
}
protected Transitions(GQuery gq) {
super(gq);
}
@Override
public String css(String prop, boolean force) {
if ("transform".equals(prop)) {
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 {
String ret = super.css(prop, force);
return ret;
}
}
@Override
public Transitions css(String prop, String value) {
if ("transform".equals(prop)) {
for (Element e : elements()) {
Transform t = getTransform(e, value);
getStyleImpl().setStyleProperty(e, transform, t.toString());
}
} else if ("transformOrigin".equals(prop)) {
super.css(transformOrigin, value);
} else if ("transition".equals(prop)) {
super.css(transition, value);
} else if (transformRegex.test(prop)) {
for (Element e : elements()) {
Transform t = getTransform(e, null);
t.setFromString(prop, value);
getStyleImpl().setStyleProperty(e, transform, t.toString());
}
} else if (!invalidTransitionNamesRegex.test(prop)){
super.css(prop, value);
}
return this;
}
private List filterTransitionPropertyNames(Properties p) {
List ret = new ArrayList();
for (String s : p.keys()) {
if (invalidTransitionNamesRegex.test(s)) {
continue;
}
String c = JsUtils.camelize(s);
// marginLeft, marginRight ... -> margin
String m = property(c);
if (m != null) {
c = m;
}
// 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() ) {
t = new Transform(initial);
data(e, TRANSFORM, t);
}
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.
*
* Example:
*
$("#foo").transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, EasingCurve.easeInBack);
$("#bar")
.transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, EasingCurve.easeInBack)
.transition("{x: +100, width: +40px}", 2000, EasingCurve.easeOut);
*
*/
public Transitions transition(Object stringOrProperties, final int duration, final Easing easing, final int delay, final Function... funcs) {
if (isEmpty()) {
return this;
}
final Properties cssProps = (stringOrProperties instanceof String)
? $$((String) stringOrProperties)
: (Properties) stringOrProperties;
final String ease = easing == null ? "ease" : easing.toString();
final List transProps = filterTransitionPropertyNames(cssProps);
final double queuedAt = delay > 0 ? Duration.currentTimeMillis() : 0;
// Use gQuery queue, so as we can chain transitions, animations etc.
queue(new Function(){
public void f() {
// This is called once per element
final String oldTransitionValue = $(this).css(transition);
// Recompute delay based on the time spent in the queue
int d = Math.max(0, delay - (int)(Duration.currentTimeMillis() - queuedAt));
// Generate transition value
String attribs = duration + "ms" + " " + ease + " " + d + "ms";
String newTransitionValue = "";
for (String s : transProps) {
newTransitionValue += (newTransitionValue.isEmpty() ? "" : ", ") + s + " " + attribs;
}
final Transitions thisTrans = $(this).as(Transitions);
// Configure animation using transition property
thisTrans.css(transition, newTransitionValue);
// Set all css properties for this transition using the css method in this class
thisTrans.css(cssProps);
// TODO: Use transitionEnd events once GQuery supports non-bit events
// last time I tried, setting 'transitionEnd' made custom events fail (slideEnter)
new Timer() {
public void run() {
thisTrans.css(transition, oldTransitionValue).each(funcs).dequeue();
}
}.schedule(d + duration);
}
});
return this;
}
/**
* 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() but has an extra parameter for delaying the animation.
*
* Example animate an element within 2 seconds:
* $("#foo")
* .transition("{ opacity: 0.1, scale: 2, x: 50, y: 50 }", 5000, EasingCurve.easeInBack, 2000);
*
*/
public Transitions transition(Object stringOrProperties, int duration, String easing, int delay) {
return transition(stringOrProperties, duration, EasingCurve.valueOf(easing), delay);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy