Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.animation; 027 028import javafx.beans.property.DoubleProperty; 029import javafx.beans.property.ObjectProperty; 030import javafx.beans.property.ObjectPropertyBase; 031import javafx.beans.property.SimpleDoubleProperty; 032import javafx.beans.property.SimpleObjectProperty; 033import javafx.geometry.Point3D; 034import javafx.scene.Node; 035import javafx.util.Duration; 036 037/** 038 * This {@code Transition} creates a rotation animation that spans its 039 * {@code duration}. This is done by updating the {@code rotate} variable of the 040 * {@code node} at regular interval. The angle value is specified in degrees. 041 * <p> 042 * It starts from the {@code fromAngle} if provided else uses the {@code node}'s 043 * {@code rotate} value. 044 * <p> 045 * It stops at the {@code toAngle} value if provided else it will use start 046 * value plus {@code byAngle}. 047 * <p> 048 * The {@code toAngle} takes precedence if both {@code toAngle} and 049 * {@code byAngle} are specified. 050 * 051 * <p> 052 * Code Segment Example: 053 * </p> 054 * 055 * <pre> 056 * <code> 057 * import javafx.scene.shape.*; 058 * import javafx.animation.transition.*; 059 * 060 * ... 061 * 062 * Rectangle rect = new Rectangle (100, 40, 100, 100); 063 * rect.setArcHeight(50); 064 * rect.setArcWidth(50); 065 * rect.setFill(Color.VIOLET); 066 * 067 * RotateTransition rt = new RotateTransition(Duration.millis(3000), rect); 068 * rt.setByAngle(180); 069 * rt.setCycleCount(4); 070 * rt.setAutoReverse(true); 071 * 072 * rt.play(); 073 * 074 * ... 075 * 076 * </code> 077 * </pre> 078 * 079 * @see Transition 080 * @see Animation 081 * 082 */ 083public final class RotateTransition extends Transition { 084 085 private static final double EPSILON = 1e-12; 086 087 private double start; 088 private double delta; 089 090 /** 091 * The target node of this {@code RotateTransition}. 092 * <p> 093 * It is not possible to change the target {@code node} of a running 094 * {@code RotateTransition}. If the value of {@code node} is changed for a 095 * running {@code RotateTransition}, the animation has to be stopped and 096 * started again to pick up the new value. 097 */ 098 private ObjectProperty<Node> node; 099 private static final Node DEFAULT_NODE = null; 100 101 public final void setNode(Node value) { 102 if ((node != null) || (value != null /* DEFAULT_NODE */)) { 103 nodeProperty().set(value); 104 } 105 } 106 107 public final Node getNode() { 108 return (node == null)? DEFAULT_NODE : node.get(); 109 } 110 111 public final ObjectProperty<Node> nodeProperty() { 112 if (node == null) { 113 node = new SimpleObjectProperty<Node>(this, "node", DEFAULT_NODE); 114 } 115 return node; 116 } 117 118 private Node cachedNode; 119 120 /** 121 * The duration of this {@code RotateTransition}. 122 * <p> 123 * It is not possible to change the {@code duration} of a running 124 * {@code RotateTransition}. If the value of {@code duration} is changed for 125 * a running {@code RotateTransition}, the animation has to be stopped and 126 * started again to pick up the new value. 127 * <p> 128 * Note: While the unit of {@code duration} is a millisecond, the 129 * granularity depends on the underlying operating system and will in 130 * general be larger. For example animations on desktop systems usually run 131 * with a maximum of 60fps which gives a granularity of ~17 ms. 132 * 133 * Setting duration to value lower than {@link Duration#ZERO} will result 134 * in {@link IllegalArgumentException}. 135 * 136 * @defaultValue 400ms 137 */ 138 private ObjectProperty<Duration> duration; 139 private static final Duration DEFAULT_DURATION = Duration.millis(400); 140 141 public final void setDuration(Duration value) { 142 if ((duration != null) || (!DEFAULT_DURATION.equals(value))) { 143 durationProperty().set(value); 144 } 145 } 146 147 public final Duration getDuration() { 148 return (duration == null)? DEFAULT_DURATION : duration.get(); 149 } 150 151 public final ObjectProperty<Duration> durationProperty() { 152 if (duration == null) { 153 duration = new ObjectPropertyBase<Duration>(DEFAULT_DURATION) { 154 155 @Override 156 public void invalidated() { 157 try { 158 setCycleDuration(getDuration()); 159 } catch (IllegalArgumentException e) { 160 if (isBound()) { 161 unbind(); 162 } 163 set(getCycleDuration()); 164 throw e; 165 } 166 } 167 168 @Override 169 public Object getBean() { 170 return RotateTransition.this; 171 } 172 173 @Override 174 public String getName() { 175 return "duration"; 176 } 177 }; 178 } 179 return duration; 180 } 181 182 /** 183 * Specifies the axis of rotation for this {@code RotateTransition}. Use 184 * {@code node.rotationAxis} for axis of rotation if this {@code axis} is 185 * null. 186 * <p> 187 * It is not possible to change the {@code axis} of a running 188 * {@code RotateTransition}. If the value of {@code axis} is changed for a 189 * running {@code RotateTransition}, the animation has to be stopped and 190 * started again to pick up the new value. 191 * 192 * @defaultValue null 193 */ 194 private ObjectProperty<Point3D> axis; 195 private static final Point3D DEFAULT_AXIS = null; 196 197 public final void setAxis(Point3D value) { 198 if ((axis != null) || (value != null /* DEFAULT_AXIS */)) { 199 axisProperty().set(value); 200 } 201 } 202 203 public final Point3D getAxis() { 204 return (axis == null)? DEFAULT_AXIS : axis.get(); 205 } 206 207 public final ObjectProperty<Point3D> axisProperty() { 208 if (axis == null) { 209 axis = new SimpleObjectProperty<Point3D>(this, "axis", DEFAULT_AXIS); 210 } 211 return axis; 212 } 213 214 /** 215 * Specifies the start angle value for this {@code RotateTransition}. 216 * <p> 217 * It is not possible to change {@code fromAngle} of a running 218 * {@code RotateTransition}. If the value of {@code fromAngle} is changed 219 * for a running {@code RotateTransition}, the animation has to be stopped 220 * and started again to pick up the new value. 221 * 222 * @defaultValue {@code Double.NaN} 223 */ 224 private DoubleProperty fromAngle; 225 private static final double DEFAULT_FROM_ANGLE = Double.NaN; 226 227 public final void setFromAngle(double value) { 228 if ((fromAngle != null) || (!Double.isNaN(value))) { 229 fromAngleProperty().set(value); 230 } 231 } 232 233 public final double getFromAngle() { 234 return (fromAngle == null)? DEFAULT_FROM_ANGLE : fromAngle.get(); 235 } 236 237 public final DoubleProperty fromAngleProperty() { 238 if (fromAngle == null) { 239 fromAngle = new SimpleDoubleProperty(this, "fromAngle", DEFAULT_FROM_ANGLE); 240 } 241 return fromAngle; 242 } 243 244 /** 245 * Specifies the stop angle value for this {@code RotateTransition}. 246 * <p> 247 * It is not possible to change {@code toAngle} of a running 248 * {@code RotateTransition}. If the value of {@code toAngle} is changed for 249 * a running {@code RotateTransition}, the animation has to be stopped and 250 * started again to pick up the new value. 251 * 252 * @defaultValue {@code Double.NaN} 253 */ 254 private DoubleProperty toAngle; 255 private static final double DEFAULT_TO_ANGLE = Double.NaN; 256 257 public final void setToAngle(double value) { 258 if ((toAngle != null) || (!Double.isNaN(value))) { 259 toAngleProperty().set(value); 260 } 261 } 262 263 public final double getToAngle() { 264 return (toAngle == null)? DEFAULT_TO_ANGLE : toAngle.get(); 265 } 266 267 public final DoubleProperty toAngleProperty() { 268 if (toAngle == null) { 269 toAngle = new SimpleDoubleProperty(this, "toAngle", DEFAULT_TO_ANGLE); 270 } 271 return toAngle; 272 } 273 274 /** 275 * Specifies the incremented stop angle value, from the start, of this 276 * {@code RotateTransition}. 277 * <p> 278 * It is not possible to change {@code byAngle} of a running 279 * {@code RotateTransition}. If the value of {@code byAngle} is changed for 280 * a running {@code RotateTransition}, the animation has to be stopped and 281 * started again to pick up the new value. 282 */ 283 private DoubleProperty byAngle; 284 private static final double DEFAULT_BY_ANGLE = 0.0; 285 286 public final void setByAngle(double value) { 287 if ((byAngle != null) || (Math.abs(value - DEFAULT_BY_ANGLE) > EPSILON)) { 288 byAngleProperty().set(value); 289 } 290 } 291 292 public final double getByAngle() { 293 return (byAngle == null)? DEFAULT_BY_ANGLE : byAngle.get(); 294 } 295 296 public final DoubleProperty byAngleProperty() { 297 if (byAngle == null) { 298 byAngle = new SimpleDoubleProperty(this, "byAngle", DEFAULT_BY_ANGLE); 299 } 300 return byAngle; 301 } 302 303 /** 304 * The constructor of {@code RotateTransition} 305 * 306 * @param duration 307 * The duration of the {@code RotateTransition} 308 * @param node 309 * The {@code node} which will be rotated 310 */ 311 public RotateTransition(Duration duration, Node node) { 312 setDuration(duration); 313 setNode(node); 314 setCycleDuration(duration); 315 } 316 317 /** 318 * The constructor of {@code RotateTransition} 319 * 320 * @param duration 321 * The duration of the {@code RotateTransition} 322 */ 323 public RotateTransition(Duration duration) { 324 this(duration, null); 325 } 326 327 /** 328 * The constructor of {@code RotateTransition} 329 * 330 */ 331 public RotateTransition() { 332 this(DEFAULT_DURATION, null); 333 } 334 335 /** 336 * {@inheritDoc} 337 */ 338 @Override 339 protected void interpolate(double frac) { 340 cachedNode.setRotate(start + frac * delta); 341 } 342 343 private Node getTargetNode() { 344 final Node node = getNode(); 345 return (node != null) ? node : getParentTargetNode(); 346 } 347 348 @Override 349 boolean impl_startable(boolean forceSync) { 350 return super.impl_startable(forceSync) 351 && ((getTargetNode() != null) || (!forceSync && (cachedNode != null))); 352 } 353 354 @Override 355 void impl_sync(boolean forceSync) { 356 super.impl_sync(forceSync); 357 if (forceSync || (cachedNode == null)) { 358 cachedNode = getTargetNode(); 359 final double _fromAngle = getFromAngle(); 360 final double _toAngle = getToAngle(); 361 start = (!Double.isNaN(_fromAngle)) ? _fromAngle : cachedNode 362 .getRotate(); 363 delta = (!Double.isNaN(_toAngle)) ? _toAngle - start : getByAngle(); 364 final Point3D _axis = getAxis(); 365 if (_axis != null) { 366 node.get().setRotationAxis(_axis); 367 } 368 } 369 } 370 371}