前言
當項目需要將一個highchart圖表以郵件發送的時候,js+css形式的highcharts 圖表肯定是不好做的,有查可以借助flash去執行js,但很麻煩,所以折中將highchart圖表轉為圖片。並且這個郵件里可能有幾十個這樣的圖表,在瀏覽器端生成圖片再上傳發送的方案也不可取,所以選擇直接在服務端生成highchart圖表。
服務端圖表其實也有PChart之類的直接在服務端生成圖片的,不過那圖片效果實在不敢恭維。最后找到了phantomjs+highchart的方式生成highchart圖表,圖表美觀。
參考: http://www.highcharts.com/articles/2-news/56-improved-image-export-with-phantomjs
phantomjs 是一個服務端JavaScript執行引擎。
phantomjs + highchart支持兩種方式,一種是命令行方式,一種是server方式。在使用命令行方式造成進程數過多把服務器整掛一次后,我換成了phantomjs Server的方式,這種方式效果好,所以下面的示例也使用的是phantomjs server
安裝phantomjs
可以編譯安裝也可以直接下載rpm,或者下載已經靜態編譯可以直接執行的二進制文件。這三者我都做過,最后因為要安裝的機器比較多,每台機器還有點區別,有的編譯成功有的編譯失敗,最后懶惰的我直接找到了可以直接下載使用的phantomjs二進制可執行文件。
安裝完之后,在demo根目錄下行執行以下命令啟動phantomjs server
phantomjs highcharts-convert.js -host 127.0.0.1 -port 3003
其中demo目錄下有這些文件,其中highcharts-convert.js文件能夠使用的網上已經非常難找了,需要的可以聯系我。
highcharts-convert.js highcharts.js highcharts-more.js highstock.js jquery-1.8.3.min.js loadspeed.js rasterize.js
DEMO
下面編寫測試代碼
1 <?php 2 3 $options = array('chart' => array('type' => 'spline', 'width' => '500', 'height' => '300', 'style' => array('fontFamily' => 'consolas,Console,SimSun'), 'backgroundColor' => '#F5F8F9'), 'tooltip' => array('valueSuffix' => '%'), 'colors' => array('#3366CC', '#097138', '#AB0'), 'credits' => array('enabled' => 0), 'yAxis' => array('title' => array('text' => '百分比(%)'), 'plotLines' => array(0 => array('value' => 0, 'width' => 1, 'color' => '#808080'))), 'title' => array('text' => '視頻下載成功率3G'), 'xAxis' => array('categories' => array('1-22', '1-23', '1-24', '1-25', '1-26', '1-27', '1-28')), 'series' => array(0 => array('name' => 'Android版(6.0 正式)6.0.1.288', 'data' => array(0, 100, 100, 0, 0, 100, 0)), 1 => array('name' => 'Android版(5.8正式)5.8.1.288', 'data' => array(96.75, 96.90000000000001, 89.3, 81.16, 97.23, 92.59, 98.73999999999999)), 2 => array('name' => 'Android版(5.7正式換包)5.7.1.289', 'data' => array(96.55, 25, 91.08, 100, 100, 0, 97.14)))); 4 5 6 $optionsJson = json_encode($options); 7 $imgFile = dirname(__FILE__) . '/' . md5($optionsJson) . '.png'; 8 $curl = curl_init('127.0.0.1:3003'); 9 curl_setopt($curl, CURLOPT_POST, true); 10 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 11 $postData = json_encode(array( 12 'infile' => preg_replace('/\"(\w+)\"\:/', '${1}:', $optionsJson), 13 'outfile' => $imgFile, 14 )); 15 curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); 16 $resp = curl_exec($curl);
參數細節
請注意上面的
1 $postData = json_encode(array( 2 'infile' => preg_replace('/\"(\w+)\"\:/','${1}:',$optionsJson), 3 'outfile' => $imgFile 4 ));
第2行中的infile為什么要這么寫呢?因為傳遞給highchart-convert.js的infile需要的參數,並不是標准的json,這個不仔細看真注意不到。
可以仔細看 http://www.highcharts.com/articles/2-news/56-improved-image-export-with-phantomjs 參數說明
"{"infile":"{xAxis: {categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']},series: [{data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}]};","callback":"function(chart) {chart.renderer.arc(200, 150, 100, 50, -Math.PI, 0).attr({fill : '#FCFFC5',stroke : 'black','stroke-width' : 1}).add();}","constr":"Chart","outfile":"//tmp//chart.png"}"
可以上面紅色的代碼,並不是json而是js對象格式。
上面有preg_replace替換的php代碼得到的是就是這樣的json
{"infile":"{chart:{type:\"spline\",width:\"500\",height:\"300\",style:{fontFamily:\"consolas,Console,SimSun\"},backgroundColor:\"#F5F8F9\"},tooltip:{valueSuffix:\"%\"},colors:[\"#3366CC\",\"#097138\",\"#AB0\"],credits:{enabled:0},yAxis:{title:{text:\"\\u767e\\u5206\\u6bd4\\uff08%\\uff09\"},plotLines:[{value:0,width:1,color:\"#808080\"}]},title:{text:\"\\u89c6\\u9891\\u4e0b\\u8f7d\\u6210\\u529f\\u73873G\"},xAxis:{categories:[\"1-22\",\"1-23\",\"1-24\",\"1-25\",\"1-26\",\"1-27\",\"1-28\"]},series:[{name:\"Android\\u7248(6.0 \\u6b63\\u5f0f)6.0.1.288\",data:[0,100,100,0,0,100,0]},{name:\"Android\\u7248(5.8\\u6b63\\u5f0f)5.8.1.288\",data:[96.75,96.9,89.3,81.16,97.23,92.59,98.74]},{name:\"Android\\u7248(5.7\\u6b63\\u5f0f\\u6362\\u5305)5.7.1.289\",data:[96.55,25,91.08,100,100,0,97.14]}]}","outfile":"\/home\/wwwroot\/demo.qq.com\/25afeab1d3e957b8beb4c58ea79c6ebd.png"}
轉成js對象可以看到是這樣的
如果不像上面那樣寫,而是直接寫成
1 $postData = json_encode(array( 2 'infile' => $options, 3 'outfile' => $imgFile 4 ));
得到的json是這樣的
{"infile":{"chart":{"type":"spline","width":"500","height":"300","style":{"fontFamily":"consolas,Console,SimSun"},"backgroundColor":"#F5F8F9"},"tooltip":{"valueSuffix":"%"},"colors":["#3366CC","#097138","#AB0"],"credits":{"enabled":0},"yAxis":{"title":{"text":"\u767e\u5206\u6bd4\uff08%\uff09"},"plotLines":[{"value":0,"width":1,"color":"#808080"}]},"title":{"text":"\u89c6\u9891\u4e0b\u8f7d\u6210\u529f\u73873G"},"xAxis":{"categories":["1-22","1-23","1-24","1-25","1-26","1-27","1-28"]},"series":[{"name":"Android\u7248(6.0 \u6b63\u5f0f)6.0.1.288","data":[0,100,100,0,0,100,0]},{"name":"Android\u7248(5.8\u6b63\u5f0f)5.8.1.288","data":[96.75,96.9,89.3,81.16,97.23,92.59,98.74]},{"name":"Android\u7248(5.7\u6b63\u5f0f\u6362\u5305)5.7.1.289","data":[96.55,25,91.08,100,100,0,97.14]}]},"outfile":"\/home\/wwwroot\/demo.qq.com\/25afeab1d3e957b8beb4c58ea79c6ebd.png"}
換成js對象是這樣的
而且請求發送給phantomjs執行會出錯
這是一個坑
輸出
如果參數不指定outfile,那么curl_exec 得到的響應resp就是圖片數據的base64編碼數據。可以直接decode輸出
亂碼問題
另外,服務器端生成圖表,一定要為Linux安裝bitmap字體,否則會得到下面這樣的亂碼圖片
安裝的方式很簡單
yum install bitmap-fonts bitmap-fonts-cjk
然后就能得到正常的圖表了
另外再給系統安裝一些其余漂亮的中文字體,在highchart中可以指定中文字體,讓圖表更加漂亮。
注:因為寫博客的時間與做這個事情的時間相距較遠,輸出的圖片與代碼數據並不匹配,見諒。