### Summary

Throughout this article, we've covered all sorts of Auto Shapes and quite a few techniques used in their creation. Hopefully it was enough to help you get started on making your own. The following outlines key points covered.

• Fireworks Auto Shapes are defined completely by JavaScript from files in your Configuration\Auto Shapes or Configuration\Auto Shape Tools folders in your Fireworks install directory.

• Previews for Auto Shapes are GIF or PNG and reside with your Auto Shape JavaScript file. For shapes in the Shapes panel, previews are 60x60 while Auto Shape tool previews are 16x16.

• Auto Shapes consist of one or more elements that can be either a path, text or a group.

• Path elements consist of one of more contours each of which consist or one or more nodes. Nodes in turn are made up of a main point and two control points, a predecessor and a successor.

• The smartShape object provides you with variables and functions to help you create and manage your shapes.

• Creating Auto Shapes should always revolve around the position of the mouse found in smartShape.currentMousePos.

• Events that call your Auto Shape script are specified in smartShape.operation.

• Movement for control points and nodes can be handled through the various register move functions.

• A register move parameters object for register move functions is created from smartShape.GetDefaultMoveParms() and lets you specify how the various register move functions move points.

• Colors and effects can be added to elements within an Auto Shape by altering those elements' pathAttributes and effectList objects.

• Characters in text elements can only be assigned or changed when reassigning that elements entire textRuns property.

• Moving text in an Auto Shape requires adjusting the text's rawLeft and rawTop properties.

• Bitmap visuals can be added to Auto Shapes through patterns on a path. You just need to be sure those patterns are installed for Fireworks.

• Auto Shape tools are much like Auto Shapes from the Shapes panel except they receive more creation events and can use RegisterInsertBBoxMove for point movement during shape creation.

• Auto Shapes can be shapes, tools as well as utilities that help you perform other actions not associated with that shape directly.

• Creating circular curves for paths requires the use of fw.ellipseBCPConst.

• Study the Extending Fireworks documentation and watch out for Auto Shape bugs. Do this and you should be well off in your efforts towards creating your own custom Auto Shapes.

#### Completed Shapes

Shape | Versions | |

Curve | (1, 2) | |

Hollow Box | (1, 2, 3, 4, 5, 6, 7) | |

Play Button Triangle | (1, 2, 3, 4) | |

Register Moves | (1, 2) | |

Cross | ||

Asterisk | (1, 2, 3) | |

Pentagon | (1, 2, 3, 4) | |

Text Wave | ||

Aqua Button | ||

Simple Arrow | ||

Element Matcher | ||

Chained Selection | (1, 2) | |

Circle Segment | ||

Rounded Polygon |

#### Useful Variables and Functions

