2013-01-06 23 views

回答

1

我在此答案中更新了Uluk的示例,添加了一个ParallelTransition,该节点沿着路径传播时对节点进行缩放。对于路径的前半部分,节点的大小会增加。一旦节点在路径的一半,它就会缩小,直到在圆的开始处达到它的原始大小。

当我高速运行(您需要运行它来看这个)时,动画确实有一种奇怪的向前运动模糊效果,我无法真正解释。

import javafx.animation.*; 
import javafx.application.Application; 
import javafx.scene.*; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.*; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class ArcToScalingDemo extends Application { 

    private PathTransition pathTransitionEllipse; 
    private ParallelTransition scalingCirclePathTransition; 

    private void init(Stage primaryStage) { 
    Group root = new Group(); 
    primaryStage.setResizable(false); 
    primaryStage.setScene(new Scene(root, 600, 460)); 

    // Ellipse path example 
    Rectangle rect = new Rectangle(0, 0, 40, 40); 
    rect.setArcHeight(10); 
    rect.setArcWidth(10); 
    rect.setFill(Color.ORANGE); 
    root.getChildren().add(rect); 

    Path path = createEllipsePath(200, 200, 50, 100, 45); 
    root.getChildren().add(path); 

    pathTransitionEllipse = PathTransitionBuilder.create() 
     .duration(Duration.seconds(4)) 
     .path(path) 
     .node(rect) 
     .orientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT) 
     .cycleCount(Timeline.INDEFINITE) 
     .autoReverse(false) 
     .build(); 

    // Circle path example 
    Rectangle rect2 = new Rectangle(0, 0, 20, 20); 
    rect2.setArcHeight(10); 
    rect2.setArcWidth(10); 
    rect2.setFill(Color.GREEN); 
    root.getChildren().add(rect2); 

    Path path2 = createEllipsePath(400, 200, 150, 150, 0); 
    root.getChildren().add(path2); 

    PathTransition pathTransitionCircle = PathTransitionBuilder.create() 
     .duration(Duration.seconds(2)) 
     .path(path2) 
     .node(rect2) 
     .orientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT) 
     .cycleCount(Timeline.INDEFINITE) 
     .autoReverse(false) 
     .build(); 

    ScaleTransition scaleTransition = ScaleTransitionBuilder.create() 
     .duration(pathTransitionCircle.getDuration().divide(2)) 
     .fromX(1) 
     .fromY(1) 
     .toX(3) 
     .toY(3) 
     .cycleCount(Timeline.INDEFINITE) 
     .autoReverse(true) 
     .build(); 

    scalingCirclePathTransition = ParallelTransitionBuilder.create() 
     .children(pathTransitionCircle, scaleTransition) 
     .node(rect2) 
     .build(); 
    } 

    private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate) { 
    ArcTo arcTo = new ArcTo(); 
    arcTo.setX(centerX - radiusX + 1); // to simulate a full 360 degree celcius circle. 
    arcTo.setY(centerY - radiusY); 
    arcTo.setSweepFlag(false); 
    arcTo.setLargeArcFlag(true); 
    arcTo.setRadiusX(radiusX); 
    arcTo.setRadiusY(radiusY); 
    arcTo.setXAxisRotation(rotate); 

    Path path = PathBuilder.create() 
     .elements(
      new MoveTo(centerX - radiusX, centerY - radiusY), 
      arcTo, 
      new ClosePath()) // close 1 px gap. 
     .build(); 
    path.setStroke(Color.DODGERBLUE); 
    path.getStrokeDashArray().setAll(5d, 5d); 
    return path; 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
    init(primaryStage); 
    primaryStage.show(); 
    pathTransitionEllipse.play(); 
    scalingCirclePathTransition.play(); 
    } 

    public static void main(String[] args) { 
    launch(args); 
    } 
} 

节点对路径中的位置不一定是相同的在动画中已过去,因为节点可以不以恒定速度行进的时间的相对持续时间。此外,在此示例中,节点的相对比例可能与这些值中的任何一个不完全匹配。您可以为ScaleTransition定义一个自定义的Interpolator,让您根据当前路径位置或动画持续时间将比例映射到一个值,但这并不是真的必要,因为在视觉上,插值看起来没有问题。

