FastReport
442 строки · 17.1 Кб
1using System;
2using System.ComponentModel;
3using System.Drawing;
4using System.Drawing.Design;
5using System.Drawing.Drawing2D;
6using FastReport.Utils;
7
8namespace FastReport.Gauge.Radial
9{
10#region Enums
11
12/// <summary>
13/// Radial Gauge types
14/// </summary>
15[Flags]
16public enum RadialGaugeType
17{
18/// <summary>
19/// Full sized gauge
20/// </summary>
21Circle = 1,
22
23/// <summary>
24/// Half of the radial gauge
25/// </summary>
26Semicircle = 2,
27
28/// <summary>
29/// Quarter of the radial gauge
30/// </summary>
31Quadrant = 4
32}
33
34/// <summary>
35/// Radial Gauge position types
36/// </summary>
37[Flags]
38[TypeConverter(typeof(FastReport.TypeConverters.FlagConverter))]
39public enum RadialGaugePosition
40{
41/// <summary>
42/// None
43/// </summary>
44None = 0,
45
46/// <summary>
47/// Top
48/// </summary>
49Top = 1,
50
51/// <summary>
52/// Bottom
53/// </summary>
54Bottom = 2,
55
56/// <summary>
57/// Left
58/// </summary>
59Left = 4,
60
61/// <summary>
62/// Right
63/// </summary>
64Right = 8
65}
66
67#endregion // Enums
68
69/// <summary>
70/// Represents a linear gauge.
71/// </summary>
72public partial class RadialGauge : GaugeObject
73{
74private const double RAD = Math.PI / 180.0;
75private PointF center;
76private RadialGaugeType type;
77private RadialGaugePosition position;
78private float semicircleOffsetRatio;
79
80#region Properties
81/// <inheritdoc/>
82public override float Width
83{
84get { return base.Width; }
85set
86{
87base.Width = value;
88if (base.Height != base.Width)
89{
90base.Height = Width;
91}
92}
93}
94
95/// <inheritdoc/>
96public override float Height
97{
98get { return base.Height; }
99set
100{
101base.Height = value;
102if (base.Width != base.Height)
103{
104base.Width = Height;
105}
106}
107}
108
109/// <summary>
110/// Returns centr of the gauge
111/// </summary>
112[Browsable(false)]
113public PointF Center
114{
115get { return center; }
116set { center = value; }
117}
118
119/// <summary>
120/// The number of radians in one degree
121/// </summary>
122public static double Radians
123{
124get { return RAD; }
125}
126
127/// <summary>
128/// Gets or sets the Radial Gauge type
129/// </summary>
130[Browsable(true)]
131[Category("Appearance")]
132public RadialGaugeType Type
133{
134get { return type; }
135set
136{
137if (value == RadialGaugeType.Circle)
138{
139position = RadialGaugePosition.None;
140type = value;
141}
142if (value == RadialGaugeType.Semicircle &&
143!(Position == RadialGaugePosition.Bottom ||
144Position == RadialGaugePosition.Left ||
145Position == RadialGaugePosition.Right ||
146Position == RadialGaugePosition.Top))
147{
148position = RadialGaugePosition.Top;
149type = value;
150}
151else if (value == RadialGaugeType.Quadrant &&
152!(
153((Position & RadialGaugePosition.Left) != 0 && (Position & RadialGaugePosition.Top) != 0 &&
154(Position & RadialGaugePosition.Right) == 0 && (Position & RadialGaugePosition.Bottom) == 0) ||
155
156((Position & RadialGaugePosition.Right) != 0 && (Position & RadialGaugePosition.Top) != 0 &&
157(Position & RadialGaugePosition.Left) == 0 && (Position & RadialGaugePosition.Bottom) == 0) ||
158
159((Position & RadialGaugePosition.Left) != 0 && (Position & RadialGaugePosition.Bottom) != 0 &&
160(Position & RadialGaugePosition.Right) == 0 && (Position & RadialGaugePosition.Top) == 0) ||
161
162((Position & RadialGaugePosition.Right) != 0 && (Position & RadialGaugePosition.Bottom) != 0 &&
163(Position & RadialGaugePosition.Left) == 0 && (Position & RadialGaugePosition.Top) == 0)
164))
165{
166position = RadialGaugePosition.Top | RadialGaugePosition.Left;
167type = value;
168}
169
170}
171}
172
173/// <summary>
174/// Gats or sets the Radial Gauge position. Doesn't work for Full Radial Gauge.
175/// </summary>
176[Category("Appearance")]
177[Editor("FastReport.TypeEditors.FlagsEditor, FastReport", typeof(UITypeEditor))]
178public RadialGaugePosition Position
179{
180get { return position; }
181set
182{
183if (Type == RadialGaugeType.Semicircle &&
184(value == RadialGaugePosition.Bottom ||
185value == RadialGaugePosition.Left ||
186value == RadialGaugePosition.Right ||
187value == RadialGaugePosition.Top))
188position = value;
189else if (Type == RadialGaugeType.Quadrant &&
190(
191((value & RadialGaugePosition.Left) != 0 && (value & RadialGaugePosition.Top) != 0 &&
192(value & RadialGaugePosition.Right) == 0 && (value & RadialGaugePosition.Bottom) == 0) ||
193
194((value & RadialGaugePosition.Right) != 0 && (value & RadialGaugePosition.Top) != 0 &&
195(value & RadialGaugePosition.Left) == 0 && (value & RadialGaugePosition.Bottom) == 0) ||
196
197((value & RadialGaugePosition.Left) != 0 && (value & RadialGaugePosition.Bottom) != 0 &&
198(value & RadialGaugePosition.Right) == 0 && (value & RadialGaugePosition.Top) == 0) ||
199
200((value & RadialGaugePosition.Right) != 0 && (value & RadialGaugePosition.Bottom) != 0 &&
201(value & RadialGaugePosition.Left) == 0 && (value & RadialGaugePosition.Top) == 0)
202))
203position = value;
204else if (Type == RadialGaugeType.Circle)
205position = 0;
206
207}
208}
209
210/// <summary>
211/// Gets or sets the semicircles offset
212/// </summary>
213[Category("Appearance")]
214public float SemicircleOffsetRatio
215{
216get { return semicircleOffsetRatio; }
217set { semicircleOffsetRatio = value; }
218}
219#endregion // Properties
220
221#region Constructors
222
223/// <summary>
224/// Initializes a new instance of the <see cref="RadialGauge"/> class.
225/// </summary>
226public RadialGauge() : base()
227{
228InitializeComponent();
229Scale = new RadialScale(this);
230Pointer = new RadialPointer(this, Scale as RadialScale);
231Label = new RadialLabel(this);
232Height = 4.0f * Units.Centimeters;
233Width = 4.0f * Units.Centimeters;
234semicircleOffsetRatio = type == RadialGaugeType.Semicircle &&
235(position == RadialGaugePosition.Left || position == RadialGaugePosition.Right) ? 1.5f : 1;
236Type = RadialGaugeType.Circle;
237Border.Lines = BorderLines.None;
238}
239
240#endregion // Constructor
241
242#region Public Methods
243
244/// <inheritdoc/>
245public override void Assign(Base source)
246{
247base.Assign(source);
248RadialGauge src = source as RadialGauge;
249Type = src.Type;
250Position = src.Position;
251}
252
253/// <inheritdoc/>
254public override void Draw(FRPaintEventArgs e)
255{
256IGraphics g = e.Graphics;
257
258float x = (AbsLeft + Border.Width / 2) * e.ScaleX;
259float y = (AbsTop + Border.Width / 2) * e.ScaleY;
260float dx = (Width - Border.Width) * e.ScaleX - 1;
261float dy = (Height - Border.Width) * e.ScaleY - 1;
262float x1 = x + dx;
263float y1 = y + dy;
264
265Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle);
266Brush brush;
267if (Fill is SolidFill)
268brush = e.Cache.GetBrush((Fill as SolidFill).Color);
269else
270brush = Fill.CreateBrush(new RectangleF(x, y, dx, dy), e.ScaleX, e.ScaleY);
271
272center = new PointF(x + dx / 2, y + dy / 2);
273
274if (type == RadialGaugeType.Circle)
275{
276g.FillAndDrawEllipse(pen, brush, x, y, dx, dy);
277}
278else if (type == RadialGaugeType.Semicircle)
279{
280float semiOffset = (Width / 16f / 2f + 2f) * semicircleOffsetRatio * e.ScaleY;
281PointF[] points = new PointF[4];
282if (position == RadialGaugePosition.Top)
283{
284g.FillPie(brush, x, y, dx, dy, -180, 180);
285g.DrawArc(pen, x, y, dx, dy, -180, 180);
286
287PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, -90 * RAD, center)[0];
288
289points[0] = new PointF(startPoint.X, startPoint.Y - 1 * e.ScaleY);
290points[1] = new PointF(startPoint.X, startPoint.Y + semiOffset);
291points[2] = new PointF(startPoint.X + dx, startPoint.Y + semiOffset);
292points[3] = new PointF(startPoint.X + dx, startPoint.Y - 1 * e.ScaleY);
293}
294else if (position == RadialGaugePosition.Bottom)
295{
296g.FillPie(brush, x, y, dx, dy, 0, 180);
297g.DrawArc(pen, x, y, dx, dy, 0, 180);
298
299PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, 90 * RAD, center)[0];
300
301points[0] = new PointF(startPoint.X, startPoint.Y + 1 * e.ScaleY);
302points[1] = new PointF(startPoint.X, startPoint.Y - semiOffset);
303points[2] = new PointF(startPoint.X - dx, startPoint.Y - semiOffset);
304points[3] = new PointF(startPoint.X - dx, startPoint.Y + 1 * e.ScaleY);
305}
306else if (position == RadialGaugePosition.Left)
307{
308g.FillPie(brush, x, y, dx, dy, 90, 180);
309g.DrawArc(pen, x, y, dx, dy, 90, 180);
310
311PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, 180 * RAD, center)[0];
312
313points[0] = new PointF(startPoint.X - 1 * e.ScaleX, startPoint.Y);
314points[1] = new PointF(startPoint.X + semiOffset, startPoint.Y);
315points[2] = new PointF(startPoint.X + semiOffset, startPoint.Y - dy);
316points[3] = new PointF(startPoint.X - 1 * e.ScaleX, startPoint.Y - dy);
317}
318else if (position == RadialGaugePosition.Right)
319{
320g.FillPie(brush, x, y, dx, dy, -90, 180);
321g.DrawArc(pen, x, y, dx, dy, -90, 180);
322
323PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, -180 * RAD, center)[0];
324
325points[0] = new PointF(startPoint.X + 1 * e.ScaleX, startPoint.Y);
326points[1] = new PointF(startPoint.X - semiOffset, startPoint.Y);
327points[2] = new PointF(startPoint.X - semiOffset, startPoint.Y - dy);
328points[3] = new PointF(startPoint.X + 1 * e.ScaleX, startPoint.Y - dy);
329}
330
331if (position != RadialGaugePosition.None)
332{
333GraphicsPath path = new GraphicsPath();
334path.AddLines(points);
335g.FillAndDrawPath(pen, brush, path);
336}
337}
338else if (type == RadialGaugeType.Quadrant)
339{
340float semiOffset = (Width / 16f / 2f + 2f) * semicircleOffsetRatio * e.ScaleY;
341if (RadialUtils.IsTop(this) && RadialUtils.IsLeft(this))
342{
343g.FillPie(brush, x, y, dx, dy, -180, 90);
344g.DrawArc(pen, x, y, dx, dy, -180, 90);
345
346PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, -90 * RAD, center)[0];
347
348PointF[] points = new PointF[5];
349points[0] = new PointF(startPoint.X, startPoint.Y - 1 * e.ScaleY);
350points[1] = new PointF(startPoint.X, startPoint.Y + semiOffset);
351points[2] = new PointF(startPoint.X + dx / 2 + semiOffset, startPoint.Y + semiOffset);
352points[3] = new PointF(startPoint.X + dx / 2 + semiOffset, y);
353points[4] = new PointF(startPoint.X + dx / 2 - 1 * e.ScaleX, y);
354GraphicsPath path = new GraphicsPath();
355path.AddLines(points);
356g.FillAndDrawPath(pen, brush, path);
357
358}
359else if (RadialUtils.IsBottom(this) && RadialUtils.IsLeft(this))
360{
361
362g.FillPie(brush, x, y, dx, dy, -270, 90);
363g.DrawArc(pen, x, y, dx, dy, -270, 90);
364
365PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, -90 * RAD, center)[0];
366PointF[] points = new PointF[5];
367points[0] = new PointF(startPoint.X, startPoint.Y + 1 * e.ScaleY);
368points[1] = new PointF(startPoint.X, startPoint.Y - semiOffset);
369points[2] = new PointF(startPoint.X + dx / 2 + semiOffset, startPoint.Y - semiOffset);
370points[3] = new PointF(startPoint.X + dx / 2 + semiOffset, y + dy);
371points[4] = new PointF(x + dx / 2 - 1 * e.ScaleX, y + dy);
372GraphicsPath path = new GraphicsPath();
373path.AddLines(points);
374g.FillAndDrawPath(pen, brush, path);
375}
376else if (RadialUtils.IsTop(this) && RadialUtils.IsRight(this))
377{
378g.FillPie(brush, x, y, dx, dy, -90, 90);
379g.DrawArc(pen, x, y, dx, dy, -90, 90);
380
381PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, 90 * RAD, center)[0];
382
383PointF[] points = new PointF[5];
384points[0] = new PointF(startPoint.X, startPoint.Y - 1 * e.ScaleY);
385points[1] = new PointF(startPoint.X, startPoint.Y + semiOffset);
386points[2] = new PointF(startPoint.X - dx / 2 - semiOffset, startPoint.Y + semiOffset);
387points[3] = new PointF(x + dx / 2 - semiOffset, y);
388points[4] = new PointF(x + dx / 2 + 1 * e.ScaleX, y);
389GraphicsPath path = new GraphicsPath();
390path.AddLines(points);
391g.FillAndDrawPath(pen, brush, path);
392}
393else if (RadialUtils.IsBottom(this) && RadialUtils.IsRight(this))
394{
395g.FillPie(brush, x, y, dx, dy, 0, 90);
396g.DrawArc(pen, x, y, dx, dy, 0, 90);
397
398PointF startPoint = RadialUtils.RotateVector(new PointF[] { new PointF(x + dx / 2, y), center }, 90 * RAD, center)[0];
399
400PointF[] points = new PointF[5];
401points[0] = new PointF(startPoint.X, startPoint.Y + 1 * e.ScaleY);
402points[1] = new PointF(startPoint.X, startPoint.Y - semiOffset);
403points[2] = new PointF(x + dx / 2 - semiOffset, startPoint.Y - semiOffset);
404points[3] = new PointF(x + dx / 2 - semiOffset, y + dy);
405points[4] = new PointF(x + dx / 2 + 1 * e.ScaleX, y + dy);
406GraphicsPath path = new GraphicsPath();
407path.AddLines(points);
408g.FillAndDrawPath(pen, brush, path);
409}
410}
411
412Scale.Draw(e);
413Pointer.Draw(e);
414Label.Draw(e);
415DrawMarkers(e);
416if (!(Fill is SolidFill))
417brush.Dispose();
418if (Report != null && Report.SmoothGraphics)
419{
420g.InterpolationMode = InterpolationMode.HighQualityBicubic;
421g.SmoothingMode = SmoothingMode.AntiAlias;
422}
423}
424
425/// <inheritdoc/>
426public override void Serialize(FRWriter writer)
427{
428RadialGauge c = writer.DiffObject as RadialGauge;
429base.Serialize(writer);
430if (Type != c.Type)
431{
432writer.WriteValue("Type", Type);
433}
434if (Position != c.Position)
435{
436writer.WriteValue("Position", Position);
437}
438}
439
440#endregion // Public Methods
441}
442}
443