2 package IkiWiki::Plugin::sparkline;
9 my $match_num=qr/[-+]?[0-9]+(?:\.[0-9]+)?/;
12 right => 'TEXT_RIGHT',
13 bottom => 'TEXT_BOTTOM',
18 hook(type => "getsetup", id => "sparkline", call => \&getsetup);
19 hook(type => "preprocess", id => "sparkline", call => \&preprocess);
35 my $style=(exists $params{style} && $params{style} eq "bar") ? "Bar" : "Line";
37 require_once('sparkline/Sparkline_$style.php');
38 \$sparkline = new Sparkline_$style();
39 \$sparkline->SetDebugLevel(DEBUG_NONE);
42 foreach my $param (qw{BarWidth BarSpacing YMin YMaz}) {
43 if (exists $params{lc($param)}) {
44 $php.=qq{\$sparkline->Set$param(}.int($params{lc($param)}).qq{);\n};
53 if ($key=~/^($match_num)(?:,($match_num))?(?:\(([a-z]+)\))?$/) {
64 if ($style eq "Bar" && defined $3) {
65 $php.=qq{\$sparkline->SetData($x, $y, '$3');\n};
68 $php.=qq{\$sparkline->SetData($x, $y);\n};
71 elsif (! length $value) {
72 error gettext("parse error")." \"$key\"";
74 elsif ($key eq 'featurepoint') {
75 my ($x, $y, $color, $diameter, $text, $location)=
76 split(/\s*,\s*/, $value);
77 if (! defined $diameter || $diameter < 0) {
78 error gettext("invalid featurepoint diameter");
83 $diameter=int($diameter);
84 $text=~s/[^-a-zA-Z0-9]+//g if defined $text;
85 if (defined $location) {
86 $location=$locmap{$location};
87 if (! defined $location) {
88 error gettext("invalid featurepoint location");
91 $php.=qq{\$sparkline->SetFeaturePoint($x, $y, '$color', $diameter};
92 $php.=qq{, '$text'} if defined $text;
93 $php.=qq{, $location} if defined $location;
99 error gettext("missing values");
102 my $height=int($params{height} || 20);
103 if ($height < 2 || $height > 100) {
104 error gettext("invalid height value");
106 if ($style eq "Bar") {
107 $php.=qq{\$sparkline->Render($height);\n};
110 if (! exists $params{width}) {
111 error gettext("missing width parameter");
113 my $width=int($params{width});
114 if ($width < 2 || $width > 1024) {
115 error gettext("invalid width value");
117 $php.=qq{\$sparkline->RenderResampled($width, $height);\n};
120 $php.=qq{\$sparkline->Output();\n?>\n};
122 # Use the sha1 of the php code that generates the sparkline as
123 # the base for its filename.
124 eval q{use Digest::SHA1};
126 my $fn=$params{page}."/sparkline-".
127 IkiWiki::possibly_foolish_untaint(Digest::SHA1::sha1_hex($php)).
129 will_render($params{page}, $fn);
131 if (! -e "$config{destdir}/$fn") {
134 $SIG{PIPE}=sub { $sigpipe=1 };
135 $pid=open2(*IN, *OUT, "php");
137 # open2 doesn't respect "use open ':utf8'"
138 binmode (OUT, ':utf8');
151 $SIG{PIPE}="DEFAULT";
152 if ($sigpipe || ! defined $png) {
153 error gettext("failed to run php");
156 if (! $params{preview}) {
157 writefile($fn, $config{destdir}, $png, 1);
160 # can't write the file, so embed it in a data uri
161 eval q{use MIME::Base64};
163 return "<img src=\"data:image/png;base64,".
164 encode_base64($png)."\" />";
168 return '<img src="'.urlto($fn, $params{destpage}).'" alt="graph" />';