下面是另一个带自定义内插器的示例,它将沿着路径按比例调整节点的比例,以使节点在路径的一半处达到最大比例。它依赖于对称的原始路径转换中的插值函数。该样本尚未经过完全正确的测试。除非绝对必要,否则我会推荐先前没有定制插补器的示例。

public class ArcToInterpolation Demo extends Application { 

    class HalfInterpolator extends Interpolator { 
    final Interpolator source; 

    HalfInterpolator(Interpolator source) { 
     this.source = source; 
    } 

    @Override protected double curve(double t) { 
     return t <= 0.5 
      ? source.interpolate(0.0, 1.0, t) * 2 
      : source.interpolate(0.0, 1.0, 1 - t) * 2; 
    } 
    } 

    private ParallelTransition scalingCirclePathTransition; 

    private void init(Stage primaryStage) { 
    Group root = new Group(); 
    primaryStage.setResizable(false); 
    primaryStage.setScene(new Scene(root, 600, 460)); 

    // Circle path example 
    Rectangle rect2 = new Rectangle(0, 0, 20, 20); 
    rect2.setArcHeight(10); 
    rect2.setArcWidth(10); 
    rect2.setFill(Color.GREEN); 
    root.getChildren().add(rect2); 

    Path path2 = createEllipsePath(400, 200, 150, 150, 0); 
    root.getChildren().add(path2); 

    PathTransition pathTransitionCircle = PathTransitionBuilder.create() 
     .duration(Duration.seconds(10)) 
     .interpolator(Interpolator.EASE_BOTH) 
     .path(path2) 
     .node(rect2) 
     .orientation(PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT) 
     .cycleCount(Timeline.INDEFINITE) 
     .autoReverse(false) 
     .build(); 

    ScaleTransition scaleTransition = ScaleTransitionBuilder.create() 
     .duration(pathTransitionCircle.getDuration()) 
     .interpolator(new HalfInterpolator(pathTransitionCircle.getInterpolator())) 
     .fromX(1) 
     .fromY(1) 
     .toX(4) 
     .toY(4) 
     .cycleCount(Timeline.INDEFINITE) 
     .autoReverse(false) 
     .build(); 

    scalingCirclePathTransition = ParallelTransitionBuilder.create() 
     .children(pathTransitionCircle, scaleTransition) 
     .node(rect2) 
     .build(); 
    } 

    private Path createEllipsePath(double centerX, double centerY, double radiusX, double radiusY, double rotate) { 
    ... as in previous sample 
    } 

    @Override 
    public void start(Stage primaryStage) throws Exception { 
    init(primaryStage); 
    primaryStage.show(); 
    scalingCirclePathTransition.play(); 
    } 

    public static void main(String[] args) { 
    launch(args); 
    } 
} 
+0

感谢您回答我所有的JavaFX问题。如果你可以提供插入代码,也许我以后需要它。到目前为止,它看起来非常好。非常感谢。 – chrise

+1

已更新的答案提供一些示例插值代码。 – jewelsea

1

看起来你应该使用

公众最终ReadOnlyObjectProperty currentTimeProperty

PathTransition类

。您可以在此属性的值更改上添加侦听器,并在出现新值时,调用double d = newDuration.toMillis(),并确定路径的哪一部分已经消失,并在动画的全部时间内将d除。

+0

但我不能添加一个侦听器到PathTransition。所以我必须自己实现一个属性更改的监听器,而不是更简单的方法? – chrise

+1

我认为,最简单的方法将是这样的:。 pathTransition.currentTimeProperty()的addListener(新的ChangeListener (){ @覆盖 公共无效改变(ObservableValue <延长时间?> OV,持续时间T,时间段T1 ){ double coef = Math.abs(Math.sin(t1.toSeconds()))+ 1; targetNode.getTransforms()。clear(); targetNode.getTransforms()。add(new Scale(coef,coef )); } }); –

+0

感谢您的解决方案(double-upvote)。我认为ParallelTransition更适合FX方式,尽管您的答案完全符合我的问题。 – chrise