1<?php 2/** 3 * 4 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 5 * @author Andreas Gohr <andi@splitbrain.org> 6 */ 7 8if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 9if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 10require_once(DOKU_PLUGIN.'syntax.php'); 11 12 13/** 14 * All DokuWiki plugins to extend the parser/rendering mechanism 15 * need to inherit from this class 16 */ 17class syntax_plugin_gchart extends DokuWiki_Syntax_Plugin { 18 19 private $supported_charts = array( 20 'qr' => 'qr', 21 'pie' => 'p3', 22 'pie3d' => 'p3', 23 'pie2d' => 'p', 24 'line' => 'lc', 25 'spark' => 'ls', 26 'sparkline' => 'ls', 27 'bar' => 'bvs', 28 'hbar' => 'bhs', 29 'vbar' => 'bvs', 30 ); 31 32 /** 33 * What kind of syntax are we? 34 */ 35 function getType(){ 36 return 'substition'; 37 } 38 39 function getPType(){ 40 return 'block'; 41 } 42 43 /** 44 * Where to sort in? 45 */ 46 function getSort(){ 47 return 160; 48 } 49 50 /** 51 * Connect pattern to lexer 52 */ 53 function connectTo($mode) { 54 $this->Lexer->addSpecialPattern('<gchart.*?>\n.*?\n</gchart>',$mode,'plugin_gchart'); 55 } 56 57 /** 58 * Handle the match 59 */ 60 function handle($match, $state, $pos, Doku_Handler $handler){ 61 62 // prepare default data 63 $return = array( 64 'type' => 'p3', 65 'data' => array(), 66 'width' => 320, 67 'height' => 140, 68 'align' => 'right', 69 'legend' => false, 70 'value' => false, 71 'title' => '', 72 'fg' => ltrim($this->getConf('fg'),'#'), 73 'bg' => ltrim($this->getConf('bg'),'#'), 74 ); 75 76 // prepare input 77 $lines = explode("\n",$match); 78 $conf = array_shift($lines); 79 array_pop($lines); 80 81 // parse adhoc configs 82 if(preg_match('/"([^"]+)"/',$conf,$match)){ 83 $return['title'] = $match[1]; 84 $conf = preg_replace('/"([^"]+)"/','',$conf); 85 } 86 if(preg_match('/\b(left|center|right)\b/i',$conf,$match)){ 87 $return['align'] = strtolower($match[1]); 88 } 89 if(preg_match('/\b(legend)\b/i',$conf,$match)){ 90 $return['legend'] = true; 91 } 92 if(preg_match('/\b(values?)\b/i',$conf,$match)){ 93 $return['value'] = true; 94 } 95 if(preg_match('/\b(\d+)x(\d+)\b/',$conf,$match)){ 96 $return['width'] = $match[1]; 97 $return['height'] = $match[2]; 98 } 99 100 $type_regex = '/\b(' . join('|', array_keys($this->supported_charts)) . ')\b/i'; 101 if(preg_match($type_regex,$conf,$match)){ 102 $return['type'] = $this->supported_charts[strtolower($match[1])]; 103 } 104 if(preg_match_all('/#([0-9a-f]{6}([0-9a-f][0-9a-f])?)\b/i',$conf,$match)){ 105 if(isset($match[1][0])){ 106 $return['fg'] = $match[1][0]; 107 } 108 if(isset($match[1][1])){ 109 $return['bg'] = $match[1][1]; 110 } 111 } 112 113 // parse chart data 114 $data = array(); 115 foreach ( $lines as $line ) { 116 //ignore comments (except escaped ones) 117 $line = preg_replace('/(?<![&\\\\])#.*$/','',$line); 118 $line = str_replace('\\#','#',$line); 119 $line = trim($line); 120 if(empty($line)){ 121 continue; 122 } 123 $line = preg_split('/(?<!\\\\)=/',$line,2); //split on unescaped equal sign 124 $line[0] = str_replace('\\=','=',$line[0]); 125 $line[1] = str_replace('\\=','=',$line[1]); 126 $data[trim($line[0])] = trim($line[1]); 127 } 128 $return['data'] = $data; 129 130 return $return; 131 } 132 133 /** 134 * Create output 135 */ 136 function render($mode, Doku_Renderer $R, $data) { 137 if ($mode != 'xhtml') { 138 return false; 139 } 140 141 $val = array_map('floatval', array_values($data['data'])); 142 $max = max(0, ceil(max($val))); 143 $min = min(0, floor(min($val))); 144 $key = array_keys($data['data']); 145 146 $url = 'https://chart.apis.google.com/chart?'; 147 $parameters = array(); 148 149 $parameters['cht'] = $data['type']; 150 if($data['bg']) { 151 $parameters['chf'] = 'bg,s,'.$data['bg']; 152 } 153 if($data['fg']) { 154 $parameters['chco'] = $data['fg']; 155 } 156 $parameters['chs'] = $data['width'].'x'.$data['height']; # size 157 $parameters['chd'] = 't:'.join(',',$val); 158 $parameters['chds'] = $min.','.$max; 159 $parameters['choe'] = 'UTF-8'; 160 if($data['title']) { 161 $parameters['chtt'] = $data['title']; 162 } 163 164 switch($data['type']){ 165 case 'bhs': # horizontal bar 166 $parameters['chxt'] = 'y'; 167 $parameters['chxl'] = '0:|'.join('|',array_reverse($key)); 168 $parameters['chbh'] = 'a'; 169 if($data['value']) { 170 $parameters['chm'] = 'N*f*,333333,0,-1,11'; 171 } 172 break; 173 case 'bvs': # vertical bar 174 $parameters['chxt'] = 'y,x'; 175 $parameters['chxr'] = '0,'.$min.','.$max; 176 $parameters['chxl'] = '1:|'.join('|',$key); 177 $parameters['chbh'] = 'a'; 178 if($data['value']) { 179 $parameters['chm'] = 'N*f*,333333,0,-1,11'; 180 } 181 break; 182 case 'lc': # line graph 183 $parameters['chxt'] = 'y,x'; 184 $parameters['chxr'] = '0,'.floor(min($min,0)).','.ceil($max); 185 $parameters['chxl'] = '1:|'.join('|',$key); 186 if($data['value']) { 187 $parameters['chm'] = 'N*f*,333333,0,-1,11'; 188 } 189 break; 190 case 'ls': # spark line 191 if($data['value']) { 192 $parameters['chm'] = 'N*f*,333333,0,-1,11'; 193 } 194 break; 195 case 'p3': # pie graphs 196 case 'p': 197 if($data['legend']){ 198 $parameters['chdl'] = join('|',$key); 199 if($data['value']){ 200 $parameters['chl'] = join('|',$val); 201 } 202 }else{ 203 if($data['value']){ 204 $cnt = count($key); 205 for($i = 0; $i < $cnt; $i++){ 206 $key[$i] .= ' ('.$val[$i].')'; 207 } 208 } 209 $parameters['chl'] = join('|',$key); 210 } 211 break; 212 case 'qr': 213 $rawval = array_keys($data['data']); 214 if (in_array($rawval[0], ['L', 'M', 'Q', 'H'])) { 215 $parameters['chld'] = array_shift($rawval); 216 } 217 unset($parameters['chd']); 218 unset($parameters['chds']); 219 $parameters['chl'] = join(';', $rawval); 220 break; 221 } 222 223 $url .= http_build_query($parameters, '', '&') . '&.png'; 224 225 $align = ''; 226 if($data['align'] == 'left') { 227 $align=' align="left"'; 228 } elseif($data['align'] == 'right') { 229 $align=' align="right"'; 230 } 231 232 $R->doc .= '<img src="'.ml($url).'" class="media'.$data['align'].'" alt="" width="'.$data['width'].'" height="'.$data['height'].'"'.$align.' />'; 233 234 return true; 235 } 236} 237 238//Setup VIM: ex: et ts=4 enc=utf-8 : 239