001/* 002 * #%L 003 * GwtMaterial 004 * %% 005 * Copyright (C) 2015 - 2017 GwtMaterialDesign 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package gwt.material.design.addins.client.pathanimator; 021 022import com.google.gwt.dom.client.Element; 023import com.google.gwt.dom.client.Style; 024import com.google.gwt.user.client.ui.Widget; 025import gwt.material.design.addins.client.MaterialAddins; 026import gwt.material.design.addins.client.pathanimator.js.JsPathAnimator; 027import gwt.material.design.addins.client.pathanimator.js.JsPathAnimatorOptions; 028import gwt.material.design.client.MaterialDesignBase; 029import gwt.material.design.client.base.HasDurationTransition; 030import gwt.material.design.jquery.client.api.Functions; 031 032import static gwt.material.design.jquery.client.api.JQuery.$; 033 034//@formatter:off 035 036/** 037 * Custom component that provides meaningfull transition between two elements to show visual continuity. 038 * <p> 039 * <pre> 040 * {@code 041 * 042 * // CAN BE CALLED AS A HELPER STATIC CONTEXT 043 * MaterialPathAnimator.animate(Element source, Element target, Functions.Func animateCallback); 044 * 045 * // INSTANTIATE THE PUSHPIN COMPONENT 046 * MaterialPathAnimator animator = new MaterialPathAnimator(); 047 * animator.setSourceElement(btnSource1.getElement()); 048 * animator.setTargetElement(panelTarget1.getElement()); 049 * animator.animate(); 050 * // Reverse Animate 051 * animator.reverseAnimate(); 052 * } 053 * </pre> 054 * 055 * @author kevzlou7979 056 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#pathAnimator">Material Path Animator</a> 057 * @see <a href="https://github.com/chinchang/cta.js">CTAJs 0.3.2</a> 058 */ 059//@formatter:on 060public class MaterialPathAnimator implements HasDurationTransition { 061 062 static { 063 if (MaterialAddins.isDebug()) { 064 MaterialDesignBase.injectDebugJs(MaterialPathAnimatorDebugClientBundle.INSTANCE.pathanimatorDebugJs()); 065 } else { 066 MaterialDesignBase.injectJs(MaterialPathAnimatorClientBundle.INSTANCE.pathanimatorJs()); 067 } 068 } 069 070 private Element sourceElement; 071 private Element targetElement; 072 private Functions.Func animateCallback; 073 private Functions.Func reverseCallback; 074 private JsPathAnimatorOptions options = JsPathAnimatorOptions.create(); 075 076 public MaterialPathAnimator() { 077 } 078 079 public MaterialPathAnimator(Element sourceElement, Element targetElement) { 080 this.sourceElement = sourceElement; 081 this.targetElement = targetElement; 082 } 083 084 /** 085 * Animate the path animator 086 */ 087 public void animate() { 088 $("document").ready(() -> JsPathAnimator.cta(sourceElement, targetElement, options, () -> { 089 if (animateCallback != null) { 090 animateCallback.call(); 091 } else { 092 // For default animateCallback when animateCallback is null 093 targetElement.getStyle().setVisibility(Style.Visibility.VISIBLE); 094 targetElement.getStyle().setOpacity(1); 095 } 096 })); 097 } 098 099 /** 100 * Helper method to apply the path animator. 101 * 102 * @param source Source element to apply the Path Animator 103 * @param target Target element to apply the Path Animator 104 */ 105 public static void animate(Element source, final Element target) { 106 animate(source, target, null); 107 } 108 109 /** 110 * Helper method to apply the path animator. 111 * 112 * @param source Source widget to apply the Path Animator 113 * @param target Target widget to apply the Path Animator 114 */ 115 public static void animate(Widget source, final Widget target) { 116 animate(source.getElement(), target.getElement()); 117 } 118 119 /** 120 * Helper method to apply the path animator with callback. 121 * 122 * @param source Source widget to apply the Path Animator 123 * @param target Target widget to apply the Path Animator 124 * @param callback The callback method to be called when the path animator is applied 125 */ 126 public static void animate(Widget source, Widget target, Functions.Func callback) { 127 animate(source.getElement(), target.getElement(), callback); 128 } 129 130 /** 131 * Helper method to apply the path animator with callback. 132 * 133 * @param sourceElement Source widget to apply the Path Animator 134 * @param targetElement Target widget to apply the Path Animator 135 * @param animateCallback The callback method to be called when the path animator is applied 136 */ 137 public static void animate(Element sourceElement, Element targetElement, Functions.Func animateCallback) { 138 MaterialPathAnimator animator = new MaterialPathAnimator(); 139 animator.setSourceElement(sourceElement); 140 animator.setTargetElement(targetElement); 141 animator.setAnimateCallback(animateCallback); 142 animator.animate(); 143 } 144 145 /** 146 * Reverse the Animation 147 */ 148 public void reverseAnimate() { 149 $("document").ready(() -> { 150 if (reverseCallback != null) { 151 reverseCallback.call(); 152 } else { 153 targetElement.getStyle().setVisibility(Style.Visibility.HIDDEN); 154 targetElement.getStyle().setOpacity(0); 155 } 156 JsPathAnimator.cta(targetElement, sourceElement, options); 157 }); 158 } 159 160 /** 161 * Helper method to reverse animate the source element to target element. 162 * 163 * @param sourceElement Source element to apply the Path Animator 164 * @param targetElement Target element to apply the Path Animator 165 */ 166 public static void reverseAnimate(final Element sourceElement, final Element targetElement) { 167 reverseAnimate(sourceElement, targetElement, null); 168 } 169 170 /** 171 * Helper method to reverse animate the source element to target element. 172 * 173 * @param source Source widget to apply the Path Animator 174 * @param target Target widget to apply the Path Animator 175 */ 176 public static void reverseAnimate(final Widget source, final Widget target) { 177 reverseAnimate(source.getElement(), target.getElement()); 178 } 179 180 /** 181 * Helper method to reverse animate the source element to target element with reverse callback. 182 * 183 * @param source Source widget to apply the Path Animator 184 * @param target Target widget to apply the Path Animator 185 * @param reverseCallback The reverse callback method to be called when the path animator is applied 186 */ 187 public static void reverseAnimate(Widget source, Widget target, Functions.Func reverseCallback) { 188 reverseAnimate(source.getElement(), target.getElement(), reverseCallback); 189 } 190 191 /** 192 * Helper method to reverse animate the source element to target element with reverse callback 193 * 194 * @param sourceElement Source element to apply the Path Animator 195 * @param targetElement Target element to apply the Path Animator 196 * @param reverseCallback The reverse callback method to be called when the path animator is applied 197 */ 198 public static void reverseAnimate(Element sourceElement, Element targetElement, Functions.Func reverseCallback) { 199 MaterialPathAnimator animator = new MaterialPathAnimator(); 200 animator.setSourceElement(sourceElement); 201 animator.setTargetElement(targetElement); 202 animator.setReverseCallback(reverseCallback); 203 animator.reverseAnimate(); 204 } 205 206 /** 207 * Get the source element 208 */ 209 public Element getSourceElement() { 210 return sourceElement; 211 } 212 213 /** 214 * Set the source element 215 */ 216 public void setSourceElement(Element sourceElement) { 217 this.sourceElement = sourceElement; 218 } 219 220 /** 221 * Get the target element 222 */ 223 public Element getTargetElement() { 224 return targetElement; 225 } 226 227 /** 228 * Set the target element 229 */ 230 public void setTargetElement(Element targetElement) { 231 this.targetElement = targetElement; 232 } 233 234 /** 235 * Get the callback method when the path animator is applied 236 */ 237 public Functions.Func getAnimateCallback() { 238 return animateCallback; 239 } 240 241 /** 242 * Set the callback method when the path animator is applied 243 */ 244 public void setAnimateCallback(Functions.Func animateCallback) { 245 this.animateCallback = animateCallback; 246 } 247 248 /** 249 * Get the reverse callback method when the path animator is applied 250 */ 251 public Functions.Func getReverseCallback() { 252 return reverseCallback; 253 } 254 255 /** 256 * Set the reverse callback method when the path animator is applied 257 */ 258 public void setReverseCallback(Functions.Func reverseCallback) { 259 this.reverseCallback = reverseCallback; 260 } 261 262 @Override 263 public void setDuration(int duration) { 264 options.duration = duration / 1000.0; 265 } 266 267 @Override 268 public int getDuration() { 269 return (int) (options.duration * 1000); 270 } 271 272 /** 273 * Duration (in milliseconds) of targetElement to become visible, if hidden initially. The library will automatically try to figure this out from the element's computed styles. Default is 0 seconds. 274 */ 275 public void setTargetShowDuration(int targetShowDuration) { 276 options.targetShowDuration = targetShowDuration / 1000.0; 277 } 278 279 public int getTargetShowDuration() { 280 return (int) (options.targetShowDuration * 1000); 281 } 282 283 /** 284 * Extra duration (in milliseconds) of targetElement to provide visual continuity between the animation and the rendering of the targetElement. Default is 1 second 285 */ 286 public void setExtraTransitionDuration(int extraTransitionDuration) { 287 options.extraTransitionDuration = extraTransitionDuration / 1000.0; 288 } 289 290 public int getExtraTransitionDuration() { 291 return (int) (options.extraTransitionDuration * 1000); 292 } 293 294 public boolean isRelativeToWindow() { 295 return options.relativeToWindow; 296 } 297 298 /** 299 * Set to true if your target element is fixed positioned in the window. Default is relative to document (works good with normal elements). 300 */ 301 public void setRelativeToWindow(boolean relativeToWindow) { 302 options.relativeToWindow = relativeToWindow; 303 } 304}