Andres is a DZone Zone Leader and has posted 143 posts at DZone. You can read more from them at their website. View Full User Profile

GraphicsBuilder Tutorial IV: Strokes

03.16.2008
| 8674 views |
  • submit to reddit

Part four of the GraphicsBuilder tutorial series. It is now the turn for Strokes, with them you can change the appearance of any shape, outline or group.

Introduction

On the previous parts of this series (I, II, III) you may have seen that shapes have a black border, sometimes white, sometimes thicker an sometimes they don't even have a border. After reading the next section you will be able to change the border's color and shape in various ways other than with a couple of properties.

Strokes

Let's start with strokes. As shown in previous snippets shapes accept a borderColor and borderWidth properties, the following drawing exemplifies this fact, we will be using the same outline so that you can easily recognize the changes from one setting to the next.

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderWidth: 3, borderColor: 'darkGreen' ){
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

Here is a similar version but this time using a basicStroke node, it accepts the same attributes [width,color] but also other properties like join, mitter, dash and dashphase, because after all it is creating a java.awt.BasicStroke under the covers.

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath {
basicStroke( width: 10, color: 'red' )
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

Unfortunately Java2d only includes one java.awt.Stroke implementation (the aforementioned BasicStroke), fortunately Jerry Huxtable decided to release a set of customizable strokes, which are now available in GraphicsBuilder. The first one is my personal favorite, shapeStroke, as it will let you draw any shape repeated along the path of the border, or a combination of shapes for that matter, as show in the next pic

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderColor: 'blue' ) {
shapeStroke( advance: 15 ){
circle( cx: 5, cy: 5, radius: 5 )
star( cx: 5, cy: 5, or: 10, ir: 5 )
}
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

Next in the list is wobbleStroke, it randomly alters its thickness, resulting it a different stroke every time you use it

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderColor: 'orange' ){
wobbleStroke()
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

We shift gears now as the following strokes accept other strokes as part of they configuration, so you can use any of the previously shown strokes in conjunction with the next. ZigzagStroke draws a zig-zag pattern using another stroke, as the following pic shows using a basic stroke as the base one.

 

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderColor: 'black' ){
zigzagStroke {
basicStroke( width: 2 )
}
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

But what if you wanted to mix two strokes together without following a zig-zag pattern? well you just have to switch to compositeStroke are you are done. You may set a pair of properties (stroke1/stroke2) or nest a couple of strokes as shown in the next example

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderColor: 'violet' ){
compositeStroke {
wobbleStroke()
basicStroke( width: 2 )
}
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

Now what if you wanted a different way to combine those strokes, say like Area operations? no problem, compoundStroke can help you achieve that goal, as it it will perform the 4 Area operations available on shapes but with strokes.

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderColor: 'cyan' ){
compoundStroke( operation: 'subtract' ){
basicStroke( width: 18 )
shapeStroke( advance: 20 ){
circle( cx: 5, cy: 5, radius: 5 )
star( cx: 5, cy: 5, or: 10, ir: 5 )
rect( width: 10, height: 10 )
}
}
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

The last stroke is also one of my favorites, text-on-a-path can't get any easier, as the pic shows by itself

antialias on
rect( width: 200, height: 130, fill: 'white', borderColor: no )
xpath( borderColor: 'navyBlue' ){
textStroke( text: 'Drawing text over a path is simple!' )
xmoveTo( x: 50, y: 130 )
xcurveTo( x1: 50, y1: 30, x2: 200, y2: 30, x3: 200, y3: 130 )
xcurveTo( x1: 200, y1: 230, x2: 350, y2: 230, x3: 350, y3: 130 )
transformations { scale(x: 0.5, y: 0.5) }
}

Conclusion

Now you now how to draw shapes, apply paints to them change the color (and paint) of their borders and even change how the border looks. All these features should give you plenty of options to create your drawings, but as you have probably seen in some of the snippets there are other features we need to discuss, as transformations, which will be the topic of the next part on this series. For now enjoy, drawing with Java2D and Groovy.

Published at DZone with permission of its author, Andres Almiray.