File Coverage

blib/lib/SVG/Timeline/Genealogy.pm
Criterion Covered Total %
statement 26 26 100.0
branch n/a
condition n/a
subroutine 9 9 100.0
pod 3 3 100.0
total 38 38 100.0


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             SVG::Timeline::Genealogy - Create genealogical timelines in SVG
4              
5             =head1 SYNOPSIS
6              
7             use SVG::Timeline::Genealogy
8              
9             my $tl = SVG::Timeline::Genealogy->new;
10              
11             $tl->add_person({
12             ahnen => 1,
13             start => 1975,
14             text => 'You',
15             });
16              
17             $tl->add_person({
18             anhen => 2,
19             start => 1950,
20             end => 1980,
21             text => 'Your Father',
22             });
23              
24             $tl->add_person({
25             anhen => 3,
26             start => 1950,
27             text => 'Your Mother',
28             });
29              
30             print $tl->draw;
31              
32             =head1 DESC
33              
34             This module allows you to easily create SVG documents that represent
35             genealogical timelines.
36              
37             The module is a subclass of L<SVG::Timeline> and this documentation should
38             be read in conjunction with the documentation for that module. SVG::Timeline
39             deals with events, in this subclass, events have been renamed to people.
40              
41             When I say "genealogical timeline", I mean an ancestor chart. This is a
42             diagram which shows the ancestors of a person. Each person on the timeline
43             is represented by a bar which shows the years they were alive. The position
44             and colour of the bars show the relationships between the people in the
45             timeline.
46              
47             In this module, people have all of the same attributes as events do in
48             SVG::Timeline, but there is one extra attribute (called "ahnen") which might
49             need some explanation.
50              
51             The term "ahnen" is short for "Anhnentafel Number". This is a number that can
52             be given to people in a genealogical system in order to represent relationships
53             between them.
54              
55             If you have the Ahnentafel number of 1, then your father is 2 and mour
56             mother is 3. You father's parents are 4 and 5 and your mother's are 6 and 7.
57             These numbers have some interesting properties. If a person's number is C<$x>,
58             then their father will be C<2 * $x> and their mother will be C<2 * $x + 1>.
59             Also, this the exception of person 1 (who can be of either sex), all men have
60             even Ahnentafel numbers and all women have odd ones.
61              
62             All of which means that if you give us the Ahnentafel number for the people
63             you add to the chart (and you have to - it's a required attribute), then we
64             can work out all the relationships between the people.
65              
66             =cut
67              
68             package SVG::Timeline::Genealogy;
69              
70 2     2   142870 use 5.010;
  2         17  
71              
72             our $VERSION = '0.0.4';
73              
74 2     2   1288 use Moose;
  2         975822  
  2         15  
75 2     2   15102 use Moose::Util::TypeConstraints;
  2         6  
  2         19  
76             extends 'SVG::Timeline';
77              
78 2     2   6195 use Time::Piece;
  2         20498  
  2         9  
79 2     2   163 use List::Util 'max';
  2         4  
  2         145  
80 2     2   1053 use SVG::Timeline::Genealogy::Person;
  2         22  
  2         977  
81              
82             subtype 'ArrayOfPeople', as 'ArrayRef[SVG::Timeline::Genealogy::Person]';
83              
84             coerce 'ArrayOfPeople',
85             from 'HashRef',
86             via { [ SVG::Timeline::Genealogy::Person->new($_) ] },
87             from 'ArrayRef[HashRef]',
88             via { [ map { SVG::Timeline::Genealogy::Person->new($_) } @$_ ] };
89              
90             has +events => (
91             isa => 'ArrayOfPeople',
92             is => 'rw',
93             default => sub { [] },
94             coerce => 1,
95             traits => ['Array'],
96             handles => {
97             all_people => 'elements',
98             add_person => 'push',
99             count_people => 'count',
100             has_people => 'count',
101             },
102             );
103              
104             around 'add_person' => sub {
105             my $orig = shift;
106             my $self = shift;
107              
108             $_[0]->{index} = 0;
109              
110             $self->$orig(@_);
111              
112             $self->calculate_indexes;
113             };
114              
115             =head1 METHODS AND ATTRIBUTES
116              
117             You'll also need to see the documentation for L<SVG::Timeline>. This document
118             only includes details of the changed and extra methods and attributes.
119              
120             =head2 calculate_indexes()
121              
122             The order that people appear in the chart isn't controlled by the order that
123             they are added but, rather, their Ahnentafel number. That means that every
124             time a new person is added, the indexes need to be recalculated. This method
125             does that. You should never need to call it.
126              
127             =cut
128              
129             sub calculate_indexes {
130 1     1 1 4 my $self = shift;
131              
132 1         4 my $count_of_people = $self->events_in_timeline;
133              
134 1         42 for ($self->all_people) {
135 1         8 $_->set_index($count_of_people);
136             }
137             }
138              
139             =head2 max_generation
140              
141             Returns the maximum number of generations that the timeline contains.
142              
143             =cut
144              
145             sub max_generation {
146 1     1 1 2 my $self = shift;
147              
148 1         44 return max(map { $_->generation } $self->all_people);
  1         32  
149             }
150              
151             =head2 events_in_timeline
152              
153             Returns the number of events expected in the timeline. This isn't just the
154             number of events (i.e. people) that have been added to the timeline. In
155             genealogy, we often don't know some of our ancestry (children being born out
156             of wedlock is far more common than you might think) and we need to leave space
157             for those people or the chart will look wrong.
158              
159             So we calculate the number of expected people from the number of generations
160             in the timeline.
161              
162             =cut
163              
164             sub events_in_timeline {
165 1     1 1 2 my $self = shift;
166              
167 1         4 return 2 ** $self->max_generation - 1;
168             }
169              
170             override 'max_year' => sub {
171             return super() // localtime->year;
172             };
173              
174             =head1 AUTHOR
175              
176             Dave Cross <dave@perlhacks.com>
177              
178             =head1 COPYRIGHT AND LICENCE
179              
180             Copyright (c) 2017, Magnum Solutions Ltd. All Rights Reserved.
181              
182             This library is free software; you can redistribute it and/or modify it
183             under the same terms as Perl itself.
184              
185             =cut
186              
187              
188             1;