Animating line graph with circular points - ios

I have stumbled upon an interesting problem and I am not sure how to solve it. I have a line graph on which data points are marked with circular dots. At the moment I am creating one CAShapeLayer for the line itself and also CAShapeLayer for each dot.
The line is being animated with the strokeEnd animation key path. And it is working. However, the slightly negative effect is that once I open the graph I see all the data points already drawn and then a line is being animated through them.
Ideally I would like to change this behaviour in such a way that at the beginning nothing is shown and as the line gets animated data points are being drawn once the line passes through them.
I was thinking about this problem for some time now and I cannot find an elegant way of solving it. It seems to me that there should be a fairly easy way of achieving what I want. Maybe I should create a compounded path (but then how do I specify that a line needs to be stroked whereas dots need to be filled?).
Could anyone please guide me in the right direction?

There are lots of ways to handle this.
Assuming that the X increments of your graph are constant, and you're using linear timing, you could simply divide the total animation time by the number of data-points, and calculate the times when you need to add points to the graph when the line progresses to that X position. Simply add dot shape layers to the parent view's layer at the appropriate time intervals.
You could also change your drawing method to add new line segments to your graph path one at a time, on a timer, and add dot shapes at the same time. That would give you a step-by-step animation rather than a smooth line drawing.

Related

Truncate a UIBezierPath

I'm trying to create a sort of progress bar class that fills along a UIBezierPath as it progresses. I need to stroke a UIBezierPath with a controlled animation.
I think I could implement this if I could truncate the path to a precise portion of its original length. Is this possible? Is there another method I can use to precisely control the animated stroking of a path?
I've seen this question, but the answer seems to address finding the points at the beginning and end of each element. I'd need to get a list of points at a pixel-by-pixel level for a list of points to be a viable solution.
I believe I'm looking for the strokeEnd property.

Drawing a line with hidden parts in cocos2d for ios

Say you have an array of points and an array of rects, and you want to do the following:
Draw a line that connects all the points in the point array, such that the parts of the line that are contained in at least one of the rects are not visible.
What is the best practice way to accomplish such a task in cocos2d ios?
This may sound like a hack, but if you are drawing the rectangles as well then you can draw them with a higher zOrder with respect to the line and the rectangles would could cover the parts of the lines they contain making those parts invisible.
Hope it helps!

drawing,the intersection point clears

We are devloping a Drawing app. In that when we draw crossed lines ,the intersection point clears the previously drawn pixels where both lines intersects eachother.We are using setneedsdisplayinrect to refresh the drawing data.
How to over come this issue?
tl;dr: You need to store the previous line segments and redraw them when draw in the same rectangle again.
We are using setneedsdisplayinrect to refresh the drawing data
That is a good thing. Can you see any side effects of doing that? If not, try passing the entire rectangle and see what happens. You will see that only the very last segment is drawn.
Now you know that you need to store and possibly redraw previous line segments (or just their image).
Naive approach
The first and simplest solution would be to store all the lines in an array and redraw them. You would notice that this will slow down your app a lot especially when after having drawn for a while. Also, it doesn't go very well with only drawing what you need
Only drawing lines inside the refreshed rectangle
You could speed up the above implementation by filtering all the lines in the array to only redraw those that intersect the refreshed rect. This could for example be done by getting the bounding box for the line segment (using CGPathGetBoundingBox(path)) and checking if it intersects the refreshed rectangle (using CGRectIntersectsRect(refreshRect, boundingBox)).
That would reduce some of the drawing but you would still end up with a very long array of lines and see performance problems after a while.
Rasterize old line segments
One good way of not having to store all previous lines is to draw them into a bitmap (a separate image context (see UIGraphicsBeginImageContextWithOptions(...))) draw that image before drawing the new line segment. However, that would almost double the drawing you would have to do so it should not be done for every frame.
One thing you could do is to store the last 100 line segments (or maybe the last 1000 or whatever your own performance investigation shows, you should investigate these things yourself) and draw the rest into an image. Every time you have a 100 new lines you add them to the image context – by first drawing the image and then drawing the new 100 line – and save that as the new image.
One other thing you could do is to take all the new lines and draw them to the image every time the user lifts their finger. This can work well in combination with the above suggestion.
Depending on the complexity of your app you may need one or more of these suggestions to keep your app responsive (which is very important for a drawing app) but investigate first and don't make your solution overly complex if you don't have to.

