3

I draw a graph with this code:

CAShapeLayer *curentGraph = [CAShapeLayer new];
CGMutablePathRef linePath = CGPathCreateMutable();
curentGraph.lineWidth = 3.0f;
curentGraph.fillColor = [[UIColor clearColor] CGColor];
curentGraph.strokeColor = [colorGraph CGColor];
for (NSValue *value in arrOfPoints) {
    CGPoint pt = [value CGPointValue];
    CGPathAddLineToPoint(linePath, NULL, pt.x,pt.y);
};
curentGraph.path = linePath;CGPathRelease(linePath);
[self.layer addSublayer:curentGraph];

and it looks like this

screenshot of graph

But I have a problem. I need to animate the graph as it appears. Every point should move up from position y = 0 to y = pt.y. Like they do in the graph on this site.

How do I animate my graph like that?

David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
Max Sim
  • 81
  • 1
  • 7

3 Answers3

7

The path property on CAShapeLayer is animatable. This means that you can create one path where every y value is 0.0 and the animate from that path to the real graph. Just make sure that the paths have the same number of points. This should be easy, since you already have the loop.

CGMutablePathRef startPath = CGPathCreateMutable();
for (NSValue *value in arrOfPoints) {
    CGPoint pt = [value CGPointValue];
    CGPathAddLineToPoint(startPath, NULL, pt.x, 0.0);
}

Then you can animate the path by creation a CABasicAnimation for the @"path" key.

CABasicAnimation *pathAppear = [CABasicAnimation animationWithKeyPath:@"path"];
pathAppear.duration = 2.0; // 2 seconds
pathAppear.fromValue = (__bridge id)startPath;
pathAppear.toValue   = (__bridge id)linePath;

[yourShapeLayer addAnimation:pathAppear forKey:@"make the path appear"];
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
7

Here is a CAShapeLayer subclass that'll allow you to animate its path implicitly (without having to declare a CABasicAnimation):

Interface:

@interface CAShapeLayerAnim : CAShapeLayer
@end

Implementation:

@implementation CAShapeLayerAnim

- (id<CAAction>)actionForKey:(NSString *)event {
    if ([event isEqualToString:@"path"]) {
        CABasicAnimation *animation = [CABasicAnimation
            animationWithKeyPath:event];
        animation.duration = [CATransaction animationDuration];
        animation.timingFunction = [CATransaction
            animationTimingFunction];
        return animation;
    }
   return [super actionForKey:event];
}

@end
Cyrille
  • 25,014
  • 12
  • 67
  • 90
  • There is no need to create a custom subclass of CAShapeLayer. CAShapeLayer already does implicit animation of it's path by default. – Duncan C Feb 14 '14 at 16:06
  • 2
    @DuncanC double check the "Discussion" of the path property in the docs: "Unlike most animatable properties, path (as with all CGPathRef animatable properties) does not support implicit animation." – David Rönnqvist Feb 14 '14 at 16:10
  • 1
    That said, maybe there is a reason for that. I'm not sure that I would subclass just to add support for implicit path animation. – David Rönnqvist Feb 14 '14 at 16:13
  • @DavidRönnqvist, oops, my mistake. You're right (as usual) Sorry Cyrille. – Duncan C Feb 14 '14 at 17:29
  • That was my first reaction as well. I saw/remembered it when I went to the documentation to find a quote to use in my comment ;) – David Rönnqvist Feb 14 '14 at 17:54
  • It's not always worth subclassing if you're going to do it on just one instance, but that one is straight out of my toolbox library. – Cyrille Feb 15 '14 at 11:01
2

For animation you need use strokeStart and strokeEnd properties of CAShapeLayer.

See example CAShapeLayer animation in Ole Begemann blog post.

From documentation strokeStart:

The value of this property must be in the range 0.0 to 1.0. The default value of this property is 1.0.

Combined with the strokeEnd property, this property defines the subregion of the path to stroke. The value in this property indicates the relative point along the path at which to begin stroking while the strokeEnd property defines the end point. A value of 0.0 represents the beginning of the path while a value of 1.0 represents the end of the path. Values in between are interpreted linearly along the path length.

Community
  • 1
  • 1
buh
  • 440
  • 2
  • 12