var mouse = smartShape.currentMousePos; // short variable for mouse position var clicked = smartShape.mouseDownPos; // short variable for mouse down position var cps = smartShape.elem.controlPoints; // short variable for control points array var elems = smartShape.elem.elements; // short variable for smartShape elements array var data = smartShape.elem.customData; // short variable for smartShape customData object var rad90 = Math.PI/2; // 90 degrees in radians var rad180 = Math.PI; // 180 degrees in radians var rad270 = 3*Math.PI/2; // 270 degrees in radians var rad360 = 2*Math.PI; // 360 degrees in radians var toDegrees = 180/Math.PI; // multiply this by a radians angle to get it in degrees var toRadians = Math.PI/180; // multiply this by a degrees angle to get it in radians /** * The following are functions for all smartShape Events */ var operation = new Object(); operation.InsertSmartShapeAt = function(){} operation.BeginDragInsert = function(){} operation.DragInsert = function(){} operation.EndDragInsert = function(){} operation.BeginDragControlPoint = function(){} operation.DragControlPoint = function(){} operation.EndDragControlPoint = function(){} operation.SmartShapeEdited = function(){} // used to invoke the above events at the bottom of your script if (operation[smartShape.operation]) operation[smartShape.operation](); /** * SetBezierNodePosition sets the position of the passed node to the * position of the point pt parameter. All node control points are * set to this point as well * Requires: SetBezierNodePosition */ SetNodePosition = function(node, pt){ SetBezierNodePosition(node, pt,pt,pt); // set point position for all nodes to pt } /** * SetBezierNodePosition sets the position of the passed node to the * position of the points ptp (node predecessor), pt (main point), and * pts (node successor) */ SetBezierNodePosition = function(node, ptp, pt, pts){ node.predX = ptp.x; node.predY = ptp.y; // Predecessor point node.x = pt.x; node.y = pt.y; // Main points node.succX = pts.x; node.succY = pts.y; // Successor points } /** * MatchBezierNodePosition assigns to a node the position as specified * by another node passed in as match. */ MatchBezierNodePosition = function(node, match){ node.predX = match.predX; node.predY = match.predY; // Predecessor points node.x = match.x; node.y = match.y; // Main points node.succX = match.succX; node.succY = match.succY; // Successor points } /** * SetControlPoint sets properties for the index'th control point of * smartShape.controlPoints, creating it in the array if it does not * yet exist. Only index and pt (point representing location) are * required parameters. */ SetControlPoint = function(index, pt, /* optional: */ name, toolTip, type, toolTipTracksDrag, visible, hiliteDragOverObject){ var cps = smartShape.controlPoints; // short variable for control points array if (index >= cps.length) cps.length = index+1; // create new control point by altering cps length if doesn't already exist cps[index].x = pt.x; cps[index].y = pt.y; // set position of control point if (type != undefined) cps[index].type = type; // String representing type: "default", "defaultInverted" or "crossHair" if (name != undefined) cps[index].name = name; // String representing name if (toolTip != undefined) cps[index].toolTip = toolTip; // String representing tool tip if (toolTipTracksDrag != undefined) cps[index].toolTipTracksDrag = toolTipTracksDrag; // true/false for whether tool tip follows mouse in drag if (visible != undefined) cps[index].visible = visible; // true/false hide or show tool tip (it remains active while true) if (hiliteDragOverObject != undefined) cps[index].hiliteDragOverObject = hiliteDragOverObject; // true/false when true, hilites objects when dragged over them } /** * CPoint creates a generic point object from a control point object */ CPoint = function(index){ return {x: cps[index].x, y:cps[index].y}; // copy x and y properties in returned object } /** * NPoint creates a generic point object from a ContourNode object */ NPoint = function(node){ return {x: node.x, y:node.y}; // copy x and y properties in returned object } /** * AddPoints adds two points pt1 and pt2 and returns the resulting point */ AddPoints = function(pt1, pt2){ return {x:pt1.x + pt2.x, y:pt1.y + pt2.y}; // add x and y properties in returned object } /** * SubtractPoints subtracts two points pt1 and pt2 and returns the resulting point */ SubtractPoints = function(pt1, pt2){ return {x:pt1.x - pt2.x, y:pt1.y - pt2.y}; // subtract x and y properties in returned object } /** * PointsEqual compares points pt1 and pt2 and returns true if they equal, false if not */ PointsEqual = function(pt1, pt2){ return (pt1.x == pt2.x && pt1.y == pt2.y); // return comparison of both x and y properties (true if both equal) } /** * DistanceBetween uses the pythagorean theorem to determine the true distance * between two points pt1 and pt2. */ DistanceBetween = function(pt1, pt2){ var dx = pt2.x - pt1.x, dy = pt2.y - pt1.y; // find differences of point locations return Math.sqrt(dx*dx + dy*dy); // pythagorean theorem } /** * PointBetween returns a point location between points pt1 and pt2 */ PointBetween = function(pt1, pt2){ return {x:(pt1.x + pt2.x)/2, y:(pt1.y + pt2.y)/2}; // return average point between 2 points } /** * AngleBetween returns the angle between two points pt1 and pt2 in radians */ AngleBetween = function(pt1, pt2){ return Math.atan2(pt2.y - pt1.y, pt2.x - pt1.x); // use arc tangent 2 to get angle } /** * PointFromVector returns a point extending outward from the point origin at the * angle angle (radians) with a distance of power */ PointFromVector = function(origin, angle, power){ return { x: origin.x + Math.cos(angle)*power, y: origin.y + Math.sin(angle)*power }; // use sine and cosine to determine new point locations } /** * RotatePointAroundPoint returns the location (point) of a point pt which has * been rotated around the point origin at an angle of angle (radians) */ RotatePointAroundPoint = function(pt, origin, angle){ var ca = Math.cos(angle), sa = Math.sin(angle); // get sine and cosine values for the angle var dx = pt.x - origin.x, dy = pt.y - origin.y; // get the differences in x and y locations return {x:origin.x + dx*ca - dy*sa, y:origin.y + dx*sa + dy*ca}; // return rotated point }

#### Find More Auto Shapes

There aren't many Auto Shapes out there yet. Hopefully as more people read this, more will pop up after peopleas it becomes more clear just how to make them. Those I am aware of that are available for download and/or purchase can be found at the following locations.

senocular.com

Phireworks

Community MX

Macromedia Fireworks Exchange

Thank you for reading. Hopefully I've provided some insight, and hopefully I'll be seeing some new custom Auto Shapes appearing out there on the web or in the exchange. If you create and Auto Shape and want me to link to it, or maybe just have some questions/concerns/corrections for this article, drop me a line at senocular at hotmail dot com.