File Coverage

blib/lib/Chart/Kaleido/Plotly.pm
Criterion Covered Total %
statement 66 76 86.8
branch 7 12 58.3
condition n/a
subroutine 17 24 70.8
pod 2 5 40.0
total 92 117 78.6


line stmt bran cond sub pod time code
1             package Chart::Kaleido::Plotly;
2              
3             # ABSTRACT: Export static images of Plotly charts using Kaleido
4              
5 1     1   215366 use 5.010;
  1         7  
6 1     1   5 use strict;
  1         1  
  1         16  
7 1     1   3 use warnings;
  1         2  
  1         29  
8              
9             our $VERSION = '0.012'; # VERSION
10              
11 1     1   519 use Moo;
  1         10472  
  1         4  
12             extends 'Chart::Kaleido';
13              
14 1     1   1662 use File::ShareDir;
  1         22239  
  1         37  
15 1     1   6 use JSON;
  1         1  
  1         9  
16 1     1   1105 use MIME::Base64 qw(decode_base64);
  1         1600  
  1         56  
17 1     1   7 use Path::Tiny;
  1         1  
  1         40  
18 1     1   422 use Safe::Isa;
  1         471  
  1         96  
19 1     1   507 use Type::Params 1.004000 qw(compile_named_oo);
  1         91711  
  1         12  
20 1     1   756 use Types::Path::Tiny qw(File Path);
  1         28591  
  1         7  
21 1     1   461 use Types::Standard qw(Int Str Num HashRef InstanceOf Optional Undef);
  1         3  
  1         5  
22 1     1   1693 use namespace::autoclean;
  1         13376  
  1         3  
23              
24              
25             my @text_formats = qw(svg json eps);
26              
27              
28             my $default_plotlyjs = sub {
29             my $plotlyjs;
30             eval {
31             $plotlyjs = File::ShareDir::dist_file( 'Chart-Plotly',
32             'plotly.js/plotly.min.js' );
33             };
34             return $plotlyjs;
35             };
36              
37             has plotlyjs => (
38             is => 'ro',
39             isa => ( Str->plus_coercions( Undef, $default_plotlyjs ) | Undef ),
40             default => $default_plotlyjs,
41             coerce => 1,
42             );
43              
44             has [qw(mathjax topojson)] => (
45             is => 'ro',
46             isa => ( Str | Undef ),
47             coerce => 1,
48             );
49              
50             has mapbox_access_token => (
51             is => 'ro',
52             isa => ( Str | Undef ),
53             );
54              
55              
56             my $PositiveInt = Int->where( sub { $_ > 0 } );
57              
58             has default_format => (
59             is => 'ro',
60             isa => Str,
61             default => 'png',
62             );
63              
64             has default_width => (
65             is => 'ro',
66             isa => $PositiveInt,
67             default => 700,
68             );
69              
70             has default_height => (
71             is => 'ro',
72             isa => $PositiveInt,
73             default => 500,
74             );
75              
76             has '+base_args' => (
77             default => sub {
78             my $self = shift;
79             [ "plotly", @{ $self->_default_chromium_args }, "--no-sandbox" ];
80             }
81             );
82              
83 2     2 0 13 sub all_formats { [qw(png jpg jpeg webp svg pdf eps json)] }
84 0     0 0 0 sub scope_name { 'plotly' }
85 4     4 0 20 sub scope_flags { [qw(plotlyjs mathjax topojson mapbox_access_token)] }
86              
87              
88             sub transform {
89 2     2 1 6 my $self = shift;
90             state $check = compile_named_oo(
91             #<<< no perltidy
92             plot => ( HashRef | InstanceOf["Chart::Plotly::Plot"] ),
93 0     0   0 format => Optional[Str], { default => sub { $self->default_format } },
94 0     0   0 width => $PositiveInt, { default => sub { $self->default_width } },
95 0     0   0 height => $PositiveInt, { default => sub { $self->default_height} },
96 2         5 scale => Num, { default => 1 },
97             #>>>
98             );
99 2         7076 my $arg = $check->(@_);
100 2 50       75 my $plot =
101             $arg->plot->$_isa('Chart::Plotly::Plot')
102             ? $arg->plot->TO_JSON
103             : $arg->plot;
104 2         56 my $format = lc( $arg->format );
105              
106 2 50       5 unless ( grep { $_ eq $format } @{ $self->all_formats } ) {
  16         33  
  2         23  
107             die "Invalid format '$format'. Supported formats: "
108 0         0 . join( ' ', @{ $self->all_formats } );
  0         0  
109             }
110              
111 2         19 my $data = {
112             format => $format,
113             width => $arg->width,
114             height => $arg->height,
115             scale => $arg->scale,
116             data => $plot,
117             };
118              
119 2     0   17 local *PDL::TO_JSON = sub { $_[0]->unpdl };
  0         0  
120 2         17 my $resp = $self->do_transform($data);
121 2 50       12 if ( $resp->{code} != 0 ) {
122 0         0 die $resp->{message};
123             }
124 2         16 my $img = $resp->{result};
125 2 100       7 return ( grep { $_ eq $format } @text_formats )
  6         382  
126             ? $img
127             : decode_base64($img);
128             }
129              
130              
131             sub save {
132 2     2 1 4133 my $self = shift;
133             state $check = compile_named_oo(
134             #<<< no perltidy
135             file => Path,
136             plot => ( HashRef | InstanceOf["Chart::Plotly::Plot"] ),
137             format => Optional[Str],
138 0     0   0 width => $PositiveInt, { default => sub { $self->default_width } },
139 0     0   0 height => $PositiveInt, { default => sub { $self->default_height} },
140 2         10 scale => Num, { default => 1 },
141             #>>>
142             );
143 2         41129 my $arg = $check->(@_);
144 2         58 my $format = $arg->format;
145 2         7 my $file = $arg->file;
146 2 50       9 unless ($format) {
147 2 50       9 if ( $file =~ /\.([^\.]+)$/ ) {
148 2         37 $format = $1;
149             }
150             }
151 2         23 $format = lc($format);
152              
153 2         25 my $img = $self->transform(
154             plot => $arg->plot,
155             format => $format,
156             width => $arg->width,
157             height => $arg->height,
158             scale => $arg->scale
159             );
160 2         48 path($file)->append_raw( { truncate => 1 }, $img );
161             }
162              
163             1;
164              
165             __END__