package HTML::TagCloud::Extended;
use strict;
use warnings;
use base qw/Class::Data::Inheritable Class::Accessor::Fast/;
use Readonly;
use HTML::TagCloud::Extended::TagColors;
use HTML::TagCloud::Extended::TagList;
use HTML::TagCloud::Extended::Tag;
use HTML::TagCloud::Extended::Factor;
use HTML::TagCloud::Extended::Exception;
our $VERSION = '0.10';
Readonly my $DEFAULT_BASE_FONT_SIZE => 24;
Readonly my $DEFAULT_FONT_SIZE_RANGE => 12;
Readonly my $DEFAULT_CSS_CLASS => "tagcloud";
Readonly my $DEFAULT_SIZE_SUFFIX => "px";
__PACKAGE__->mk_classdata('_epoch_level');
__PACKAGE__->_epoch_level([qw/earliest earlier later latest/]);
__PACKAGE__->mk_accessors(qw/
colors
tags
base_font_size
font_size_range
css_class
use_hot_color
hot_tags_size
_size_suffix
_hot_tags_name
/);
sub new {
my $class = shift;
my $self = bless { }, $class;
$self->_init(@_);
return $self;
}
sub _init {
my $self = shift;
$self->_set_default_parameters();
$self->_set_custom_parameters(@_);
$self->colors ( HTML::TagCloud::Extended::TagColors->new );
$self->tags ( HTML::TagCloud::Extended::TagList->new );
}
sub hot_tags_name {
my $self = shift;
if($_[0]) {
my $tags = ref $_[0] ? $_[0] : [@_];
$self->_hot_tags_name($tags);
}
return $self->_hot_tags_name;
}
sub _check_hot_tag_name {
my ($self, $name) = @_;
foreach my $tag_name ( @{ $self->hot_tags_name } ) {
return 1 if $name eq $tag_name;
}
return 0;
}
sub _set_default_parameters {
my $self = shift;
$self->base_font_size ( $DEFAULT_BASE_FONT_SIZE );
$self->font_size_range ( $DEFAULT_FONT_SIZE_RANGE );
$self->css_class ( $DEFAULT_CSS_CLASS );
$self->_size_suffix ( $DEFAULT_SIZE_SUFFIX );
}
sub _set_custom_parameters {
my ($self, %args) = @_;
if ( exists $args{base_font_size} ) {
$self->base_font_size($args{base_font_size});
}
if ( exists $args{font_size_range} ) {
$self->font_size_range($args{font_size_range});
}
if ( exists $args{css_class} ) {
$self->css_class($args{css_class});
}
if ( exists $args{hot_tags_size} ) {
$self->hot_tags_size($args{hot_tags_size});
}
else {
my $size = $self->base_font_size + ($self->font_size_range / 2);
$self->hot_tags_size($size);
}
if ( exists $args{size_suffix} ) {
$self->size_suffix($args{size_suffix});
}
$self->_hot_tags_name( exists $args{hot_tags_name} ? $args{hot_tags_name} : [] );
$self->use_hot_color ( exists $args{use_hot_color} ? $args{use_hot_color} : undef );
}
sub size_suffix {
my ($self, $suffix) = @_;
if ($suffix) {
my $correct_suffix;
foreach my $registered ( qw/mm cm in pt pc px/ ) {
$correct_suffix = $suffix if $suffix eq $registered;
}
if ($correct_suffix) {
$self->_size_suffix($correct_suffix);
}
else {
HTML::TagCloud::Extended::Exception->throw(
qq/You should correct suffix for text-size [ mm cm in pt pc px ]. /
);
}
}
$self->_size_suffix;
}
sub add {
my($self, $tag_name, $url, $count, $timestamp) = @_;
my $tag = HTML::TagCloud::Extended::Tag->new(
name => $tag_name || '',
url => $url || '',
count => $count || 0,
timestamp => $timestamp,
);
$self->tags->add($tag);
}
sub max_font_size {
my $self = shift;
return $self->base_font_size + $self->font_size_range;
}
sub min_font_size {
my $self = shift;
my $num = $self->base_font_size - $self->font_size_range;
return $num > 0 ? $num : 0;
}
sub html_and_css {
my ($self, $conf) = @_;
my $html = qq|\n|;
$html .= $self->html($conf);
return $html;
}
sub css {
my $self = shift;
my $css = '';
foreach my $type ( keys %{ $self->colors } ) {
my $color = $self->colors->{$type};
my $class = $self->css_class;
foreach my $attr ( keys %$color ) {
my $code = $color->{$attr};
$css .= ".${class} .${type} a:${attr} {text-decoration: none; color: #${code};}\n";
}
}
return $css;
}
sub html {
my ($self, $conf) = @_;
my $html_tags = $self->html_tags($conf);
my $html = join "", @$html_tags;
return $self->wrap_div($html);
}
sub wrap_span {
my($self, $html) = @_;
return "" unless $html;
return sprintf qq|\n%s\n|, $self->css_class, $html;
}
sub wrap_div {
my($self, $html) = @_;
return "" unless $html;
return sprintf qq|
\n%s
\n|, $self->css_class, $html;
}
sub html_tags {
my($self, $conf) = @_;
my $tags_amount = $self->tags->count;
if ($tags_amount == 0) {
return [];
} elsif ($tags_amount == 1) {
my $ite = $self->tags->iterator;
my $tag = $ite->first;
my $html = $self->create_html_tag($tag, 'latest', $self->max_font_size);
return [$html];
}
$conf ||= {};
my $order_by = $conf->{order_by} || 'name';
$self->tags->sort($order_by);
my $limit = $conf->{limit};
my $tags = $limit ? $self->tags->splice(0, $limit) : $self->tags;
my $count_factor = HTML::TagCloud::Extended::Factor->new(
min => $tags->min_count,
max => $tags->max_count,
range => $self->max_font_size - $self->min_font_size,
);
my $epoch_factor = HTML::TagCloud::Extended::Factor->new(
min => $tags->min_epoch,
max => $tags->max_epoch,
range => 3,
);
my @html_tags = ();
my $ite = $tags->iterator;
while( my $tag = $ite->next ) {
my $count_lv = $count_factor->get_level($tag->count);
my $epoch_lv = $epoch_factor->get_level($tag->epoch);
my $color_type = $self->_epoch_level->[$epoch_lv];
my $font_size = $self->min_font_size + $count_lv;
if ( ( $self->use_hot_color eq 'name' && $self->_check_hot_tag_name($tag->name) )
|| ( $self->use_hot_color eq 'size' && $font_size >= $self->hot_tags_size ) ) {
$color_type = 'hot';
}
my $html_tag = $self->create_html_tag($tag, $color_type, $font_size);
push @html_tags, $html_tag;
}
return \@html_tags;
}
sub create_html_tag {
my($self, $tag, $type, $size) = @_;
return sprintf qq|%s\n|,
$type,
$size,
$self->size_suffix,
$tag->url,
$tag->name;
}
1;
__END__
=head1 NAME
HTML::TagCloud::Extended - HTML::TagCloud extension
=head1 SYNOPSIS
use HTML::TagCloud::Extended;
my $cloud = HTML::TagCloud::Extended->new();
$cloud->add($tag1, $url1, $count1, $timestamp1);
$cloud->add($tag2, $url2, $count2, $timestamp2);
$cloud->add($tag3, $url3, $count3, $timestamp3);
my $html = $cloud->html_and_css( {
order_by => 'count_desc',
limit => 20,
} );
print $html;
=head1 DESCRIPTION
This is extension of L.
This module allows you to register timestamp with tags.
And color of tags will be changed according to it's timestamp.
Now, this doesn't depend on L.
=head1 TIMESTAMP
When you call 'add()' method, set timestamp as last argument.
$cloud->add('perl','http://www.perl.org/', 20, '2005-07-15 00:00:00');
=head2 FORMAT
follow three types of format are allowed.
=over 4
=item 2005-07-15 00:00:00
=item 2005/07/15 00:00:00
=item 20050715000000
=back
=head1 COLORS
This module chooses color from follow four types according to tag's timestamp.
=over 4
=item earliest
=item earlier
=item later
=item latest
=back
You needn't to set colors because the default colors are set already.
But when you want to set colors by yourself, of course, you can.
my $cloud = HTML::TagCloud::Extended->new;
$cloud->colors->set(
earliest => '#000000',
);
$cloud->colors->set(
earlier => '#333333',
later => '#999999',
latest => '#cccccc',
);
# or, you can set color for each attribute
$cloud->colors->set(
earliest => {
link => '#000000',
hover => '#CCCCCC',
visited => '#333333',
active => '#666666',
},
);
=head1 LIMITTING
When you want to limit the amount of tags, 'html()', html_and_css()'
need second argument as hash reference.
$cloud->html_and_css( { order_by => 'timestamp_desc' , limit => 20 } );
=head2 SORTING TYPE
default is 'name'
=over 4
=item name
=item name_desc
=item count
=item count_desc
=item timestamp
=item timestamp_desc
=back
=head1 OTHER FEATURES
=over 4
=item use_hot_color
set by size
my $cloud = HTML::TagCloud::Extended->new(
use_hot_color => 'size',
hot_tags_size => 24,
);
# or set with accessor method
my $cloud = HTML::TagCloud::Extended->new;
$cloud->use_hot_color('size');
$cloud->hot_tags_size(24);
Then, tags that's size is over 24 applys color for 'hot'.
If you omit 'hot_tags_size', it'll be proper number automatically.
set by name
my $cloud = HTML::TagCloud::Extended->new(
use_hot_color => 'name',
hot_tags_name => [ 'perl', 'ruby', 'python' ],
);
# or set with accessor method
my $cloud = HTML::TagCloud::Extended->new;
$cloud->use_hot_color('name');
$cloud->hot_tags_name('perl', 'ruby', 'puthon');
You can alse change colors for 'hot' by yourself.
$cloud->colors->set( hot => '#ff9900' );
# or
$cloud->colors->set(
hot => {
link => '#000000',
hover => '#CCCCCC',
visited => '#333333',
active => '#666666',
},
);
=item base_font_size
default size is 24
# set as constructor's argument
my $cloud = HTML::TagCloud::Extended->new(
base_font_size => 30,
);
# or you can use accessor.
$cloud->base_font_size(30);
=item size_suffix
default suffix is 'px'
You can choose it from [ mm cm in pt pc px ].
# set as constructor's argument
my $cloud = HTML::TagCloud::Extended->new(
size_suffix => 'pt',
);
# or you can use accessor.
$cloud->size_suffix('cm');
=item font_size_range
defualt range is 12.
my $cloud = HTML::TagCloud::Extended->new(
font_size_range => 10
);
$cloud->font_size_range(10);
=item css_class
default name is 'tagcloud'
my $cloud = HTML::TagCloud::Extended->new(
css_class => 'mycloud',
);
$cloud->css_class('mycloud');
=back
=head1 SEE ALSO
L
=head1 AUTHOR
Lyo Kato Elyo.kato@gmail.comE
=head1 COPYRIGHT AND LICENSE
This library is free software. You can redistribute it and/or
modify it under the same terms as perl itself.
=cut