前言
工具:PdfSharpCore或Pdfsharp
知识 :基本的三角函数
思路 : 画坐标,确定点-------->画多个半径渐变的正多边形------->根据数据确定雷达图的数值位置
StepOne:画一个正五边形
先画一个辅助坐标轴,
再通过三角函数确认其各个点的坐标,这里画一张图展示
因为pdfsharp默认的原点为左上角,正值为第四象限,
所以为了更好的确定各点的坐标,
则需要移动原点的位置,旋转坐标轴,以求设置为熟悉的常用坐标
好在pdfsharpcore提供了现成的方法,调整起来也比较简单
代码:
const double PAI = Math.PI;
static void Main(string[] args)
{
PdfDocument doc = new PdfDocument();
PdfPage page = new PdfPage(doc);
XGraphics graphics = XGraphics.FromPdfPage(page);
//这个方法用来移动坐标原点的位置
graphics.TranslateTransform(200, 200);
//这个方法用来旋转坐标轴
graphics.RotateTransform(180);
graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(-200,0), new XPoint(200,0));
graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(0,200), new XPoint(0,-200));
double radius = 60;
XPoint[] points = new XPoint[6]
{
new XPoint(){ X = 0,Y = radius },
new XPoint(){ X = Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius },
new XPoint(){ X = Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
new XPoint(){ X = -1*Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
new XPoint(){ X = -1*Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius},
new XPoint(){ X = 0,Y = radius }
};
graphics.DrawLines(new XPen(XColors.RoyalBlue),points);
graphics.Save();
doc.AddPage(page);
doc.Save("../../../wdnmd.pdf");
运行后可以得到
StepTwo:以原点为中心,以等比的半径画若干个五边形
有了以上的代码,只需要准备一个半径数组即可
如下:
const double PAI = Math.PI;
static void Main(string[] args)
{
PdfDocument doc = new PdfDocument();
PdfPage page = new PdfPage(doc);
XGraphics graphics = XGraphics.FromPdfPage(page);
graphics.TranslateTransform(200, 200);
graphics.RotateTransform(180);
graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(-200,0), new XPoint(200,0));
graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(0,200), new XPoint(0,-200));
//等差/或等比都行
double[] radius_list = new double[5]
{
60,75,90,105,120
};
radius_list.ToList<double>().ForEach(item=> {
XPoint[] points = new XPoint[6]
{
new XPoint(){ X = 0,Y = item },
new XPoint(){ X = Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item },
new XPoint(){ X = Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
new XPoint(){ X = -1*Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
new XPoint(){ X = -1*Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item},
new XPoint(){ X = 0,Y = item }
};
graphics.DrawLines(new XPen(XColors.RoyalBlue), points);
});
graphics.Save();
doc.AddPage(page);
doc.Save("../../../wdnmd.pdf");
}
StepThree:填充数据
假设有一组数据如下
[100,20,66,33,55]
[44,77,30,100,88]
[66,88,77,50,20]
然后你要在以下两种方法中选择一种
1.固定顶点数值
2.以组中对位最大值为顶点数值(可以更充分的绘制)
这里选择第二种
接下来是确定组中各点在图中的位置
因为点一定在原点到多边形顶点的连线上,且长度为self/Max*R
所以可以确定点的具体坐标,
这里直接省去计算的步骤,得出三组的坐标点为
[(0,100/100*R),
(-1*20/88*R*sin72,20/88*R*sin18),
(-1*66/77*R*sin36,-1*66/77*R*sin54),
(33/100*R*sin36,-1*33/100*R*sin54),
(55/88*R*sin72,55/88*R*sin18)
]
[(0,44/100*R),
(-1*77/88*R*sin72,77/88*R*sin18),
(-1*30/77*R*sin36,-1*30/77*R*sin54),
(100/100*R*sin36,-1*100/100*R*sin54),
(88/88*R*sin72,88/88*R*sin18)
]
[(0,66/100*R),
(-1*88/88*R*sin72,88/88*R*sin18),
(-1*77/77*R*sin36,-1*77/77*R*sin54),
(50/100*R*sin36,-1*50/100*R*sin54),
(20/88*R*sin72,20/88*R*sin18)
]
StepFour:绘制多边形
在确定了各个点的坐标位置后,直接调用graphics.DrawPolygon方法即可
代码如下:
const double PAI = Math.PI;
static void Main(string[] args)
{
PdfDocument doc = new PdfDocument();
PdfPage page = new PdfPage(doc);
XGraphics graphics = XGraphics.FromPdfPage(page);
graphics.TranslateTransform(200, 200);
graphics.RotateTransform(180);
graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(-200,0), new XPoint(200,0));
graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(0,200), new XPoint(0,-200));
/* double radius = 60;
XPoint[] points = new XPoint[6]
{
new XPoint(){ X = 0,Y = radius },
new XPoint(){ X = Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius },
new XPoint(){ X = Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
new XPoint(){ X = -1*Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
new XPoint(){ X = -1*Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius},
new XPoint(){ X = 0,Y = radius }
};
graphics.DrawLines(new XPen(XColors.RoyalBlue),points);*/
//等差/或等比都行
double[] radius_list = new double[5]
{
60,75,90,105,120
};
radius_list.ToList<double>().ForEach(item=> {
XPoint[] points = new XPoint[6]
{
new XPoint(){ X = 0,Y = item },
new XPoint(){ X = Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item },
new XPoint(){ X = Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
new XPoint(){ X = -1*Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
new XPoint(){ X = -1*Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item},
new XPoint(){ X = 0,Y = item }
};
graphics.DrawLines(new XPen(XColors.RoyalBlue), points);
});
//假设以下是数据
List<double[]> doubles = new List<double[]>()
{
new double[]{100,20,66,33,55},
new double[]{44,77,30,100,88},
new double[]{ 66, 88, 77, 50, 20 }
};
//寻找数据中每一列的最大值
double maxOne = 0;
double maxTwo = 0;
double maxThree = 0;
double maxFour = 0;
double maxFive = 0;
foreach(double[] temp in doubles){
maxOne = Math.Max(temp[0],maxOne);
maxTwo = Math.Max(temp[1], maxTwo);
maxThree = Math.Max(temp[2], maxThree);
maxFour = Math.Max(temp[3], maxFour);
maxFive = Math.Max(temp[4], maxFive);
}
doubles.ForEach(item => {
//根据同上的三角函数,确定各点的坐标
XPoint[] points = new XPoint[6]
{
new XPoint(0,item[0]/maxOne*120),
new XPoint(-1*item[1]/maxTwo*120*Math.Sin(72*PAI/180),item[1]/maxTwo*120*Math.Sin(18*PAI/180)),
new XPoint(-1*item[2]/maxThree*120*Math.Sin(36*PAI/180),-1*item[2]/maxThree*120*Math.Sin(54*PAI/180)),
new XPoint(item[3]/maxFour*120*Math.Sin(36*PAI/180),-1*item[3]/maxFour*120*Math.Sin(54*PAI/180)),
new XPoint(item[4]/maxFive*120*Math.Sin(72*PAI/180),item[4]/maxFive*120*Math.Sin(18*PAI/180)),
new XPoint(0,item[0]/maxOne*120)
};
graphics.DrawPolygon(new XPen(XColors.Red, 1), points);
});
graphics.Save();
doc.AddPage(page);
doc.Save("../../../wdnmd.pdf");
}
效果如下
StepFive:总结
PdfSharp/Core的绘图方法很丰富,可以用来绘制比较精密的图形。
同时,如果想要更进一步的绘制,最好将数据Model固定,弄一种固定格式,也可以借此展示更多信息。
最后注意坐标点的计算需要用到一些三角函数,请不要忘光了。