| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | 
| 2 |  |  |  |  |  |  | ############################################################################### | 
| 3 |  |  |  |  |  |  | # | 
| 4 |  |  |  |  |  |  | # Shape - A class for writing Excel shapes. | 
| 5 |  |  |  |  |  |  | # | 
| 6 |  |  |  |  |  |  | # Used in conjunction with Excel::Writer::XLSX. | 
| 7 |  |  |  |  |  |  | # | 
| 8 |  |  |  |  |  |  | # Copyright 2000-2021, John McNamara, jmcnamara@cpan.org | 
| 9 |  |  |  |  |  |  | # | 
| 10 |  |  |  |  |  |  | # Documentation after __END__ | 
| 11 |  |  |  |  |  |  | # | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | # perltidy with the following options: -mbl=2 -pt=0 -nola | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | use 5.008002; | 
| 16 | 1124 |  |  | 1124 |  | 16828 | use strict; | 
|  | 1124 |  |  |  |  | 3085 |  | 
| 17 | 1124 |  |  | 1124 |  | 5604 | use warnings; | 
|  | 1124 |  |  |  |  | 2669 |  | 
|  | 1124 |  |  |  |  | 18530 |  | 
| 18 | 1124 |  |  | 1124 |  | 5783 | use Carp; | 
|  | 1124 |  |  |  |  | 2889 |  | 
|  | 1124 |  |  |  |  | 21056 |  | 
| 19 | 1124 |  |  | 1124 |  | 5366 | use Exporter; | 
|  | 1124 |  |  |  |  | 3551 |  | 
|  | 1124 |  |  |  |  | 54319 |  | 
| 20 | 1124 |  |  | 1124 |  | 6838 |  | 
|  | 1124 |  |  |  |  | 1761 |  | 
|  | 1124 |  |  |  |  | 535555 |  | 
| 21 |  |  |  |  |  |  | our @ISA     = qw(Exporter); | 
| 22 |  |  |  |  |  |  | our $VERSION = '1.09'; | 
| 23 |  |  |  |  |  |  | our $AUTOLOAD; | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | ############################################################################### | 
| 26 |  |  |  |  |  |  | # | 
| 27 |  |  |  |  |  |  | # new() | 
| 28 |  |  |  |  |  |  | # | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | my $class      = shift; | 
| 31 |  |  |  |  |  |  | my $fh         = shift; | 
| 32 | 28 |  |  | 28 | 0 | 911 | my $self       = Excel::Writer::XLSX::Package::XMLwriter->new( $fh ); | 
| 33 | 28 |  |  |  |  | 45 |  | 
| 34 | 28 |  |  |  |  | 103 | my %properties = @_; | 
| 35 |  |  |  |  |  |  |  | 
| 36 | 28 |  |  |  |  | 107 | $self->{_name} = undef; | 
| 37 |  |  |  |  |  |  | $self->{_type} = 'rect'; | 
| 38 | 28 |  |  |  |  | 81 |  | 
| 39 | 28 |  |  |  |  | 70 | # Is a Connector shape. 1/0 Value is a hash lookup from type. | 
| 40 |  |  |  |  |  |  | $self->{_connect} = 0; | 
| 41 |  |  |  |  |  |  |  | 
| 42 | 28 |  |  |  |  | 54 | # Is a Drawing. Always 0, since a single shape never fills an entire sheet. | 
| 43 |  |  |  |  |  |  | $self->{_drawing} = 0; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 28 |  |  |  |  | 50 | # OneCell or Absolute: options to move and/or size with cells. | 
| 46 |  |  |  |  |  |  | $self->{_editAs} = ''; | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 28 |  |  |  |  | 52 | # Auto-incremented, unless supplied by user. | 
| 49 |  |  |  |  |  |  | $self->{_id} = 0; | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 28 |  |  |  |  | 58 | # Shape text (usually centered on shape geometry). | 
| 52 |  |  |  |  |  |  | $self->{_text} = 0; | 
| 53 |  |  |  |  |  |  |  | 
| 54 | 28 |  |  |  |  | 74 | # Shape stencil mode.  A copy (child) is created when inserted. | 
| 55 |  |  |  |  |  |  | # The link to parent is broken. | 
| 56 |  |  |  |  |  |  | $self->{_stencil} = 1; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 28 |  |  |  |  | 62 | # Index to _shapes array when inserted. | 
| 59 |  |  |  |  |  |  | $self->{_element} = -1; | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 28 |  |  |  |  | 45 | # Shape ID of starting connection, if any. | 
| 62 |  |  |  |  |  |  | $self->{_start} = undef; | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 28 |  |  |  |  | 58 | # Shape vertex, starts at 0, numbered clockwise from 12 o'clock. | 
| 65 |  |  |  |  |  |  | $self->{_start_index} = undef; | 
| 66 |  |  |  |  |  |  |  | 
| 67 | 28 |  |  |  |  | 51 | $self->{_end}       = undef; | 
| 68 |  |  |  |  |  |  | $self->{_end_index} = undef; | 
| 69 | 28 |  |  |  |  | 50 |  | 
| 70 | 28 |  |  |  |  | 59 | # Number and size of adjustments for shapes (usually connectors). | 
| 71 |  |  |  |  |  |  | $self->{_adjustments} = []; | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 28 |  |  |  |  | 57 | # Start and end sides. t)op, b)ottom, l)eft, or r)ight. | 
| 74 |  |  |  |  |  |  | $self->{_start_side} = ''; | 
| 75 |  |  |  |  |  |  | $self->{_end_side}   = ''; | 
| 76 | 28 |  |  |  |  | 100 |  | 
| 77 | 28 |  |  |  |  | 60 | # Flip shape Horizontally. eg. arrow left to arrow right. | 
| 78 |  |  |  |  |  |  | $self->{_flip_h} = 0; | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 28 |  |  |  |  | 55 | # Flip shape Vertically. eg. up arrow to down arrow. | 
| 81 |  |  |  |  |  |  | $self->{_flip_v} = 0; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 28 |  |  |  |  | 52 | # shape rotation (in degrees 0-360). | 
| 84 |  |  |  |  |  |  | $self->{_rotation} = 0; | 
| 85 |  |  |  |  |  |  |  | 
| 86 | 28 |  |  |  |  | 43 | # An alternate way to create a text box, because Excel allows it. | 
| 87 |  |  |  |  |  |  | # It is just a rectangle with text. | 
| 88 |  |  |  |  |  |  | $self->{_txBox} = 0; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 28 |  |  |  |  | 51 | # Shape outline colour, or 0 for noFill (default black). | 
| 91 |  |  |  |  |  |  | $self->{_line} = '000000'; | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 28 |  |  |  |  | 68 | # Line type: dash, sysDot, dashDot, lgDash, lgDashDot, lgDashDotDot. | 
| 94 |  |  |  |  |  |  | $self->{_line_type} = ''; | 
| 95 |  |  |  |  |  |  |  | 
| 96 | 28 |  |  |  |  | 53 | # Line weight (integer). | 
| 97 |  |  |  |  |  |  | $self->{_line_weight} = 1; | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 28 |  |  |  |  | 57 | # Shape fill colour, or 0 for noFill (default noFill). | 
| 100 |  |  |  |  |  |  | $self->{_fill} = 0; | 
| 101 |  |  |  |  |  |  |  | 
| 102 | 28 |  |  |  |  | 63 | # Formatting for shape text, if any. | 
| 103 |  |  |  |  |  |  | $self->{_format} = {}; | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 28 |  |  |  |  | 65 | # copy of colour palette table from Workbook.pm. | 
| 106 |  |  |  |  |  |  | $self->{_palette} = []; | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 28 |  |  |  |  | 53 | # Vertical alignment: t, ctr, b. | 
| 109 |  |  |  |  |  |  | $self->{_valign} = 'ctr'; | 
| 110 |  |  |  |  |  |  |  | 
| 111 | 28 |  |  |  |  | 58 | # Alignment: l, ctr, r, just | 
| 112 |  |  |  |  |  |  | $self->{_align} = 'ctr'; | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 28 |  |  |  |  | 56 | $self->{_x_offset} = 0; | 
| 115 |  |  |  |  |  |  | $self->{_y_offset} = 0; | 
| 116 | 28 |  |  |  |  | 62 |  | 
| 117 | 28 |  |  |  |  | 49 | # Scale factors, which also may be set when the shape is inserted. | 
| 118 |  |  |  |  |  |  | $self->{_scale_x} = 1; | 
| 119 |  |  |  |  |  |  | $self->{_scale_y} = 1; | 
| 120 | 28 |  |  |  |  | 102 |  | 
| 121 | 28 |  |  |  |  | 55 | # Default size, which can be modified and/or scaled. | 
| 122 |  |  |  |  |  |  | $self->{_width}  = 50; | 
| 123 |  |  |  |  |  |  | $self->{_height} = 50; | 
| 124 | 28 |  |  |  |  | 81 |  | 
| 125 | 28 |  |  |  |  | 49 | # Initial assignment. May be modified when prepared. | 
| 126 |  |  |  |  |  |  | $self->{_column_start} = 0; | 
| 127 |  |  |  |  |  |  | $self->{_row_start}    = 0; | 
| 128 | 28 |  |  |  |  | 49 | $self->{_x1}           = 0; | 
| 129 | 28 |  |  |  |  | 48 | $self->{_y1}           = 0; | 
| 130 | 28 |  |  |  |  | 53 | $self->{_column_end}   = 0; | 
| 131 | 28 |  |  |  |  | 55 | $self->{_row_end}      = 0; | 
| 132 | 28 |  |  |  |  | 52 | $self->{_x2}           = 0; | 
| 133 | 28 |  |  |  |  | 59 | $self->{_y2}           = 0; | 
| 134 | 28 |  |  |  |  | 48 | $self->{_x_abs}        = 0; | 
| 135 | 28 |  |  |  |  | 55 | $self->{_y_abs}        = 0; | 
| 136 | 28 |  |  |  |  | 47 |  | 
| 137 | 28 |  |  |  |  | 49 | # Override default properties with passed arguments | 
| 138 |  |  |  |  |  |  | while ( my ( $key, $value ) = each( %properties ) ) { | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 28 |  |  |  |  | 129 | # Strip leading "-" from Tk style properties e.g. -color => 'red'. | 
| 141 |  |  |  |  |  |  | $key =~ s/^-//; | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 53 |  |  |  |  | 88 | # Add leading underscore "_" to internal hash keys, if not supplied. | 
| 144 |  |  |  |  |  |  | $key = "_" . $key unless $key =~ m/^_/; | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 53 | 50 |  |  |  | 197 | $self->{$key} = $value; | 
| 147 |  |  |  |  |  |  | } | 
| 148 | 53 |  |  |  |  | 197 |  | 
| 149 |  |  |  |  |  |  | bless $self, $class; | 
| 150 |  |  |  |  |  |  | return $self; | 
| 151 | 28 |  |  |  |  | 55 | } | 
| 152 | 28 |  |  |  |  | 89 |  | 
| 153 |  |  |  |  |  |  |  | 
| 154 |  |  |  |  |  |  | ############################################################################### | 
| 155 |  |  |  |  |  |  | # | 
| 156 |  |  |  |  |  |  | # set_properties( name => 'Shape 1', type => 'rect' ) | 
| 157 |  |  |  |  |  |  | # | 
| 158 |  |  |  |  |  |  | # Set shape properties. | 
| 159 |  |  |  |  |  |  | # | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | my $self       = shift; | 
| 162 |  |  |  |  |  |  | my %properties = @_; | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 1 |  |  | 1 | 0 | 5 | # Update properties with passed arguments. | 
| 165 | 1 |  |  |  |  | 3 | while ( my ( $key, $value ) = each( %properties ) ) { | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | # Strip leading "-" from Tk style properties e.g. -color => 'red'. | 
| 168 | 1 |  |  |  |  | 6 | $key =~ s/^-//; | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | # Add leading underscore "_" to internal hash keys, if not supplied. | 
| 171 | 2 |  |  |  |  | 4 | $key = "_" . $key unless $key =~ m/^_/; | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | if ( !exists $self->{$key} ) { | 
| 174 | 2 | 50 |  |  |  | 8 | warn "Unknown shape property: $key. Property not set.\n"; | 
| 175 |  |  |  |  |  |  | next; | 
| 176 | 2 | 50 |  |  |  | 5 | } | 
| 177 | 0 |  |  |  |  | 0 |  | 
| 178 | 0 |  |  |  |  | 0 | $self->{$key} = $value; | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  | } | 
| 181 | 2 |  |  |  |  | 9 |  | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | ############################################################################### | 
| 184 |  |  |  |  |  |  | # | 
| 185 |  |  |  |  |  |  | # set_adjustment( adj1, adj2, adj3, ... ) | 
| 186 |  |  |  |  |  |  | # | 
| 187 |  |  |  |  |  |  | # Set the shape adjustments array (as a reference). | 
| 188 |  |  |  |  |  |  | # | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | my $self = shift; | 
| 191 |  |  |  |  |  |  | $self->{_adjustments} = \@_; | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  |  | 
| 194 | 4 |  |  | 4 | 0 | 13 |  | 
| 195 | 4 |  |  |  |  | 13 | ############################################################################### | 
| 196 |  |  |  |  |  |  | # | 
| 197 |  |  |  |  |  |  | # AUTOLOAD. Deus ex machina. | 
| 198 |  |  |  |  |  |  | # | 
| 199 |  |  |  |  |  |  | # Dynamically create set/get methods that aren't already defined. | 
| 200 |  |  |  |  |  |  | # | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | my $self = shift; | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | # Ignore calls to DESTROY. | 
| 205 |  |  |  |  |  |  | return if $AUTOLOAD =~ /::DESTROY$/; | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 127 |  |  | 127 |  | 11707 | # Check for a valid method names, i.e. "set_xxx_Cy". | 
| 208 |  |  |  |  |  |  | $AUTOLOAD =~ /.*::(get|set)(\w+)/ or die "Unknown method: $AUTOLOAD\n"; | 
| 209 |  |  |  |  |  |  |  | 
| 210 | 127 | 100 |  |  |  | 2591 | # Match the function (get or set) and attribute, i.e. "_xxx_yyy". | 
| 211 |  |  |  |  |  |  | my $gs        = $1; | 
| 212 |  |  |  |  |  |  | my $attribute = $2; | 
| 213 | 54 | 50 |  |  |  | 234 |  | 
| 214 |  |  |  |  |  |  | # Check that the attribute exists. | 
| 215 |  |  |  |  |  |  | exists $self->{$attribute} or die "Unknown method: $AUTOLOAD\n"; | 
| 216 | 54 |  |  |  |  | 95 |  | 
| 217 | 54 |  |  |  |  | 87 | # The attribute value | 
| 218 |  |  |  |  |  |  | my $value; | 
| 219 |  |  |  |  |  |  |  | 
| 220 | 54 | 50 |  |  |  | 121 | # set_property() pattern. | 
| 221 |  |  |  |  |  |  | # When a method is AUTOLOADED we store a new anonymous | 
| 222 |  |  |  |  |  |  | # sub in the appropriate slot in the symbol table. The speeds up subsequent | 
| 223 | 54 |  |  |  |  | 61 | # calls to the same method. | 
| 224 |  |  |  |  |  |  | # | 
| 225 |  |  |  |  |  |  | no strict 'refs';    # To allow symbol table hackery | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | $value = $_[0]; | 
| 228 |  |  |  |  |  |  | $value = 1 if not defined $value;    # The default value is always 1 | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 1124 |  |  | 1124 |  | 6728 | if ( $gs eq 'set' ) { | 
|  | 1124 |  |  |  |  | 3984 |  | 
|  | 1124 |  |  |  |  | 197485 |  | 
| 231 |  |  |  |  |  |  | *{$AUTOLOAD} = sub { | 
| 232 | 54 |  |  |  |  | 69 | my $self  = shift; | 
| 233 | 54 | 100 |  |  |  | 97 | my $value = shift; | 
| 234 |  |  |  |  |  |  |  | 
| 235 | 54 | 100 |  |  |  | 110 | $value = 1 if not defined $value; | 
| 236 | 48 |  |  |  |  | 127 | $self->{$attribute} = $value; | 
| 237 | 17 |  |  | 17 |  | 37 | }; | 
| 238 | 17 |  |  |  |  | 20 |  | 
| 239 |  |  |  |  |  |  | $self->{$attribute} = $value; | 
| 240 | 17 | 50 |  |  |  | 30 | } | 
| 241 | 17 |  |  |  |  | 34 | else { | 
| 242 | 48 |  |  |  |  | 138 | *{$AUTOLOAD} = sub { | 
| 243 |  |  |  |  |  |  | my $self = shift; | 
| 244 | 48 |  |  |  |  | 168 | return $self->{$attribute}; | 
| 245 |  |  |  |  |  |  | }; | 
| 246 |  |  |  |  |  |  |  | 
| 247 | 6 |  |  |  |  | 28 | # Let AUTOLOAD return the attribute for the first invocation | 
| 248 | 20 |  |  | 20 |  | 51 | return $self->{$attribute}; | 
| 249 | 20 |  |  |  |  | 71 | } | 
| 250 | 6 |  |  |  |  | 27 | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 6 |  |  |  |  | 64 | ############################################################################### | 
| 254 |  |  |  |  |  |  | # | 
| 255 |  |  |  |  |  |  | # _get_palette_color() | 
| 256 |  |  |  |  |  |  | # | 
| 257 |  |  |  |  |  |  | # Convert from an Excel internal colour index to a XML style #RRGGBB index | 
| 258 |  |  |  |  |  |  | # based on the default or user defined values in the Workbook palette. | 
| 259 |  |  |  |  |  |  | # Note: This version doesn't add an alpha channel. | 
| 260 |  |  |  |  |  |  | # | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | my $self    = shift; | 
| 263 |  |  |  |  |  |  | my $index   = shift; | 
| 264 |  |  |  |  |  |  | my $palette = $self->{_palette}; | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | # Adjust the colour index. | 
| 267 |  |  |  |  |  |  | $index -= 8; | 
| 268 | 14 |  |  | 14 |  | 21 |  | 
| 269 | 14 |  |  |  |  | 19 | # Palette is passed in from the Workbook class. | 
| 270 | 14 |  |  |  |  | 21 | my @rgb = @{ $palette->[$index] }; | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | return sprintf "%02X%02X%02X", @rgb[0, 1, 2]; | 
| 273 | 14 |  |  |  |  | 21 | } | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 14 |  |  |  |  | 19 | 1; | 
|  | 14 |  |  |  |  | 32 |  | 
| 277 |  |  |  |  |  |  |  | 
| 278 | 14 |  |  |  |  | 77 |  | 
| 279 |  |  |  |  |  |  | =head1 NAME | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | Shape - A class for creating Excel Drawing shapes | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | To create a simple Excel file containing shapes using L<Excel::Writer::XLSX>: | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | #!/usr/bin/perl | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | use strict; | 
| 290 |  |  |  |  |  |  | use warnings; | 
| 291 |  |  |  |  |  |  | use Excel::Writer::XLSX; | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | my $workbook  = Excel::Writer::XLSX->new( 'shape.xlsx' ); | 
| 294 |  |  |  |  |  |  | my $worksheet = $workbook->add_worksheet(); | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | # Add a default rectangle shape. | 
| 297 |  |  |  |  |  |  | my $rect = $workbook->add_shape(); | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | # Add an ellipse with centered text. | 
| 300 |  |  |  |  |  |  | my $ellipse = $workbook->add_shape( | 
| 301 |  |  |  |  |  |  | type => 'ellipse', | 
| 302 |  |  |  |  |  |  | text => "Hello\nWorld" | 
| 303 |  |  |  |  |  |  | ); | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | # Add a plus shape. | 
| 306 |  |  |  |  |  |  | my $plus = $workbook->add_shape( type => 'plus'); | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | # Insert the shapes in the worksheet. | 
| 309 |  |  |  |  |  |  | $worksheet->insert_shape( 'B3', $rect ); | 
| 310 |  |  |  |  |  |  | $worksheet->insert_shape( 'C3', $ellipse ); | 
| 311 |  |  |  |  |  |  | $worksheet->insert_shape( 'D3', $plus ); | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | The C<Excel::Writer::XLSX::Shape> module is used to create Shape objects for L<Excel::Writer::XLSX>. | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | A Shape object is created via the Workbook C<add_shape()> method: | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | my $shape_rect = $workbook->add_shape( type => 'rect' ); | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | Once the object is created it can be inserted into a worksheet using the C<insert_shape()> method: | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | $worksheet->insert_shape('A1', $shape_rect); | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | A Shape can be inserted multiple times if required. | 
| 327 |  |  |  |  |  |  |  | 
| 328 |  |  |  |  |  |  | $worksheet->insert_shape('A1', $shape_rect); | 
| 329 |  |  |  |  |  |  | $worksheet->insert_shape('B2', $shape_rect, 20, 30); | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | =head1 METHODS | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | =head2 add_shape( %properties ) | 
| 335 |  |  |  |  |  |  |  | 
| 336 |  |  |  |  |  |  | The C<add_shape()> Workbook method specifies the properties of the Shape in hash C<< property => value >> format: | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | my $shape = $workbook->add_shape( %properties ); | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | The available properties are shown below. | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | =head2 insert_shape( $row, $col, $shape, $x, $y, $scale_x, $scale_y ) | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | The C<insert_shape()> Worksheet method sets the location and scale of the shape object within the worksheet. | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  | # Insert the shape into the worksheet. | 
| 347 |  |  |  |  |  |  | $worksheet->insert_shape( 'E2', $shape ); | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | Using the cell location and the C<$x> and C<$y> cell offsets it is possible to position a shape anywhere on the canvas of a worksheet. | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | A more detailed explanation of the C<insert_shape()> method is given in the main L<Excel::Writer::XLSX> documentation. | 
| 352 |  |  |  |  |  |  |  | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | =head1 SHAPE PROPERTIES | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | Any shape property can be queried or modified by the corresponding get/set method: | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | my $ellipse = $workbook->add_shape( %properties ); | 
| 359 |  |  |  |  |  |  | $ellipse->set_type( 'plus' );    # No longer an ellipse! | 
| 360 |  |  |  |  |  |  | my $type = $ellipse->get_type();  # Find out what it really is. | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | Multiple shape properties may also be modified in one go by using the C<set_properties()> method: | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | $shape->set_properties( type => 'ellipse', text => 'Hello' ); | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | The properties of a shape object that can be defined via C<add_shape()> are shown below. | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | =head2 name | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | Defines the name of the shape. This is an optional property and the shape will be given a default name if not supplied. The name is generally only used by Excel Macros to refer to the object. | 
| 371 |  |  |  |  |  |  |  | 
| 372 |  |  |  |  |  |  | =head2 type | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | Defines the type of the object such as C<rect>, C<ellipse> or C<triangle>: | 
| 375 |  |  |  |  |  |  |  | 
| 376 |  |  |  |  |  |  | my $ellipse = $workbook->add_shape( type => 'ellipse' ); | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | The default type is C<rect>. | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | The full list of available shapes is shown below. | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | See also the C<shapes_all.pl> program in the C<examples> directory of the distro. It creates an example workbook with all supported shapes labelled with their shape names. | 
| 383 |  |  |  |  |  |  |  | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | =over 4 | 
| 386 |  |  |  |  |  |  |  | 
| 387 |  |  |  |  |  |  | =item * Basic Shapes | 
| 388 |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  | blockArc              can            chevron       cube          decagon | 
| 390 |  |  |  |  |  |  | diamond               dodecagon      donut         ellipse       funnel | 
| 391 |  |  |  |  |  |  | gear6                 gear9          heart         heptagon      hexagon | 
| 392 |  |  |  |  |  |  | homePlate             lightningBolt  line          lineInv       moon | 
| 393 |  |  |  |  |  |  | nonIsoscelesTrapezoid noSmoking      octagon       parallelogram pentagon | 
| 394 |  |  |  |  |  |  | pie                   pieWedge       plaque        rect          round1Rect | 
| 395 |  |  |  |  |  |  | round2DiagRect        round2SameRect roundRect     rtTriangle    smileyFace | 
| 396 |  |  |  |  |  |  | snip1Rect             snip2DiagRect  snip2SameRect snipRoundRect star10 | 
| 397 |  |  |  |  |  |  | star12                star16         star24        star32        star4 | 
| 398 |  |  |  |  |  |  | star5                 star6          star7         star8         sun | 
| 399 |  |  |  |  |  |  | teardrop              trapezoid      triangle | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | =item * Arrow Shapes | 
| 402 |  |  |  |  |  |  |  | 
| 403 |  |  |  |  |  |  | bentArrow        bentUpArrow       circularArrow     curvedDownArrow | 
| 404 |  |  |  |  |  |  | curvedLeftArrow  curvedRightArrow  curvedUpArrow     downArrow | 
| 405 |  |  |  |  |  |  | leftArrow        leftCircularArrow leftRightArrow    leftRightCircularArrow | 
| 406 |  |  |  |  |  |  | leftRightUpArrow leftUpArrow       notchedRightArrow quadArrow | 
| 407 |  |  |  |  |  |  | rightArrow       stripedRightArrow swooshArrow       upArrow | 
| 408 |  |  |  |  |  |  | upDownArrow      uturnArrow | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | =item * Connector Shapes | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | bentConnector2   bentConnector3   bentConnector4 | 
| 413 |  |  |  |  |  |  | bentConnector5   curvedConnector2 curvedConnector3 | 
| 414 |  |  |  |  |  |  | curvedConnector4 curvedConnector5 straightConnector1 | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | =item * Callout Shapes | 
| 417 |  |  |  |  |  |  |  | 
| 418 |  |  |  |  |  |  | accentBorderCallout1  accentBorderCallout2  accentBorderCallout3 | 
| 419 |  |  |  |  |  |  | accentCallout1        accentCallout2        accentCallout3 | 
| 420 |  |  |  |  |  |  | borderCallout1        borderCallout2        borderCallout3 | 
| 421 |  |  |  |  |  |  | callout1              callout2              callout3 | 
| 422 |  |  |  |  |  |  | cloudCallout          downArrowCallout      leftArrowCallout | 
| 423 |  |  |  |  |  |  | leftRightArrowCallout quadArrowCallout      rightArrowCallout | 
| 424 |  |  |  |  |  |  | upArrowCallout        upDownArrowCallout    wedgeEllipseCallout | 
| 425 |  |  |  |  |  |  | wedgeRectCallout      wedgeRoundRectCallout | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | =item * Flow Chart Shapes | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | flowChartAlternateProcess  flowChartCollate        flowChartConnector | 
| 430 |  |  |  |  |  |  | flowChartDecision          flowChartDelay          flowChartDisplay | 
| 431 |  |  |  |  |  |  | flowChartDocument          flowChartExtract        flowChartInputOutput | 
| 432 |  |  |  |  |  |  | flowChartInternalStorage   flowChartMagneticDisk   flowChartMagneticDrum | 
| 433 |  |  |  |  |  |  | flowChartMagneticTape      flowChartManualInput    flowChartManualOperation | 
| 434 |  |  |  |  |  |  | flowChartMerge             flowChartMultidocument  flowChartOfflineStorage | 
| 435 |  |  |  |  |  |  | flowChartOffpageConnector  flowChartOnlineStorage  flowChartOr | 
| 436 |  |  |  |  |  |  | flowChartPredefinedProcess flowChartPreparation    flowChartProcess | 
| 437 |  |  |  |  |  |  | flowChartPunchedCard       flowChartPunchedTape    flowChartSort | 
| 438 |  |  |  |  |  |  | flowChartSummingJunction   flowChartTerminator | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | =item * Action Shapes | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | actionButtonBackPrevious actionButtonBeginning actionButtonBlank | 
| 443 |  |  |  |  |  |  | actionButtonDocument     actionButtonEnd       actionButtonForwardNext | 
| 444 |  |  |  |  |  |  | actionButtonHelp         actionButtonHome      actionButtonInformation | 
| 445 |  |  |  |  |  |  | actionButtonMovie        actionButtonReturn    actionButtonSound | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | =item * Chart Shapes | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | Not to be confused with Excel Charts. | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | chartPlus chartStar chartX | 
| 452 |  |  |  |  |  |  |  | 
| 453 |  |  |  |  |  |  | =item * Math Shapes | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | mathDivide mathEqual mathMinus mathMultiply mathNotEqual mathPlus | 
| 456 |  |  |  |  |  |  |  | 
| 457 |  |  |  |  |  |  | =item * Stars and Banners | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | arc            bevel          bracePair  bracketPair chord | 
| 460 |  |  |  |  |  |  | cloud          corner         diagStripe doubleWave  ellipseRibbon | 
| 461 |  |  |  |  |  |  | ellipseRibbon2 foldedCorner   frame      halfFrame   horizontalScroll | 
| 462 |  |  |  |  |  |  | irregularSeal1 irregularSeal2 leftBrace  leftBracket leftRightRibbon | 
| 463 |  |  |  |  |  |  | plus           ribbon         ribbon2    rightBrace  rightBracket | 
| 464 |  |  |  |  |  |  | verticalScroll wave | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | =item * Tab Shapes | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | cornerTabs plaqueTabs squareTabs | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | =back | 
| 471 |  |  |  |  |  |  |  | 
| 472 |  |  |  |  |  |  | =head2 text | 
| 473 |  |  |  |  |  |  |  | 
| 474 |  |  |  |  |  |  | This property is used to make the shape act like a text box. | 
| 475 |  |  |  |  |  |  |  | 
| 476 |  |  |  |  |  |  | my $rect = $workbook->add_shape( type => 'rect', text => "Hello\nWorld" ); | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | The text is super-imposed over the shape. The text can be wrapped using the newline character C<\n>. | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | =head2 id | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | Identification number for internal identification. This number will be auto-assigned, if not assigned, or if it is a duplicate. | 
| 483 |  |  |  |  |  |  |  | 
| 484 |  |  |  |  |  |  | =head2 format | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | Workbook format for decorating the shape text (font family, size, and decoration). | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | =head2 start, start_index | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | Shape indices of the starting point for a connector and the index of the connection. Index numbers are zero-based, start from the top dead centre and are counted clockwise. | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | Indices are typically created for vertices and centre points of shapes. They are the blue connection points that appear when connection shapes are selected manually in Excel. | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | =head2 end, end_index | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | Same as above but for end points and end connections. | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  |  | 
| 499 |  |  |  |  |  |  | =head2 start_side, end_side | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | This is either the letter C<b> or C<r> for the bottom or right side of the shape to be connected to and from. | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | If the C<start>, C<start_index>, and C<start_side> parameters are defined for a connection shape, the shape will be auto located and linked to the starting and ending shapes respectively. This can be very useful for flow and organisation charts. | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | =head2 flip_h, flip_v | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | Set this value to 1, to flip the shape horizontally and/or vertically. | 
| 508 |  |  |  |  |  |  |  | 
| 509 |  |  |  |  |  |  | =head2 rotation | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | Shape rotation, in degrees, from 0 to 360. | 
| 512 |  |  |  |  |  |  |  | 
| 513 |  |  |  |  |  |  | =head2 line, fill | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | Shape colour for the outline and fill. Colours may be specified as a colour index, or in RGB format, i.e. C<AA00FF>. | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | See C<COLOURS IN EXCEL> in the main documentation for more information. | 
| 518 |  |  |  |  |  |  |  | 
| 519 |  |  |  |  |  |  | =head2 line_type | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | Line type for shape outline. The default is solid. The list of possible values is: | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | dash, sysDot, dashDot, lgDash, lgDashDot, lgDashDotDot, solid | 
| 524 |  |  |  |  |  |  |  | 
| 525 |  |  |  |  |  |  | =head2 valign, align | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | Text alignment within the shape. | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | Vertical alignment can be: | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | Setting     Meaning | 
| 532 |  |  |  |  |  |  | =======     ======= | 
| 533 |  |  |  |  |  |  | t           Top | 
| 534 |  |  |  |  |  |  | ctr         Centre | 
| 535 |  |  |  |  |  |  | b           Bottom | 
| 536 |  |  |  |  |  |  |  | 
| 537 |  |  |  |  |  |  | Horizontal alignment can be: | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  | Setting     Meaning | 
| 540 |  |  |  |  |  |  | =======     ======= | 
| 541 |  |  |  |  |  |  | l           Left | 
| 542 |  |  |  |  |  |  | r           Right | 
| 543 |  |  |  |  |  |  | ctr         Centre | 
| 544 |  |  |  |  |  |  | just        Justified | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | The default is to centre both horizontally and vertically. | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | =head2 scale_x, scale_y | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | Scale factor in x and y dimension, for scaling the shape width and height. The default value is 1. | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | Scaling may be set on the shape object or via C<insert_shape()>. | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | =head2 adjustments | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | Adjustment of shape vertices. Most shapes do not use this. For some shapes, there is a single adjustment to modify the geometry. For instance, the plus shape has one adjustment to control the width of the spokes. | 
| 557 |  |  |  |  |  |  |  | 
| 558 |  |  |  |  |  |  | Connectors can have a number of adjustments to control the shape routing. Typically, a connector will have 3 to 5 handles for routing the shape. The adjustment is in percent of the distance from the starting shape to the ending shape, alternating between the x and y dimension. Adjustments may be negative, to route the shape away from the endpoint. | 
| 559 |  |  |  |  |  |  |  | 
| 560 |  |  |  |  |  |  | =head2 stencil | 
| 561 |  |  |  |  |  |  |  | 
| 562 |  |  |  |  |  |  | Shapes work in stencil mode by default. That is, once a shape is inserted, its connection is separated from its master. The master shape may be modified after an instance is inserted, and only subsequent insertions will show the modifications. | 
| 563 |  |  |  |  |  |  |  | 
| 564 |  |  |  |  |  |  | This is helpful for Org charts, where an employee shape may be created once, and then the text of the shape is modified for each employee. | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | The C<insert_shape()> method returns a reference to the inserted shape (the child). | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | Stencil mode can be turned off, allowing for shape(s) to be modified after insertion. In this case the C<insert_shape()> method returns a reference to the inserted shape (the master). This is not very useful for inserting multiple shapes, since the x/y coordinates also gets modified. | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | =head1 TIPS | 
| 571 |  |  |  |  |  |  |  | 
| 572 |  |  |  |  |  |  | Use C<< $worksheet->hide_gridlines(2) >> to prepare a blank canvas without gridlines. | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | Shapes do not need to fit on one page. Excel will split a large drawing into multiple pages if required. Use the page break preview to show page boundaries superimposed on the drawing. | 
| 575 |  |  |  |  |  |  |  | 
| 576 |  |  |  |  |  |  | Connected shapes will auto-locate in Excel if you move either the starting shape or the ending shape separately. However, if you select both shapes (lasso or control-click), the connector will move with it, and the shape adjustments will not re-calculate. | 
| 577 |  |  |  |  |  |  |  | 
| 578 |  |  |  |  |  |  | =head1 EXAMPLE | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | #!/usr/bin/perl | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | use strict; | 
| 583 |  |  |  |  |  |  | use warnings; | 
| 584 |  |  |  |  |  |  | use Excel::Writer::XLSX; | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | my $workbook  = Excel::Writer::XLSX->new( 'shape.xlsx' ); | 
| 587 |  |  |  |  |  |  | my $worksheet = $workbook->add_worksheet(); | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | # Add a default rectangle shape. | 
| 590 |  |  |  |  |  |  | my $rect = $workbook->add_shape(); | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | # Add an ellipse with centered text. | 
| 593 |  |  |  |  |  |  | my $ellipse = $workbook->add_shape( | 
| 594 |  |  |  |  |  |  | type => 'ellipse', | 
| 595 |  |  |  |  |  |  | text => "Hello\nWorld" | 
| 596 |  |  |  |  |  |  | ); | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | # Add a plus shape. | 
| 599 |  |  |  |  |  |  | my $plus = $workbook->add_shape( type => 'plus'); | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | # Insert the shapes in the worksheet. | 
| 602 |  |  |  |  |  |  | $worksheet->insert_shape( 'B3', $rect ); | 
| 603 |  |  |  |  |  |  | $worksheet->insert_shape( 'C3', $ellipse ); | 
| 604 |  |  |  |  |  |  | $worksheet->insert_shape( 'D3', $plus ); | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  |  | 
| 607 |  |  |  |  |  |  | See also the C<shapes_*.pl> program in the C<examples> directory of the distro. | 
| 608 |  |  |  |  |  |  |  | 
| 609 |  |  |  |  |  |  | =head1 TODO | 
| 610 |  |  |  |  |  |  |  | 
| 611 |  |  |  |  |  |  | =over 4 | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | =item * Add shapes which have custom geometries. | 
| 614 |  |  |  |  |  |  |  | 
| 615 |  |  |  |  |  |  | =item * Provide better integration of workbook formats for shapes. | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | =item * Add further validation of shape properties to prevent creation of workbooks that will not open. | 
| 618 |  |  |  |  |  |  |  | 
| 619 |  |  |  |  |  |  | =item * Auto connect shapes that are not anchored to cell A1. | 
| 620 |  |  |  |  |  |  |  | 
| 621 |  |  |  |  |  |  | =item * Add automatic shape connection to shape vertices besides the object centre. | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | =item * Improve automatic shape connection to shapes with concave sides (e.g. chevron). | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | =back | 
| 626 |  |  |  |  |  |  |  | 
| 627 |  |  |  |  |  |  | =head1 AUTHOR | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | Dave Clarke dclarke@cpan.org | 
| 630 |  |  |  |  |  |  |  | 
| 631 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 632 |  |  |  |  |  |  |  | 
| 633 |  |  |  |  |  |  | (c) MM-MMXXI, John McNamara. | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. |