Skip to content

Instantly share code, notes, and snippets.

@padcom
Created October 11, 2017 17:19
Show Gist options
  • Save padcom/36a279b2efa7b0f8f74f97ad2acf32f4 to your computer and use it in GitHub Desktop.
Save padcom/36a279b2efa7b0f8f74f97ad2acf32f4 to your computer and use it in GitHub Desktop.
C#.NET - drawing a spider chart
public class Chart {
private readonly Brush b = new SolidBrush(Color.FromArgb(200, 255, 0, 255));
private readonly Pen p1 = new Pen(Color.Black, 2);
private readonly Pen p2 = new Pen(Color.Black, 1);
private readonly Pen p3 = new Pen(Color.Red, 2);
public Bitmap Draw(Point center, int radius, int max, decimal[] v) {
var width = center.X * 2;
var height = center.Y * 2;
var chart = new Bitmap(width, height);
var g = Graphics.FromImage(chart);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.FillRectangle(Brushes.White, 0, 0, width, height);
g.DrawLine(p2, center.X, 0, center.X, height);
g.DrawLine(p2, 0, center.Y, width, center.Y);
g.DrawPolygon(p2, CalculatePoints(center, radius, v.Length));
g.DrawPolygon(p2, CalculatePoints(center, (int)(radius * 0.75), v.Length));
g.DrawPolygon(p2, CalculatePoints(center, (int)(radius * 0.50), v.Length));
g.DrawPolygon(p2, CalculatePoints(center, (int)(radius * 0.25), v.Length));
g.FillPolygon(b, CalculatePoints(center, radius, max, v));
g.DrawPolygon(p3, CalculatePoints(center, radius, max, v));
return chart;
}
private bool isOdd(int n) {
return n % 2 == 1;
}
public Point[] CalculatePoints(Point center, int radius, int max, decimal[] values) {
var result = new Point[values.Length];
var n = values.Length;
var centerAngle = 2 * Math.PI / n;
// calculate the default start angle
var startAngle = isOdd(n) ? Math.PI / 2 - centerAngle / 2 : Math.PI / 2;
// create a vertex array
for (var i = 0; i < n; i++) {
var angle = startAngle + (i * centerAngle );
var distance = radius * (double)values[i] / max;
var x = (int)Math.Round(center.X + distance * Math.Cos(angle));
var y = (int)Math.Round(center.Y - distance * Math.Sin(angle));
result[i] = new Point(x, y);
}
return result;
}
public Point[] CalculatePoints(Point center, int radius, decimal[] values) {
var max = (int)values.Aggregate((x, a) => x > a ? x : a);
return CalculatePoints(center, radius, max, values);
}
public Point[] CalculatePoints(Point center, int radius, int count) {
decimal[] points = new decimal[count];
for (int i = 0; i < count; i++) {
points[i] = radius;
}
return CalculatePoints(center, radius, points);
}
}
public class ChartTest {
[Test]
public void WillDrawAChart() {
var chart = new Chart();
var output = chart.Draw(new Point(200, 200), 200, 15, new decimal[] { 5, 14, 9, 8, 4,13,7,2,5 });
Assert.IsNotNull(output, "Expected Chart.Draw() to produce a bitmap");
Assert.IsInstanceOf(typeof(Bitmap), output, "Expected Chart.Draw() to produce a bitmap");
output.Save(@"/tmp/test.png");
}
[Test]
public void WillCalculatePointsOfTheChart() {
var chart = new Chart();
var actual = chart.CalculatePoints(new Point(100, 100), 100, 150, new decimal[] { 100, 50, 75 });
var expected = new Point[] { new Point(158, 67), new Point(71, 83), new Point(100, 150) };
Assert.AreEqual(expected, actual);
}
[Test]
public void WillCalculatePointsOfTheChartWithAutoCalculatedMaxValue() {
var chart = new Chart();
var actual = chart.CalculatePoints(new Point(100, 100), 100, new decimal[] { 100, 50, 75 });
var expected = new Point[] { new Point(187, 50), new Point(57, 75), new Point(100, 175) };
Assert.AreEqual(expected, actual);
}
[Test]
public void WillCalculateReferencePoints() {
var chart = new Chart();
var actual = chart.CalculatePoints(new Point(100, 100), 100, 3);
var expected = new Point[] { new Point(187, 50), new Point(13, 50), new Point(100, 200) };
Assert.AreEqual(expected, actual);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment