之前做过一个【霍兰德职业兴趣测试】测试的项目,大体结构就是用户答题,系统根据用户回答的问题进行职业性格测试,最后显示结果,在结果页存在一个类似于六芒星的能力分析图(这个是我自己起的名字,具体是叫什么我也不太清楚,下面将以“六芒星图”代替),起初我们用的是Echarts插件,本来相安无事。突然有一天,客户提了一个需求,需要把结果页实现一个长按保存的功能,我们计划用html2canvas实现,这时发现页面中使用Echarts生成的六芒星图在利用html2canvas时不能成功保存为图片,前端的同事们束手无策,好吧,工作丢给了我们PHP,欲哭无泪。我在各种网站中找资料,发现没有任何现成的代码(可能是我没有找到),好吧,自己写。之前由于时间比较紧,没有时间考虑其他的东西,用的是GD库的函数,别提多苦逼了。现在把整理好的代码放上来供大家参考,希望能帮到同样问题的小伙伴。
由于之前使用GD库的代码实现的,后来发现GD库过于麻烦,而且性能简直不敢恭维,所以,后来完善代码的使用的是Imagick,所以需要安装这个控件,这篇文章也会将Imagick的安装方法简单介绍,如果不懂的小伙伴可以在自行百度其他答案。
以下代码完全是本人自行编写,可能存在性能、资源上的不足,请各位大神多多指点,谢谢。
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;
}
}
draw([58, 63, 44, 45, 75, 56]);
header('Content-Type:image/png');
echo $image->getImageBlob();
效果图展示
setBackgroundColor('#ff0000')->setNode(5)->draw([58, 63, 44, 45, 75]);
header('Content-Type:image/png');
echo $image->getImageBlob();
效果图展示
还有很多其他的设置,欢迎小伙伴们尝试,如果有不足的地方,希望小伙伴们能够指正,谢谢。