This post will show the FXG code generated from Illustrator of creating a button with vector based artwork from start to finish. For this post we’ll be creating a circular button with a transparent gradient on top. You will see code for an Ellipse, Rectangle, Solid Color Fill, Linear Gradient, transparent gradient, rotation of the gradient, scale of the gradient, the start location of the gradient, applying a mask and fixing the code so our graphic element can be scaled to any size and keep our sharp vector graphics and original aspect ratio.
But first let’s look at an FXG code that is exported from a blank artboard in Illustrator.
<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" viewHeight="792" viewWidth="612" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1"/>
<Private/>
</Graphic>
Notice the viewHeight and viewWidth property in the Graphic tag.
Creating the circle or Ellipse (An Ellipse is a filled circular graphic element.).
<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" viewHeight="792" viewWidth="612" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
<Group ai:seqID="2" d:type="layer" d:userLabel="Layer 3">
<Ellipse width="100" height="100" ai:seqID="3">
<fill>
<SolidColor color="#FF0000"/>
</fill>
</Ellipse>
</Group>
</Group>
<Private/>
</Graphic>
The Ellipse above is 100 x 100. In Illustrator it has been placed at 0×0 position on the artboard. This position is relative to the center of the Ellipse not the upper left hand corner (so from the middle of Ellipse at 0×0 half off it is off the artboard). When you are creating content in Illustrator position it in the upper left corner of the artboard. This location is called the registration point. Note: For this example we are not applying any transformations to the image. It is important to know that transformations work with the registration point. See http://en.wikipedia.org/wiki/Image_registration
To see what this looks like create a new Flex project and paste the code above into a new file called “circleAI.fxg”. Then add it to the Application like so:
<?xml version="1.0" encoding="utf-8"?>
<s:rApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*">
<local:circleAI >
</s:Application>
If that’s all you wanted to do then that will work. But if you set any dimensions on it such as 200×200 then you will notice that becomes skewed.
<?xml version="1.0" encoding="utf-8"?>
<s:rApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*">
<local:circleAI width="200" height="200">
</s:Application>
The reason is that the viewWidth and viewHeight properties are defining the whole size of the artboard in Illustrator not the dimensions of the Ellipsis. We can fix this. Open up the circleAI.fxg file and remove those properties and try it again.
In the design of the button we have a linear gradient that fades into the background. To get a transparent gradient we must first create a mask.
<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
<Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
<mask>
<Group>
<Rect width="100" height="100" ai:seqID="3">
<fill>
<SolidColor color="#FF0000"/>
</fill>
</Rect>
</Group>
</mask>
<Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
<Ellipse width="100" height="100" ai:seqID="5">
<fill>
<SolidColor color="#FF0000"/>
</fill>
</Ellipse>
</Group>
</Group>
</Group>
<Private/>
</Graphic>
This is the first part of creating the gradient. That is creating the mask. In the Group element above we have a property called mask. A mask is a stupid name for what it does. A mask is just a second graphic element that is used to define what areas should be visible in the layer it is part of. In the code above we use a rectangle for this purpose. Because we specified a mask everything in the Group is hidden. The only part of our original content that will be shown is the opaque pixels defined in our mask area. So since we have a fully opaque rectangle sized the same as the Ellipse our Ellipse is fully visible. If the rectangle was sized 50 x 50 then only the upper left quarter of the Ellipse would be visible.
BTW Notice all the additional namespaces in the code above. You can remove these and get a much cleaner looking code. However they don’t affect the result so we will leave them in.
Next we add a gradient to the fill of the rectangle.
<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
<Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
<mask>
<Group>
<Rect width="100" height="100" ai:seqID="3">
<fill>
<LinearGradient x="0" y="50" scaleX="100">
<GradientEntry ratio="0" color="#FFFFFF"/>
<GradientEntry ratio="0.618104" color="#5A5A5A"/>
<GradientEntry ratio="1"/>
</LinearGradient>
</fill>
</Rect>
</Group>
</mask>
<Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
<Ellipse width="100" height="100" ai:seqID="5">
<fill>
<SolidColor color="#FF0000"/>
</fill>
</Ellipse>
</Group>
</Group>
</Group>
<Private/>
</Graphic>
The code above creates a gradient but it does not provide transparency. We can add transparency by setting the alpha property on the Gradient Entry.
<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
<Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
<mask>
<Group>
<Rect width="100" height="100" ai:seqID="3">
<fill>
<LinearGradient x="0" y="50" scaleX="100">
<GradientEntry ratio="0" color="#FFFFFF"/>
<GradientEntry ratio="0.618104" color="#5A5A5A" alpha="0.381896"/>
<GradientEntry ratio="1" alpha="0"/>
</LinearGradient>
</fill>
</Rect>
</Group>
</mask>
<Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
<Ellipse width="100" height="100" ai:seqID="5">
<fill>
<SolidColor color="#FF0000"/>
</fill>
</Ellipse>
</Group>
</Group>
</Group>
<Private/>
</Graphic>
Notice the linear gradient X and Y. This is where it starts. Also notice the scaleX. This is how wide it is. If it is set to 100 percent and the width of the rectangle is 100 then the gradient is also 100.
Next you set the rotation on the gradient.
<?xml version="1.0" encoding="utf-8" ?>
<Graphic version="2.0" ai:appVersion="15.1.0.39" ATE:version="1.0.0" flm:version="1.0.0" d:using="" xmlns="http://ns.adobe.com/fxg/2008" xmlns:ATE="http://ns.adobe.com/ate/2009" xmlns:ai="http://ns.adobe.com/ai/2009" xmlns:d="http://ns.adobe.com/fxg/2008/dt" xmlns:flm="http://ns.adobe.com/flame/2008">
<Library/>
<Group ai:seqID="1" d:layerType="page" d:pageHeight="792" d:pageWidth="612" d:type="layer" d:userLabel="Artboard 1">
<Group maskType="luminosity" luminosityClip="true" ai:seqID="2" ai:spare="1">
<mask>
<Group>
<Rect width="100" height="100" ai:seqID="3">
<fill>
<LinearGradient x="0" y="100" scaleX="100" rotation="-90">
<GradientEntry ratio="0" color="#FFFFFF"/>
<GradientEntry ratio="0.618104" color="#5A5A5A" alpha="0.381896"/>
<GradientEntry ratio="1" alpha="0"/>
</LinearGradient>
</fill>
</Rect>
</Group>
</mask>
<Group ai:seqID="4" d:type="layer" d:userLabel="Layer 3">
<Ellipse width="100" height="100" ai:seqID="5">
<fill>
<SolidColor color="#FF0000"/>
</fill>
</Ellipse>
</Group>
</Group>
</Group>
<Private/>
</Graphic>
When we do this the X and Y are also rotated as well. To maintain the gradient position we set the Y to 100.
<LinearGradient x="0" y="100" scaleX="100" rotation="-90">
<GradientEntry ratio="0" color="#FFFFFF"/>
<GradientEntry ratio="0.618104" color="#5A5A5A" alpha="0.381896"/>
<GradientEntry ratio="1" alpha="0"/>
</LinearGradient>
If we want to use this in Flex as a button then create a new Skin and place the instances inside. This button will scale and maintain it’s vector graphics irregardless of the width and height of the button.
<?xml version="1.0" encoding="utf-8"?>
<s:SparkButtonSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
minWidth="21" minHeight="21"
alpha.disabled="0.5" xmlns:local="*">
<fx:Metadata>
[HostComponent("spark.components.Button")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<s:Rect width="100%" height="100%" alpha="0">
<s:fill>
<s:SolidColor color="0"/>
</s:fill>
</s:Rect>
<local:circleFinal includeIn="up,over,disabled" width="100%" height="100%">
</local:circleFinal>
<local:circleFinalDown includeIn="down" width="100%" height="100%" >
</local:circleFinalDown>
</s:SparkButtonSkin>
<s:HGroup verticalCenter="0" horizontalCenter="0" verticalAlign="middle">
<s:Button skinClass="MyButtonSkin"
width="100" height="100"/>
<s:Button skinClass="MyButtonSkin"
width="150" height="150"/>
</s:HGroup>