SVGKit 2013 – Recipes (part 2)

(see also the first set of SVGKit recipes)

Change the color of a SVG element like a Path or Circle after the user click on it

CALayer* layerUserClickedOn = ...

if( [layerUserClickedOn isKindOfClass:[CAShapeLayer class]] ) // should ALWAYS be true, but just in case you write your code wrong...
{
   CAShapeLayer* shapeLayer = (CAShapeLayer*) layerUserClickedOn;
   shapeLayer.fillColor = [UIColor redColor].CGColor;
}

Find the CALayer that was generated from a particular SVGElement

NB: Apple/ObjectiveC uses “id” as a keyword, so we had to rename the SVG name “id” to “identifier”.

If your SVG file is legal, and has a unique “id” attribute for every SVGElement, then you can find the CALayer directly from the SVGElement, using the “id” attribute. If your SVG file has no “id” attributes, or the SVGElement you’re searching has no “id” element, then you’ll have to do more work – or fix the SVG file (edit it, add an “id” attribute to the SVGElement that matters, save it … then use this recipe)!

SVGKImage* svgImage = ...
SVGElement* element = ... // see previous SVGKit recipes
CALayer* layer = [svgImage layerWithIdentifier:element.identifier];
... // do something with it...

Clone part of the image, and move it around / change it

First of all, find the part of the SVG you want to clone, e.g. using “Search an SVG file for particular tags / nodes / elements” from the first set of SVGKit recipes.

That gives you an (SVGElement*). Use the previous recipe to get the CALayer. Finally, clone it and use it:

#import "CALayer+RecursiveClone.h" // requires SVGKit version 1.1.0 or later

...
-(void) someMethod
{
   SVGKImage* svgImage = ...
   SVGElement* elementToClone = ... // see previous SVGKit recipes
   CALayer* layerToClone = ... // see recipe above

   CALayer* newLayer = [layerToClone cloneRecursively];
   newLayer.frame = layerToClone.bounds; // reset it to be positioned at (0,0)
   
   // if you want the clone to start in same position as original
   // add this code
   if( calculatePositionOfOriginalLayer )
   {
      CGFloat xOffsetOriginal = 0.0f;
      CGFloat yOffsetOriginal = 0.0f;
      CALayer* parentLayer = layerToClone;
      while( nil != (parentLayer = parentLayer.superlayer) )
      {
         xOffsetOriginal += parentLayer.frame.origin.x;
         yOffsetOriginal += parentLayer.frame.origin.y;
      }
      CGPoint positionOfOriginalLayer = CGPointApplyTransform( layerToClone.position, CGAffineMakeTranslation( xOffsetOriginal, yOffsetOriginal ) );
   }
}

Edit the polygons / lines / shapes after loading

Every “shape” is stored as some form of Apple CGPath object.

CALayer* layerInSVG = ... // use a previous recipe to get the layer from the SVG element
CAShapeLayer* shapeLayer = (CAShapeLayer*) layerInSVG; // if you chose wrong, this will error at runtime
CGPath pathToEdit = shapeLayer.path;

... // edit the path, and create a replacement path

shapeLayer.path = myEditedPath;

Apple doesn’t provide an API to directly edit CGPath objects. They have a C API that let’s you create a callback function that turns the CGPath into a list of draw-calls, that you can then work with. But it takes quite a bit of code to read this, and then convert it back into a CGPath that Apple can draw.

So far, no-one has open-sourced their code for this (I’ve got a private version I wrote for a previous project, but it’s thousands of lines of code). Either petition Apple to add the missing APIs, or find someone to write it for you / license it to you, or write it yourself.

4 Replies to “SVGKit 2013 – Recipes (part 2)”

  1. Hi, I really like SVGKIT!
    I have just one question About the first recipe. I want to detect which Layer has been “Clicked on” by the user. How can I Do that?
    Thank you in advance.

  2. Lots of ways. Look at the Demo project included, it does this in debug mode. You can copy that source code to your app

Comments are closed.