]> source.dussan.org Git - gwtquery.git/commitdiff
add color animation
authorJulien Dramaix <julien.dramaix@gmail.com>
Fri, 22 Apr 2011 09:08:34 +0000 (09:08 +0000)
committerJulien Dramaix <julien.dramaix@gmail.com>
Fri, 22 Apr 2011 09:08:34 +0000 (09:08 +0000)
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ColorEffect.java [new file with mode: 0644]
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTest.java

diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ColorEffect.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ColorEffect.java
new file mode 100644 (file)
index 0000000..aa1b814
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2011, 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 com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.query.client.GQuery;
+import com.google.gwt.query.client.css.BorderColorProperty;
+import com.google.gwt.query.client.css.CSS;
+import com.google.gwt.query.client.css.RGBColor;
+import com.google.gwt.query.client.js.JsNamedArray;
+import com.google.gwt.query.client.js.JsObjectArray;
+import com.google.gwt.query.client.js.JsRegexp;
+import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Effect;
+
+public class ColorEffect extends Effect {
+
+  /**
+   * Specific class handle specific borderColor shortcut properties
+   * 
+   */
+  public static class BorderColorEffect extends ColorEffect {
+
+    private static BorderColorProperty[] borderColorProperties = {
+        CSS.BORDER_BOTTOM_COLOR, CSS.BORDER_TOP_COLOR, CSS.BORDER_LEFT_COLOR,
+        CSS.BORDER_RIGHT_COLOR};
+    private JsNamedArray<int[]> startColors;
+    
+
+    public BorderColorEffect(Element e, String endColorString) {
+      
+      endColor = parseColor(endColorString);
+      startColors = JsNamedArray.create();
+      
+      GQuery $e = GQuery.$(e);
+      
+      for (BorderColorProperty border : borderColorProperties){
+        int[] startColor = parseColor($e.css(border, true));
+        startColors.put(border.getCssName(), startColor);
+      }
+    }
+    
+    
+    @Override
+    public void applyValue(GQuery g, double progress) {
+      for (BorderColorProperty border : borderColorProperties){
+        startColor = startColors.get(border.getCssName());
+        attr = border.getCssName();
+        super.applyValue(g, progress);
+      }
+    }
+  }
+
+  // hexadecimal regex
+  private static JsRegexp HEXADECIMAL_COLOR_PATTERN = new JsRegexp(
+      "#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})");
+  private static JsNamedArray<int[]> htmlColorToRgb;
+
+  // rgb and rgba regex
+  private static JsRegexp RGB_COLOR_PATTERN = new JsRegexp(
+      "rgba?\\(\\s*([0-9]{1,3}%?)\\s*,\\s*([0-9]{1,3}%?)\\s*,\\s*([0-9]{1,3}%?).*\\)$");
+
+  static {
+    htmlColorToRgb = JsNamedArray.create();
+    htmlColorToRgb.put("white", new int[]{255, 255, 255});
+    htmlColorToRgb.put("aqua", new int[]{0, 255, 255});
+    htmlColorToRgb.put("azure", new int[]{240, 255, 255});
+    htmlColorToRgb.put("beige", new int[]{245, 245, 220});
+    htmlColorToRgb.put("black", new int[]{0, 0, 0});
+    htmlColorToRgb.put("blue", new int[]{0, 0, 255});
+    htmlColorToRgb.put("brown", new int[]{165, 42, 42});
+    htmlColorToRgb.put("cyan", new int[]{0, 255, 255});
+    htmlColorToRgb.put("darkblue", new int[]{0, 0, 139});
+    htmlColorToRgb.put("darkcyan", new int[]{0, 139, 139});
+    htmlColorToRgb.put("darkgrey", new int[]{169, 169, 169});
+    htmlColorToRgb.put("darkgreen", new int[]{0, 100, 0});
+    htmlColorToRgb.put("darkkhaki", new int[]{189, 183, 107});
+    htmlColorToRgb.put("darkmagenta", new int[]{139, 0, 139});
+    htmlColorToRgb.put("darkolivegreen", new int[]{85, 107, 47});
+    htmlColorToRgb.put("darkorange", new int[]{255, 140, 0});
+    htmlColorToRgb.put("darkorchid", new int[]{153, 50, 204});
+    htmlColorToRgb.put("darkred", new int[]{139, 0, 0});
+    htmlColorToRgb.put("darksalmon", new int[]{233, 150, 122});
+    htmlColorToRgb.put("darkviolet", new int[]{148, 0, 211});
+    htmlColorToRgb.put("fuchsia", new int[]{255, 0, 255});
+    htmlColorToRgb.put("gold", new int[]{255, 215, 0});
+    htmlColorToRgb.put("green", new int[]{0, 128, 0});
+    htmlColorToRgb.put("indigo", new int[]{75, 0, 130});
+    htmlColorToRgb.put("khaki", new int[]{240, 230, 140});
+    htmlColorToRgb.put("lightblue", new int[]{173, 216, 230});
+    htmlColorToRgb.put("lightcyan", new int[]{224, 255, 255});
+    htmlColorToRgb.put("lightgreen", new int[]{144, 238, 144});
+    htmlColorToRgb.put("lightgrey", new int[]{211, 211, 211});
+    htmlColorToRgb.put("lightpink", new int[]{255, 182, 193});
+    htmlColorToRgb.put("lightyellow", new int[]{255, 255, 224});
+    htmlColorToRgb.put("lime", new int[]{0, 255, 0});
+    htmlColorToRgb.put("magenta", new int[]{255, 0, 255});
+    htmlColorToRgb.put("maroon", new int[]{128, 0, 0});
+    htmlColorToRgb.put("navy", new int[]{0, 0, 128});
+    htmlColorToRgb.put("olive", new int[]{128, 128, 0});
+    htmlColorToRgb.put("orange", new int[]{255, 165, 0});
+    htmlColorToRgb.put("pink", new int[]{255, 192, 203});
+    htmlColorToRgb.put("purple", new int[]{128, 0, 128});
+    htmlColorToRgb.put("violet", new int[]{128, 0, 128});
+    htmlColorToRgb.put("red", new int[]{255, 0, 0});
+    htmlColorToRgb.put("silver", new int[]{192, 192, 192});
+    htmlColorToRgb.put("white", new int[]{255, 255, 255});
+    htmlColorToRgb.put("yellow", new int[]{255, 255, 0});
+
+  }
+
+  protected int[] endColor;
+  protected int[] startColor;
+  
+  ColorEffect(String attr, String startColorString, String endColorString) {
+    assert startColorString != null && endColorString != null;
+    this.attr = attr;
+    startColor = parseColor(startColorString);
+    endColor = parseColor(endColorString);
+    GWT.log("startColorString" + startColorString);
+  };
+
+  private ColorEffect(){}
+
+  @Override
+  public void applyValue(GQuery g, double progress) {
+    int[] result = new int[3];
+    for (int i = 0; i < 3; i++) {
+      int composante = (int) Math.round(startColor[i] + progress
+          * (endColor[i] - startColor[i]));
+      result[i] = Math.max(0, Math.min(255, composante));
+    }
+    String value = RGBColor.rgb(result[0], result[1], result[2]).getCssName();
+
+    g.css(attr, value);
+  }
+
+  public int[] getEndColor() {
+    return endColor;
+  }
+
+  public int[] getStartColor() {
+    return startColor;
+  }
+
+  protected int[] parseColor(String color) {
+    JsObjectArray<String> matches = RGB_COLOR_PATTERN.exec(color);
+    if (matches != null) {
+      return parseRGBColor(matches);
+    }
+
+    matches = HEXADECIMAL_COLOR_PATTERN.exec(color);
+    if (matches != null) {
+      return parseHexColor(matches);
+    }
+
+    return parseLiteralColor(color);
+  }
+
+  private int[] parseHexColor(JsObjectArray<String> matches) {
+    assert matches.length() == 2;
+    int[] result = new int[3];
+
+    String hexCode = matches.get(1);
+
+    int step = (hexCode.length() == 3) ? 1 : 2;
+
+    for (int i = 0; i < 3; i++) {
+      String color = hexCode.substring(i * step, (i * step) + step);
+      if (step == 1) {
+        color += color;
+      }
+      result[i] = Math.max(0, Math.min(255, Integer.parseInt(color, 16)));
+
+    }
+
+    return result;
+  }
+
+  private int[] parseLiteralColor(String color) {
+    return htmlColorToRgb.get(color);
+  }
+
+  private int[] parseRGBColor(JsObjectArray<String> matches) {
+    assert matches.length() == 4;
+    int[] result = new int[3];
+
+    for (int i = 1; i < 4; i++) {
+      String valueString = matches.get(i);
+      int value = -1;
+      if (valueString.endsWith("%")) {
+        int percentage = Integer.parseInt(valueString.substring(0,
+            valueString.length() - 1));
+        value = Math.round((float) 2.55 * percentage);
+      } else {
+        value = Integer.parseInt(valueString);
+      }
+      result[i - 1] = Math.max(0, Math.min(255, value));
+    }
+    return result;
+  }
+
+}
\ No newline at end of file
index e681da13bd73dbe6f6a453646f14ab8bcd9f2db0..62cc5da9a0ed797b1cc02ee81eeeeb1060cffb72 100755 (executable)
@@ -15,8 +15,6 @@
  */\r
 package com.google.gwt.query.client.plugins.effects;\r
 \r
