PHP使用Imagick绘制六芒星能力图

先说一下本人在工作中遇到的瓶颈

       之前做过一个【霍兰德职业兴趣测试】测试的项目,大体结构就是用户答题,系统根据用户回答的问题进行职业性格测试,最后显示结果,在结果页存在一个类似于六芒星的能力分析图(这个是我自己起的名字,具体是叫什么我也不太清楚,下面将以“六芒星图”代替),起初我们用的是Echarts插件,本来相安无事。突然有一天,客户提了一个需求,需要把结果页实现一个长按保存的功能,我们计划用html2canvas实现,这时发现页面中使用Echarts生成的六芒星图在利用html2canvas时不能成功保存为图片,前端的同事们束手无策,好吧,工作丢给了我们PHP,欲哭无泪。我在各种网站中找资料,发现没有任何现成的代码(可能是我没有找到),好吧,自己写。之前由于时间比较紧,没有时间考虑其他的东西,用的是GD库的函数,别提多苦逼了。现在把整理好的代码放上来供大家参考,希望能帮到同样问题的小伙伴。

使用条件

      由于之前使用GD库的代码实现的,后来发现GD库过于麻烦,而且性能简直不敢恭维,所以,后来完善代码的使用的是Imagick,所以需要安装这个控件,这篇文章也会将Imagick的安装方法简单介绍,如果不懂的小伙伴可以在自行百度其他答案。

Windows安装

  • ImageMagick下载地址(对照好VC库的版本)https://windows.php.net/downloads/pecl/deps/
  • php扩展下载地址http://pecl.php.net/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.2011@qq.com
 * +--------------------------------------------------------
 * | @date 22:14 2018/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 2018/8/22
     *
     * @access public
     * @param $color string 颜色值
     *
     * @return $this
     */
    public function setBackgroundColor($color)
    {
        $this->backgroundColor = $color;
        return $this;
    }
    /**
     * 设置每个级别的多边形填充的颜色
     * @author Renling
     * @date 14:06 2018/8/22
     *
     * @access public
     * @param $color array 每个级别的多边形填充的颜色
     *
     * @return $this
     */
    public function setLevelColor($color)
    {
        $this->levelFillColor = $color;
        return $this;
    }
    /**
     * 设置图片大小
     * @author Renling
     * @date 14:08 2018/8/22
     *
     * @access public
     * @param $size int 图片的大小
     *
     * @return $this
     */
    public function setSize($size)
    {
        $this->sideLength = $size;
        return $this;
    }
    /**
     * 设置多边形的边数
     * @author Renling
     * @date 14:10 2018/8/22
     *
     * @access public
     * @param $node int 多边形的节点数
     *
     * @return $this
     */
    public function setNode($node)
    {
        $this->nodeNumber = $node;
        return $this;
    }
    /**
     * 设置辅助线颜色
     * @author Renling
     * @date 14:12 2018/8/22
     *
     * @access public
     * @param $color string 颜色值
     *
     * @return $this
     */
    public function setGuideColor($color)
    {
        $this->guideColor = $color;
        return $this;
    }
    /**
     * 设置每个能力的最大值
     * @author Renling
     * @date 14:13 2018/8/22
     *
     * @access public
     * @param $value int 能力值
     *
     * @return $this
     */
    public function setMaxValue($value)
    {
        $this->nodeMaxValue = $value;
        return $this;
    }
    /**
     * 设置能力轮廓线的颜色
     * @author Renling
     * @date 14:15 2018/8/22
     *
     * @access public
     * @param $color string 颜色值
     *
     * @return $this
     */
    public function setAbilityLineColor($color)
    {
        $this->abilityLineColor = $color;
        return $this;
    }
    /**
     * 设置能力轮廓的填充颜色
     * @author Renling
     * @date 14:17 2018/8/22
     *
     * @access public
     * @param $color string 颜色值
     *
     * @return $this
     */
    public function setAbilityFillColor($color)
    {
        $this->abilityFillColor = $color;
        return $this;
    }
    /**
     * 获取辅助线的颜色资源
     * @author Renling
     * @date 22:24 2018/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 2018/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 2018/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 2018/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 2018/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 2018/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;
    }
}

实例展示

<?php
require '../PolygonChart.php';
$chart = new PolygonChart;
$image = $chart->draw([58, 63, 44, 45, 75, 56]);
header('Content-Type:image/png');
echo $image->getImageBlob();

效果图展示

                   

<?php
require '../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();

效果图展示

           

还有很多其他的设置,欢迎小伙伴们尝试,如果有不足的地方,希望小伙伴们能够指正,谢谢。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值