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 => "preprocess", id => "sparkline", call => \&preprocess);
21 sub preprocess (@) { #{{{
26 my $style=(exists $params{style} && $params{style} eq "bar") ? "Bar" : "Line";
28 require_once('sparkline/Sparkline_$style.php');
29 \$sparkline = new Sparkline_$style();
30 \$sparkline->SetDebugLevel(DEBUG_NONE);
33 foreach my $param (qw{BarWidth BarSpacing YMin YMaz}) {
34 if (exists $params{lc($param)}) {
35 $php.=qq{\$sparkline->Set$param(}.int($params{lc($param)}).qq{);\n};
44 if ($key=~/^($match_num)(?:,($match_num))?(?:\(([a-z]+)\))?$/) {
55 if ($style eq "Bar" && defined $3) {
56 $php.=qq{\$sparkline->SetData($x, $y, '$3');\n};
59 $php.=qq{\$sparkline->SetData($x, $y);\n};
62 elsif (! length $value) {
63 return "[[sparkline ".gettext("parse error")." \"$key\"]]";
65 elsif ($key eq 'featurepoint') {
66 my ($x, $y, $color, $diameter, $text, $location)=
67 split(/\s*,\s*/, $value);
68 if (! defined $diameter || $diameter < 0) {
69 return "[[sparkline ".gettext("bad featurepoint diameter")."]]";
74 $diameter=int($diameter);
75 $text=~s/[^-a-zA-Z0-9]+//g if defined $text;
76 if (defined $location) {
77 $location=$locmap{$location};
78 if (! defined $location) {
79 return "[[sparkline ".gettext("bad featurepoint location")."]]";
82 $php.=qq{\$sparkline->SetFeaturePoint($x, $y, '$color', $diameter};
83 $php.=qq{, '$text'} if defined $text;
84 $php.=qq{, $location} if defined $location;
90 return "[[sparkline ".gettext("missing values")."]]";
93 my $height=int($params{height} || 20);
94 if ($height < 2 || $height > 100) {
95 return "[[sparkline ".gettext("bad height value")."]]";
97 if ($style eq "Bar") {
98 $php.=qq{\$sparkline->Render($height);\n};
101 if (! exists $params{width}) {
102 return "[[sparkline ".gettext("missing width parameter")."]]";
104 my $width=int($params{width});
105 if ($width < 2 || $width > 1024) {
106 return "[[sparkline ".gettext("bad width value")."]]";
108 $php.=qq{\$sparkline->RenderResampled($width, $height);\n};
111 $php.=qq{\$sparkline->Output();\n?>\n};
113 # Use the sha1 of the php code that generates the sparkline as
114 # the base for its filename.
115 eval q{use Digest::SHA1};
117 my $fn=$params{page}."/sparkline-".
118 IkiWiki::possibly_foolish_untaint(Digest::SHA1::sha1_hex($php)).
120 will_render($params{page}, $fn);
122 if (! -e "$config{destdir}/$fn") {
125 $SIG{PIPE}=sub { $sigpipe=1 };
126 $pid=open2(*IN, *OUT, "php");
128 # open2 doesn't respect "use open ':utf8'"
129 binmode (OUT, ':utf8');
142 $SIG{PIPE}="DEFAULT";
144 return "[[sparkline ".gettext("failed to run php")."]]";
147 if (! $params{preview}) {
148 writefile($fn, $config{destdir}, $png, 1);
151 # can't write the file, so embed it in a data uri
152 eval q{use MIME::Base64};
154 return "<img src=\"data:image/png;base64,".
155 encode_base64($png)."\" />";
159 return '<img src="'.urlto($fn, $params{destpage}).'" alt="graph" />';