Search code examples
objective-ccore-graphicsmousemovecgimage

Core Graphics. Best practice for drawing dynamically with mouse move event?


Image example
(source: unt.edu)

I am drawing the image above in Core Graphics using CGContextAddLineToPoint calls. The image itself is not important. However the way it is in the program the shape is based on the position the mouse moves. The problem starts where once an image is rotated, when the user resizes the corners everything needs to be recalculated and rendered while the mouse is being moved. And there is a lot of calculating being done.

Because of all these calculations, not only would dynamically drawing lag, it would 'jump around' as it was being recalculated and repositioned dynamically. I figured out a solution to steady the outside box by drawing 4 simple lines to various calculated points but the problem lies with everything else.

The box will contain various other shapes and lines, and recalculating each of them to be resized when mouse is being moved seems tedious and inefficient. I am wondering what the best practice is to implement whether using CGLayer or CGImageRef for this, and how you would implement them?

The main problem is that I am doing so many calculations while the mouse moves that the image VERY noticeably lags behind and even jumps around while rendering everything dynamically.


Solution

  • In the typical drawing app, you handle two UI events:

    1. In response to the mouse move event, you set the new reference points (origin, rotation etc.) for your shapes and ask the system to repaint the affected area

    2. In response to the repaint event, you draw the shapes using the set reference points.

    This is a robust approach. It does not clog up your CPU by calculating several shape positions at once. However, if calculating the new reference points or repainting the changed shape cannot be done in a fraction of a second (i.e. in 200ms or less), you'll notice a considerable delay. The visible shape will lag behind the mouse position.

    Assuming that your calculation and drawing methods are more or less efficient and cannot be optimized to achieve an execution time of 200ms, you need to resort to a simplified display during shape movement, i.e. once you start to move the shape or change is dimensions, an overlaid outline appears, which quickly follows the mouse movements. It doesn't display the final shapes but rather a simplified outline. The outline is sufficient to position the shape. Once you release the mouse button, the real calculation starts and after a short delay, the final shape is displayed.

    In this scenario, the implementation is somewhat more difficult:

    1. In response to the mouse move event, you set the new reference points for the outline and ask the system to repaint the affected area.

    2. In response to the repaint event, you draw the old shape (stored in a CGImage) plus the outline on top.

    3. In response to the mouse up event, you start a separate thread to recalculate the shape coordinates and draw it into a CGImage.

    4. When the thread has finished, ask the system the repaint the affected area. Now draw the new image (without the outline).