Drawing lines in cocos2d

I'm trying to draw lines in Cocos2d using touches.
I had a system where it would just add a small sprite where you touched, but it's working terribly. So I've been trying to find a way to draw actual lines using a method like ccDrawLine, but every tutorial I find seems to leave out something, and I just can't figure it out.
I've found this tutorial, Drawing line on touches moved in COCOS2D but I don't understand a few things about that.
It seems to reference the same variable from two different files, so I don't understand how it's doing that. (The naughtyTouchArray variable)
I can't find a complete guide on drawing lines, so sorry for the codeless question, but I'm getting frustrated.
Thanks.
The answer you've linked in your question provides good solution to your problem. There is no "two different files". Just two different methods of one layer. One method (ccTouchesMoved:withEvent:) handles touches and fill the array of points to be connected to each other one-by-one with lines. From cocos2d documentation, all drawing must be placed in the draw method of the node. So, another (draw) method just draws lines according to the given array. Cocos2d is based on OpenGL and it fully redraws scene every tick, so you cannot just draw new line. You had to draw all of them.
Or any other node can draw your array in it's draw method, so you can simply pass stored array of points from the layer, that detects touches, to this node.

Free hand painting and erasing using UIBezierPath and CoreGraphics

I have been trying so much but have no solution find out yet. I have to implement the painting and erasing on iOS so I successfully implemented the painting logic using UIBezierPath. The problem is that for erasing, I implemented the same logic as for painting by using kCGBlendModeClear but the problem is that I cant redraw on the erased area and this is because in each pass in drawRect i have to stroke both the painting and erasing paths. So is there anyway that we can subtract erasing path from drawing path to get the resultant path and then stroke it. I am very new to Core Graphics and looking forward for your reply and comments. Or any other logic to implement the same. I can't use eraser as background color because my background is textured.
You don't need to stroke the path every time, in fact doing so is a huge performance hit. I guarantee if you try it on an iPad 3 you will be met with a nearly unresponsive screen after a few strokes. You only need to add and stroke the path once. After that, it will be stored as pixel data. So don't keep track of your strokes, just add them, stroke them, and get rid of them. Also look into using a CGLayer (you can draw to that outside the main loop, and only render it to your rect in the main loop so it saves lots of time).
These are the steps that I use, and I am doing the exact same thing (I use a CGPath instead of UIBezierPath, but the idea is the same):
1) In touches began, store the touch point and set the context to either erase or draw, depending on what the user has selected.
2) In touches moved, if the point is a certain arbitrary distance away from the last point, then move to the last point (CGContextMoveToPoint) and draw a line to the new point (CGContextAddLineToPoint) in my CGLayer. Calculate the rectangle that was changed (i.e. contains the two points) and call setNeedsDisplayInRect: with that rectangle.
3) In drawRect render the CGLayer into the current window context ( UIGraphicsGetCurrentContext() ).
On an iPad 3 (the one that everyone has the most trouble with due to its enormous pixel count) this process takes between 0.05 ms and 0.15ms per render (depending on how fast you swipe). There is one caveat though, if you don't take the proper precautions, the entire frame rectangle will be redrawn even if you only use setNeedsDisplayInRect: My hacky way to combat this (thanks to the dev forums) is described in my self answered question here, Otherwise, if your view takes a long time to draw the entire frame (mine took an unacceptable 150 ms) you will get a short stutter under certain conditions while the view buffer gets recreated.
EDIT With the new info from your comments, it seems that the answer to this question will benefit you -> Use a CoreGraphic Stroke as Alpha Mask in iPhone App
Hai here is the code for making painting, erasing, undo, redo, saving as picture. you can check sample code and implement this on your project.
Here

Resources