-import java.util.ArrayList;\r
-\r
 import com.google.gwt.animation.client.Animation;\r
 import com.google.gwt.dom.client.Element;\r
 import com.google.gwt.query.client.Function;\r
@@ -25,9 +23,12 @@ import com.google.gwt.query.client.Properties;
 import com.google.gwt.query.client.js.JsObjectArray;\r
 import com.google.gwt.query.client.js.JsRegexp;\r
 import com.google.gwt.query.client.plugins.Effects;\r
+import com.google.gwt.query.client.plugins.effects.ColorEffect.BorderColorEffect;\r
+\r
+import java.util.ArrayList;\r
 \r
 /**\r
- *  Animation effects on any numeric CSS property. \r
+ * Animation effects on any numeric CSS property.\r
  */\r
 public class PropertiesAnimation extends Animation {\r
 \r
@@ -36,33 +37,36 @@ public class PropertiesAnimation extends Animation {
    */\r
   public static interface Easing {\r
     public double interpolate(double progress);\r
-    \r
-    public Easing LINEAR = new Easing() {     \r
+\r
+    public Easing LINEAR = new Easing() {\r
       public double interpolate(double progress) {\r
         return progress;\r
       }\r
     };\r
-    \r
-    public Easing SWING = new Easing() {     \r
+\r
+    public Easing SWING = new Easing() {\r
       public double interpolate(double progress) {\r
-       return (1 + Math.cos(Math.PI + progress * Math.PI)) / 2;\r
+        return (1 + Math.cos(Math.PI + progress * Math.PI)) / 2;\r
       }\r
     };\r
   }\r
-  \r
+\r
   /**\r
    * A pojo to store effect values.\r
    */\r
   public static class Effect {\r
-
+\r
     public String attr;\r
     public double end;\r
     public double start;\r
     public String unit;\r
     public String value;\r
 \r
-    Effect(String attr, String value, double start, double end,\r
-        String unit) {\r
+    Effect() {\r
+      end = start = -1;\r
+    }\r
+\r
+    Effect(String attr, String value, double start, double end, String unit) {\r
       this.attr = attr;\r
       this.value = value;\r
       this.start = start;\r
@@ -70,40 +74,90 @@ public class PropertiesAnimation extends Animation {
       this.unit = unit;\r
     }\r
 \r
-    public String getVal(double progress) {\r
+    public void applyValue(GQuery g, double progress) {\r
+\r
       double ret = (start + ((end - start) * progress));\r
-      return ("px".equals(unit) ? ((int) ret) : ret) + unit;\r
+      String value = ("px".equals(unit) ? ((int) ret) : ret) + unit;\r
+\r
+      g.css(attr, value);\r
     }\r
-    \r
+\r
     public String toString() {\r
-      return ("attr=" + attr + " value=" + value + " start=" + start + " end=" + end + " unit=" + unit).replaceAll("\\.0([^\\d])", "$1");\r
+      return ("attr=" + attr + " value=" + value + " start=" + start + " end="\r
+          + end + " unit=" + unit).replaceAll("\\.0([^\\d])", "$1");\r
     }\r
   }\r
-  \r
-  private static final String[] attrsToSave = new String[] { "overflow",\r
-      "visibility" };\r
+\r
+  private static final String[] attrsToSave = new String[]{\r
+      "overflow", "visibility"};\r
 \r
   private static JsRegexp nonPxRegExp = new JsRegexp(\r
       "z-?index|font-?weight|opacity|zoom|line-?height", "i");\r
-  \r
-  \r
+\r
+  private static JsRegexp colorRegExp = new JsRegexp(".*color$", "i");\r
+  public static JsRegexp RGB_COLOR_PATTERN = new JsRegexp(\r
+      "rgb\\(\\s*([0-9]{1,3}%?)\\s*,\\s*([0-9]{1,3}%?)\\s*,\\s*([0-9]{1,3}%?)\\s*\\)$");\r
+  public static JsRegexp HEXADECIMAL_COLOR_PATTERN = new JsRegexp(\r
+      "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$");\r
+\r
   public static Effect computeFxProp(Element e, String key, String val,\r
       boolean hidden) {\r
+\r
+    if (colorRegExp.test(key)) {\r
+      return computeFxColorProp(e, key, val);\r
+    }\r
+\r
+    return computeFxNumericProp(e, key, val, hidden);\r
+  }\r
+\r
+  private static Effect computeFxColorProp(Element e, String key, String val) {\r
+\r
+    if ("BORDERCOLOR".equals(key.toUpperCase())) {\r
+      return new BorderColorEffect(e, val);\r
+    }\r
+\r
+    String initialColor = null;\r
+\r
+    if ("BACKGROUNDCOLOR".equals(key.toUpperCase())) {\r
+      // find the first parent having a background-color value (other than\r
+      // transparent)\r
+      Element current = e;\r
+\r
+      while ((initialColor == null || initialColor.length() == 0 || initialColor.equals("transparent"))\r
+          && current != null) {\r
+        initialColor = GQuery.$(current).css(key);\r
+        current = !"body".equalsIgnoreCase(current.getTagName())\r
+            ? current.getParentElement() : null;\r
+      }\r
+      if (initialColor == null || initialColor.length() == 0\r
+          || initialColor.equals("transparent")) {\r
+        initialColor = "white";\r
+      }\r
+    } else {\r
+      initialColor = GQuery.$(e).css(key, true);\r
+    }\r
+\r
+    return new ColorEffect(key, initialColor, val);\r
+  }\r
+\r
+  public static Effect computeFxNumericProp(Element e, String key, String val,\r
+      boolean hidden) {\r
+\r
     GQuery g = Effects.$(e);\r
     String unit = "";\r
     if ("toggle".equals(val)) {\r
       val = hidden ? "show" : "hide";\r
     }\r
-    \r
-    if (("show".equals(val) && !hidden) || ("hide").equals(val) && hidden){\r
+\r
+    if (("show".equals(val) && !hidden) || ("hide").equals(val) && hidden) {\r
       return null;\r
     }\r
-    \r
-    if (hidden){\r
+\r
+    if (hidden) {\r
       g.show();\r
     }\r
     double start = g.cur(key, true), end = start;\r
-    \r
+\r
     if ("show".equals(val)) {\r
       g.saveCssAttrs(key);\r
       start = 0;\r
@@ -123,7 +177,8 @@ public class PropertiesAnimation extends Animation {
         String $2 = parts.get(2);\r
         String $3 = parts.get(3);\r
         end = Double.parseDouble($2);\r
-        unit = nonPxRegExp.test(key) ? "" : $3 == null || $3.isEmpty() ? "px" : $3;\r
+        unit = nonPxRegExp.test(key) ? "" : $3 == null || $3.isEmpty() ? "px"\r
+            : $3;\r
         if (!"px".equals(unit)) {\r
           double to = end == 0 ? 1 : end;\r
           g.css(key, to + unit);\r
@@ -135,10 +190,11 @@ public class PropertiesAnimation extends Animation {
         }\r
       }\r
     }\r
-    \r
+\r
     Effect fx = new Effect(key, val, start, end, unit);\r
     return fx;\r
   }\r
+\r
   private Element e;\r
   private Easing easing = Easing.SWING;\r
   private ArrayList<Effect> effects = new ArrayList<Effect>();\r
@@ -172,7 +228,7 @@ public class PropertiesAnimation extends Animation {
       } else if ("show".equals(l.value)) {\r
         g.show();\r
         g.restoreCssAttrs(l.attr);\r
-      }     \r
+      }\r
     }\r
     g.restoreCssAttrs(attrsToSave);\r
     g.each(funcs);\r
@@ -185,7 +241,7 @@ public class PropertiesAnimation extends Animation {
     boolean move = false;\r
     boolean hidden = !g.visible();\r
     Effect fx;\r
-    //g.show();\r
+    // g.show();\r
     for (String key : prps.keys()) {\r
       String val = prps.getStr(key);\r
       if ((fx = computeFxProp(e, key, val, hidden)) != null) {\r
@@ -199,7 +255,7 @@ public class PropertiesAnimation extends Animation {
       g.css("overflow", "hidden");\r
     }\r
     if (move && !g.css("position", true).matches("absolute|relative")) {\r
-      g.css("position", "relative");    \r
+      g.css("position", "relative");\r
     }\r
     g.css("visibility", "visible");\r
     super.onStart();\r
@@ -208,16 +264,17 @@ public class PropertiesAnimation extends Animation {
   @Override\r
   public void onUpdate(double progress) {\r
     for (Effect fx : effects) {\r
-      g.css(fx.attr, fx.getVal(progress));\r
+      fx.applyValue(g, progress);\r
+\r
     }\r
   }\r
 \r
   @Override\r
   protected double interpolate(double progress) {\r
-    if (easing != null){\r
+    if (easing != null) {\r
       return easing.interpolate(progress);\r
     }\r
-    //maybe return super.interpolate() instead ?\r
+    // maybe return super.interpolate() instead ?\r
     return progress;\r
   }\r
 \r
index a120eb70c449556191b32637ff3619b61c70099a..313feb8b4dbaebf0fefb2c8d529c4fdb10f708eb 100644 (file)
@@ -22,6 +22,7 @@ import com.google.gwt.dom.client.Element;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.query.client.GQuery.Offset;
 import com.google.gwt.query.client.plugins.Effects;
+import com.google.gwt.query.client.plugins.effects.ColorEffect;
 import com.google.gwt.query.client.plugins.effects.PropertiesAnimation;
 import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing;
 import com.google.gwt.user.client.Timer;
@@ -285,6 +286,35 @@ public class GQueryEffectsTest extends GWTTestCase {
             .toString());
   }
   
+  public void testColorEffectParsing(){
+    String html = "<div id='test' style='color: #112233'>Test</div>";
+    $(e).html(html);
+    
+    ColorEffect effect = (ColorEffect) PropertiesAnimation.computeFxProp($("#test",e).get(0), "color", "#ffffff", false);
+    assertEquals(17, effect.getStartColor()[0]); //#11
+    assertEquals(34, effect.getStartColor()[1]); //#22
+    assertEquals(51, effect.getStartColor()[2]); //#33
+    
+    assertEquals(255, effect.getEndColor()[0]);
+    assertEquals(255, effect.getEndColor()[1]);
+    assertEquals(255, effect.getEndColor()[2]);
+    
+    effect = (ColorEffect) PropertiesAnimation.computeFxProp(e, "color", "rgb(255,255,255)", false);
+    assertEquals(255, effect.getEndColor()[0]);
+    assertEquals(255, effect.getEndColor()[1]);
+    assertEquals(255, effect.getEndColor()[2]);
+    
+    effect = (ColorEffect) PropertiesAnimation.computeFxProp(e, "color", "rgb(100%, 100%, 100%)", false);
+    assertEquals(255, effect.getEndColor()[0]);
+    assertEquals(255, effect.getEndColor()[1]);
+    assertEquals(255, effect.getEndColor()[2]);
+    
+    effect = (ColorEffect) PropertiesAnimation.computeFxProp(e, "color", "white", false);
+    assertEquals(255, effect.getEndColor()[0]);
+    assertEquals(255, effect.getEndColor()[1]);
+    assertEquals(255, effect.getEndColor()[2]);
+  }
+  
   private void assertPosition(GQuery g, Offset min, Offset max) {
     int a = Math.min(min.top, max.top);
     int b = Math.max(min.top, max.top);
@@ -302,5 +332,5 @@ public class GQueryEffectsTest extends GWTTestCase {
         + " - " + b;
     assertTrue(msg, c);
   }
-
+  
 }