先说一下本人在工作中遇到的瓶颈
之前做过一个【霍兰德职业兴趣测试】测试的项目,大体结构就是用户答题,系统根据用户回答的问题进行职业性格测试,最后显示结果,在结果页存在一个类似于六芒星的能力分析图(这个是我自己起的名字,具体是叫什么我也不太清楚,下面将以“六芒星图”代替),起初我们用的是Echarts插件,本来相安无事。突然有一天,客户提了一个需求,需要把结果页实现一个长按保存的功能,我们计划用html2canvas实现,这时发现页面中使用Echarts生成的六芒星图在利用html2canvas时不能成功保存为图片,前端的同事们束手无策,好吧,工作丢给了我们PHP,欲哭无泪。我在各种网站中找资料,发现没有任何现成的代码(可能是我没有找到),好吧,自己写。之前由于时间比较紧,没有时间考虑其他的东西,用的是GD库的函数,别提多苦逼了。现在把整理好的代码放上来供大家参考,希望能帮到同样问题的小伙伴。
使用条件
由于之前使用GD库的代码实现的,后来发现GD库过于麻烦,而且性能简直不敢恭维,所以,后来完善代码的使用的是Imagick,所以需要安装这个控件,这篇文章也会将Imagick的安装方法简单介绍,如果不懂的小伙伴可以在自行百度其他答案。
Windows安装
ImageMagick下载地址(对照好VC库的版本)/downloads/pecl/deps/php扩展下载地址/package/imagick将ImageMagick的软件包下载好之后解压,然后将软件目录下的bin目录加入到环境变量中,不会设置环境变量的小伙伴请看这里测试ImageMagick是否安装成功,打开CMD命令,输入下面的命令(stream.ext -version),如果出现了版本信息证明已经安装成功了。将php的扩展包解压,然后将解压包中的php_imagick.dll文件及其他的.dll文件都复制到php目录的扩展控件目录下,修改配置文件,重启使之生效Linux安装(以CentOS为例)
使用yum安装ImageMagick与ImageMagick-devel(也可以使用源码编译安装,不过依赖有些麻烦,有兴趣的小伙伴可以研究一下),注意ImageMagick-devel这个必须安装,否则在安装php扩展时会报错。使用convert -v测试是否安装成功同样使用windows中的那个php扩展的地址,下载.tar文件,使用phpize编译安装,然后重启服务(如果PHP不是源码安装的小伙伴可以自行百度)。上代码
以下代码完全是本人自行编写,可能存在性能、资源上的不足,请各位大神多多指点,谢谢。
<?php/*** +--------------------------------------------------------* | 多边形能力分析图* +--------------------------------------------------------* | @author Renling* +--------------------------------------------------------* | @email gang888.@* +--------------------------------------------------------* | @date 22:14 /8/21* +--------------------------------------------------------* | @method* | PolygonChart::setLevelColor($color) 设置辅助区域的颜色* | $color array 5个颜色数据组成的数组 ,可参考PolygonChart::$levelFillColor* | PolygonChart::setSize($size) 设置图片大小* | PolygonChart::setNode($node) 设置边数* | PolygonChart::setGuideColor($color) 设置辅助线颜色* | PolygonChart::setMaxValue($color) 设置能力值* | PolygonChart::setAbilityLineColor($color) 设置能力轮廓线的颜色* | PolygonChart::setAbilityFillColor($color) 设置能力轮廓的填充颜色* | PolygonChart::setBackgroundColor($color) 设置图片的背景颜色* | PolygonChart::draw($data) 绘制图形* | $data array 元素数量与边数对应* +--------------------------------------------------------*/class PolygonChart{private $backgroundColor = 'rgba(255, 255, 255, 0)'; //设置图像的背景颜色private $levelFillColor = ['rgba(35, 135, 147, 0.5)','rgba(59, 162, 174, 0.5)','rgba(89, 182, 193, 0.5)','rgba(138, 206, 214, 0.5)','rgba(178, 226, 232, 0.5)'];//设置每个级别的多边形填充的颜色private $sideLength = 200;//图片的边长=多边形外接圆直径private $nodeNumber = 6; //节点的数量private $guideColor = '#217882';//辅助线的颜色private $nodeMaxValue = 100; //每个节点所代表的最大值private $abilityLineColor = '#aa604d'; //能力线的颜色private $abilityFillColor = 'rgba(227, 144, 62, 0.5)'; //能力图的填充颜色private $guideColorImagickPixel;//辅助线颜色资源private $circumscribedCircleRadius; //正多边形外接圆的半径private $points;//各点坐标存储/*** 设置图像的背景颜色* @author Renling* @date 17:22 /8/22** @access public* @param $color string 颜色值** @return $this*/public function setBackgroundColor($color){$this->backgroundColor = $color;return $this;}/*** 设置每个级别的多边形填充的颜色* @author Renling* @date 14:06 /8/22** @access public* @param $color array 每个级别的多边形填充的颜色** @return $this*/public function setLevelColor($color){$this->levelFillColor = $color;return $this;}/*** 设置图片大小* @author Renling* @date 14:08 /8/22** @access public* @param $size int 图片的大小** @return $this*/public function setSize($size){$this->sideLength = $size;return $this;}/*** 设置多边形的边数* @author Renling* @date 14:10 /8/22** @access public* @param $node int 多边形的节点数** @return $this*/public function setNode($node){$this->nodeNumber = $node;return $this;}/*** 设置辅助线颜色* @author Renling* @date 14:12 /8/22** @access public* @param $color string 颜色值** @return $this*/public function setGuideColor($color){$this->guideColor = $color;return $this;}/*** 设置每个能力的最大值* @author Renling* @date 14:13 /8/22** @access public* @param $value int 能力值** @return $this*/public function setMaxValue($value){$this->nodeMaxValue = $value;return $this;}/*** 设置能力轮廓线的颜色* @author Renling* @date 14:15 /8/22** @access public* @param $color string 颜色值** @return $this*/public function setAbilityLineColor($color){$this->abilityLineColor = $color;return $this;}/*** 设置能力轮廓的填充颜色* @author Renling* @date 14:17 /8/22** @access public* @param $color string 颜色值** @return $this*/public function setAbilityFillColor($color){$this->abilityFillColor = $color;return $this;}/*** 获取辅助线的颜色资源* @author Renling* @date 22:24 /8/21** @access private** @return ImagickPixel*/private function getGuideColor(){if (is_null($this->guideColorImagickPixel)) {$this->guideColorImagickPixel = new ImagickPixel($this->guideColor);}return $this->guideColorImagickPixel;}/*** 根据多变形等级绘制正多边形* @author Renling* @date 22:34 /8/21 0021** @access private* @param $level int 正多边形的等级 1-5,等级越高,多边形等级越大** @return ImagickDraw*/private function drawPolygon($level = 5){//根据正多边形的等级计算坐标中需要进行偏移的距离$offsetLength = (5-$level)*$this->circumscribedCircleRadius/5;//获取当前等级的外接圆半径$levelCircumscribedCircleRadius = $level*$this->circumscribedCircleRadius/5;//根据边数获取节点的坐标$points = [];//获取角度$angle = 360/$this->nodeNumber;//获取第一个点坐标$points[] = ['x' => $levelCircumscribedCircleRadius+$offsetLength, 'y' => $offsetLength];//当前临时变量为了优化代码,不做解释$coordinateTmp = $levelCircumscribedCircleRadius+$offsetLength;//遍历获取后面的sideNumber-1个节点的坐标for ($i=1; $i<$this->nodeNumber; $i++) {//当前临时变量为了优化代码,不做解释$angleTmp = deg2rad($i*$angle);$y = $coordinateTmp-round(cos($angleTmp)*$levelCircumscribedCircleRadius, 2);$x = $coordinateTmp+round(sin($angleTmp)*$levelCircumscribedCircleRadius, 2);$points[] = ['x' => $x, 'y' => $y];}$this->points[] = $points;//获取辅助线的颜色资源$guideColor = $this->getGuideColor();//获取辅助图像的填充颜色$fillColor = new ImagickPixel($this->levelFillColor[$level-1]);//实例化ImagickDraw$draw = new ImagickDraw();//设置透明度$draw->setStrokeOpacity(1);//设置辅助线的颜色$draw->setStrokeColor($guideColor);//设置边的宽度$draw->setStrokeWidth(1);//设置辅助图形的填充颜色$draw->setFillColor($fillColor);//绘制正多边形$draw->polygon($points);return $draw;}/*** 绘制中心点到最大多边形节点的连线* @author Renling* @date 17:17 /8/22** @access private** @return ImagickDraw*/public function drawCenterToMaxLine(){//绘制中心点到最大多边形节点的连线$draw = new ImagickDraw();//设置透明度$draw->setStrokeOpacity(1);//设置辅助线的颜色$draw->setStrokeColor($this->getGuideColor());//设置边的宽度$draw->setStrokeWidth(1);//获取最大外接圆的节点坐标$points = $this->points[0];foreach ($points as $nodeItem) {$draw->line($this->circumscribedCircleRadius, $this->circumscribedCircleRadius, $nodeItem['x'], $nodeItem['y']);}return $draw;}/*** 构建一个多边形的背景图* @author Renling* @date 22:26 /8/21** @access private** @return Imagick*/private function drawPolygonBkImage(){//构建图像资源$image = new Imagick();//对图像资源进行属性设置(宽 高 颜色)$image->newImage($this->sideLength, $this->sideLength, new ImagickPixel($this->backgroundColor));//设置图像资源图片格式(PNG)$image->setImageFormat("png");return $image;}/*** 绘制能力图像* @author Renling* @date 22:57 /8/21 0021** @access private* @param $data array 能力数据** @return ImagickDraw*/private function drawAbility($data){if (!is_array($data)) {return null;}//获取中心点坐标$centerPoint = ['x' => $this->circumscribedCircleRadius, 'y' => $this->circumscribedCircleRadius];//获取每个节点的最大外接圆的点坐标$maxCircumscribedCirclePoints = $this->points[0];//获取每项的值的节点坐标$dataPoints = [];foreach ($maxCircumscribedCirclePoints as $key => $maxCircumscribedCirclePointsItem) {if (!isset($data[$key]))$value = 0;else$value = $data[$key];if ($value<0)$value = 0;elseif ($value>$this->nodeMaxValue)$value = $this->nodeMaxValue;$dataPoints[] = ['x'=> round($centerPoint['x'] + ($maxCircumscribedCirclePointsItem['x'] - $centerPoint['x'])*$value/$this->nodeMaxValue, 2),'y'=> round($centerPoint['y'] + ($maxCircumscribedCirclePointsItem['y'] - $centerPoint['y'])*$value/$this->nodeMaxValue, 2),];}//构建一个多边形$draw = new ImagickDraw();//获取能力图形线的颜色资源$abilityLineColor = new ImagickPixel($this->abilityLineColor);//设置透明度$draw->setStrokeOpacity(1);//设置能力图形线的颜色$draw->setStrokeColor($abilityLineColor);//设置边的宽度$draw->setStrokeWidth(1);//设置填充颜色$draw->setFillColor(new ImagickPixel($this->abilityFillColor));//绘制能力多边形$draw->polygon($dataPoints);return $draw;}/*** 自动制作一个正多边形能力图* @author Renling* @date 22:37 /8/21** @access public* @param $data array 能力数据** @return Imagick*/public function draw($data){//设置正多边形外接圆的半径$this->circumscribedCircleRadius = $this->sideLength/2;//构建一个图像资源$image = $this->drawPolygonBkImage();//从大到小的依次绘制5个正多边形for ($level=5; $level>0; $level--) {$draw = $this->drawPolygon($level);$image->drawImage($draw);unset($draw);}$image->drawImage($this->drawCenterToMaxLine());//构建能力图形//将能力图形绘制到图片上$image->drawImage($this->drawAbility($data));return $image;}}
实例展示
<?phprequire '../PolygonChart.php';$chart = new PolygonChart;$image = $chart->draw([58, 63, 44, 45, 75, 56]);header('Content-Type:image/png');echo $image->getImageBlob();
效果图展示
<?phprequire '../PolygonChart.php';$chart = new PolygonChart;$image = $chart->setBackgroundColor('#ff0000')->setNode(5)->draw([58, 63, 44, 45, 75]);header('Content-Type:image/png');echo $image->getImageBlob();
效果图展示
还有很多其他的设置,欢迎小伙伴们尝试,如果有不足的地方,希望小伙伴们能够指正,谢谢。