feat: add FundAnagraficaRenderer (layout C: title strip + 3 columns)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
using CertReports.Syncfusion.Helpers;
|
||||
using CertReports.Syncfusion.Models;
|
||||
using Syncfusion.Drawing;
|
||||
using Syncfusion.Pdf;
|
||||
using Syncfusion.Pdf.Graphics;
|
||||
|
||||
namespace CertReports.Syncfusion.Services.Implementations;
|
||||
|
||||
public class FundAnagraficaRenderer
|
||||
{
|
||||
private const float PageW = 595f - 2 * PdfTheme.PageMargin;
|
||||
private const float PageH = 842f - 2 * PdfTheme.PageMargin - PdfTheme.FooterHeight;
|
||||
private const float ColGap = 8f;
|
||||
private const float Col1W = 190f;
|
||||
private const float Col2W = 125f;
|
||||
private const float Col3W = PageW - Col1W - Col2W - 2 * ColGap;
|
||||
|
||||
public PdfDocument Render(FundReportData data)
|
||||
{
|
||||
var doc = new PdfDocument();
|
||||
var page = PdfTheme.AddA4Page(doc);
|
||||
var g = page.Graphics;
|
||||
var info = data.Info;
|
||||
float y = 0f;
|
||||
|
||||
y = DrawTitle(g, info, y);
|
||||
y += 6f;
|
||||
y = DrawStrip(g, info, y);
|
||||
y += 8f;
|
||||
|
||||
float col1X = 0f;
|
||||
float col2X = Col1W + ColGap;
|
||||
float col3X = col2X + Col2W + ColGap;
|
||||
|
||||
DrawAnagrafici(g, info, col1X, Col1W, y);
|
||||
DrawEsg(g, info, col2X, Col2W, y);
|
||||
DrawPerfGrid(g, info, col3X, Col3W, y);
|
||||
|
||||
PdfTheme.DrawFooter(g, PageW, PageH, 1, data.ShowBranding);
|
||||
return doc;
|
||||
}
|
||||
|
||||
private float DrawTitle(PdfGraphics g, FundInfo info, float y)
|
||||
{
|
||||
const float h = 22f;
|
||||
g.DrawRectangle(PdfTheme.AccentBlueBrush, new RectangleF(0, y, PageW, h));
|
||||
var fmt = new PdfStringFormat
|
||||
{
|
||||
Alignment = PdfTextAlignment.Center,
|
||||
LineAlignment = PdfVerticalAlignment.Middle
|
||||
};
|
||||
var title = $"{info.Tipo ?? "Fondo"} — {info.Strumento} — {info.Isin}";
|
||||
g.DrawString(title, PdfTheme.Bold,
|
||||
new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 255, 255, 255))),
|
||||
new RectangleF(0, y, PageW, h), fmt);
|
||||
return y + h;
|
||||
}
|
||||
|
||||
private float DrawStrip(PdfGraphics g, FundInfo info, float y)
|
||||
{
|
||||
const float h = 36f;
|
||||
const float w1 = 100f;
|
||||
const float w2 = 225f;
|
||||
const float w3 = 150f;
|
||||
const float gap = 8f;
|
||||
|
||||
DrawStripBox(g, "RATING / RANK",
|
||||
info.Rank.HasValue ? info.Rank.Value.ToString("F2") : "—",
|
||||
0f, y, w1, h);
|
||||
DrawStripBox(g, "PREZZO",
|
||||
info.Prezzo.HasValue ? $"{info.Prezzo.Value:F2} {info.Valuta}" : "—",
|
||||
w1 + gap, y, w2, h);
|
||||
DrawStripBox(g, "AGGIORNATO AL",
|
||||
info.DataPrezzo.HasValue ? info.DataPrezzo.Value.ToString("dd/MM/yyyy") : "—",
|
||||
w1 + gap + w2 + gap, y, w3, h);
|
||||
|
||||
return y + h;
|
||||
}
|
||||
|
||||
private void DrawStripBox(PdfGraphics g, string label, string value,
|
||||
float x, float y, float w, float h)
|
||||
{
|
||||
var bgBrush = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 232, 238, 248)));
|
||||
var borderPen = new PdfPen(new PdfColor(PdfTheme.AccentBlue), 0.5f);
|
||||
g.DrawRectangle(bgBrush, new RectangleF(x, y, w, h));
|
||||
g.DrawRectangle(borderPen, new RectangleF(x, y, w, h));
|
||||
g.DrawRectangle(PdfTheme.AccentBlueBrush, new RectangleF(x, y, 3f, h));
|
||||
var grayBrush = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 136, 136, 136)));
|
||||
var leftFmt = new PdfStringFormat { Alignment = PdfTextAlignment.Left };
|
||||
g.DrawString(label, PdfTheme.Small, grayBrush,
|
||||
new RectangleF(x + 6f, y + 2f, w - 8f, 10f), leftFmt);
|
||||
g.DrawString(value, PdfTheme.Bold, PdfTheme.AccentBlueBrush,
|
||||
new RectangleF(x + 6f, y + 13f, w - 8f, h - 15f), leftFmt);
|
||||
}
|
||||
|
||||
private void DrawAnagrafici(PdfGraphics g, FundInfo info, float x, float w, float y)
|
||||
{
|
||||
y = DrawColHeader(g, "Dati Anagrafici", x, w, y);
|
||||
|
||||
var items = new (string Label, string Value)[]
|
||||
{
|
||||
("Società", info.Societa ?? "—"),
|
||||
("Categoria MS", info.CategoriaMorningstar ?? "—"),
|
||||
("Tipo", info.Tipo ?? "—"),
|
||||
("Valuta", info.Valuta ?? "—"),
|
||||
("Hedged", string.IsNullOrEmpty(info.Hedged) ? "—" : info.Hedged),
|
||||
("Benchmark", info.Benchmark ?? "—"),
|
||||
("Spese correnti", info.SpeseCorrenti.HasValue ? $"{info.SpeseCorrenti.Value:F2}%" : "—"),
|
||||
("Catalogo", info.Catalogo ?? "—"),
|
||||
("Proventi", info.Proventi ?? "—"),
|
||||
("Data lancio", info.DataLancio.HasValue ? info.DataLancio.Value.ToString("dd/MM/yyyy") : "—"),
|
||||
("Patrimonio", info.Patrimonio.HasValue ? $"{info.Patrimonio.Value:N0} EUR" : "—"),
|
||||
};
|
||||
|
||||
DrawKvList(g, items, x, w, y);
|
||||
}
|
||||
|
||||
private void DrawEsg(PdfGraphics g, FundInfo info, float x, float w, float y)
|
||||
{
|
||||
y = DrawColHeader(g, "ESG Score", x, w, y);
|
||||
|
||||
var scores = new (string Label, decimal? Value)[]
|
||||
{
|
||||
("Sustainability", info.Sustainability),
|
||||
("Environmental", info.Environmental),
|
||||
("Social", info.Social),
|
||||
("Governance", info.Governance),
|
||||
};
|
||||
|
||||
var greenBg = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 232, 245, 233)));
|
||||
var greenPen = new PdfPen(new PdfColor(Color.FromArgb(255, 200, 230, 201)), 0.5f);
|
||||
var grayLbl = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 85, 85, 85)));
|
||||
var greenVal = new PdfSolidBrush(new PdfColor(PdfTheme.PositiveGreen));
|
||||
|
||||
foreach (var (label, val) in scores)
|
||||
{
|
||||
const float cardH = 36f;
|
||||
g.DrawRectangle(greenBg, new RectangleF(x, y, w, cardH));
|
||||
g.DrawRectangle(greenPen, new RectangleF(x, y, w, cardH));
|
||||
g.DrawString(label, PdfTheme.Small, grayLbl,
|
||||
new RectangleF(x + 5f, y + 2f, w - 8f, 12f));
|
||||
var valText = (val.HasValue && val.Value != 0m) ? val.Value.ToString("F2") : "—";
|
||||
g.DrawString(valText, PdfTheme.Bold, greenVal,
|
||||
new RectangleF(x + 5f, y + 14f, w - 8f, 20f));
|
||||
y += cardH + 3f;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPerfGrid(PdfGraphics g, FundInfo info, float x, float w, float y)
|
||||
{
|
||||
y = DrawGridHeader(g, "PERFORMANCE · VOLATILITÀ · REND/RISK", x, w, y);
|
||||
|
||||
var periods = new (string Label, decimal? Perf, decimal? Vol, decimal? Rr)[]
|
||||
{
|
||||
("3 Mesi", info.P3M, info.V3M, info.R3M),
|
||||
("6 Mesi", info.P6M, info.V6M, info.R6M),
|
||||
("Da inizio anno", info.PYD, info.VYD, info.RYD),
|
||||
("1 Anno", info.P1Y, info.V1Y, info.R1Y),
|
||||
("3 Anni", info.P3Y, info.V3Y, info.R3Y),
|
||||
("5 Anni", info.P5Y, info.V5Y, info.R5Y),
|
||||
};
|
||||
|
||||
const float cellGap = 3f;
|
||||
float cellW = (w - 2 * cellGap) / 3f;
|
||||
const float cellH = 50f;
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
int col = i % 3;
|
||||
int row = i / 3;
|
||||
float cx = x + col * (cellW + cellGap);
|
||||
float cy = y + row * (cellH + cellGap);
|
||||
var p = periods[i];
|
||||
DrawPerfCell(g, p.Label, p.Perf, p.Vol, p.Rr, cx, cy, cellW, cellH);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPerfCell(PdfGraphics g, string period,
|
||||
decimal? perf, decimal? vol, decimal? rr,
|
||||
float x, float y, float w, float h)
|
||||
{
|
||||
var cellBg = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 248, 250, 255)));
|
||||
var cellPen = new PdfPen(new PdfColor(Color.FromArgb(255, 221, 227, 240)), 0.5f);
|
||||
g.DrawRectangle(cellBg, new RectangleF(x, y, w, h));
|
||||
g.DrawRectangle(cellPen, new RectangleF(x, y, w, h));
|
||||
|
||||
var center = new PdfStringFormat
|
||||
{
|
||||
Alignment = PdfTextAlignment.Center,
|
||||
LineAlignment = PdfVerticalAlignment.Top
|
||||
};
|
||||
|
||||
g.DrawString(period, PdfTheme.SmallBold, PdfTheme.AccentBlueBrush,
|
||||
new RectangleF(x, y + 2f, w, 12f), center);
|
||||
|
||||
if (perf.HasValue)
|
||||
{
|
||||
var perfBrush = perf.Value < 0
|
||||
? new PdfSolidBrush(new PdfColor(PdfTheme.NegativeRed))
|
||||
: new PdfSolidBrush(new PdfColor(PdfTheme.PositiveGreen));
|
||||
g.DrawString($"{perf.Value:F2}%", PdfTheme.TableBold, perfBrush,
|
||||
new RectangleF(x, y + 14f, w, 12f), center);
|
||||
}
|
||||
else
|
||||
g.DrawString("—", PdfTheme.TableFont,
|
||||
new PdfSolidBrush(new PdfColor(PdfTheme.TextSecondary)),
|
||||
new RectangleF(x, y + 14f, w, 12f), center);
|
||||
|
||||
var volText = vol.HasValue ? $"Vol: {vol.Value:F2}%" : "Vol: —";
|
||||
g.DrawString(volText, PdfTheme.Small,
|
||||
new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 85, 85, 85))),
|
||||
new RectangleF(x, y + 26f, w, 12f), center);
|
||||
|
||||
g.DrawLine(new PdfPen(new PdfColor(Color.FromArgb(255, 238, 238, 238)), 0.5f),
|
||||
new PointF(x + 4f, y + h - 15f), new PointF(x + w - 4f, y + h - 15f));
|
||||
|
||||
var rrText = rr.HasValue ? $"R/R: {rr.Value:F2}" : "R/R: —";
|
||||
g.DrawString(rrText, PdfTheme.Small,
|
||||
new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 136, 136, 136))),
|
||||
new RectangleF(x, y + h - 14f, w, 12f), center);
|
||||
}
|
||||
|
||||
private float DrawColHeader(PdfGraphics g, string title, float x, float w, float y)
|
||||
{
|
||||
g.DrawRectangle(PdfTheme.AccentBlueBrush, new RectangleF(x, y, 3f, 14f));
|
||||
g.DrawString(title, PdfTheme.Bold, new PdfSolidBrush(new PdfColor(PdfTheme.AccentBlue)),
|
||||
new RectangleF(x + 6f, y, w - 6f, 14f));
|
||||
g.DrawLine(new PdfPen(new PdfColor(PdfTheme.AccentBlue), 0.5f),
|
||||
new PointF(x, y + 15f), new PointF(x + w, y + 15f));
|
||||
return y + 18f;
|
||||
}
|
||||
|
||||
private float DrawGridHeader(PdfGraphics g, string title, float x, float w, float y)
|
||||
{
|
||||
const float h = 16f;
|
||||
g.DrawRectangle(PdfTheme.AccentBlueBrush, new RectangleF(x, y, w, h));
|
||||
var fmt = new PdfStringFormat
|
||||
{
|
||||
Alignment = PdfTextAlignment.Left,
|
||||
LineAlignment = PdfVerticalAlignment.Middle
|
||||
};
|
||||
g.DrawString(title, PdfTheme.SmallBold,
|
||||
new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 255, 255, 255))),
|
||||
new RectangleF(x + 4f, y, w - 6f, h), fmt);
|
||||
return y + h + 4f;
|
||||
}
|
||||
|
||||
private void DrawKvList(PdfGraphics g, (string Label, string Value)[] items,
|
||||
float x, float w, float y)
|
||||
{
|
||||
float rh = PdfTheme.RowHeight;
|
||||
float labelW = w * 0.52f;
|
||||
float valueW = w * 0.48f;
|
||||
var labelBrush = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 85, 85, 85)));
|
||||
var valueBrush = new PdfSolidBrush(new PdfColor(Color.FromArgb(255, 33, 33, 33)));
|
||||
|
||||
foreach (var (label, value) in items)
|
||||
{
|
||||
g.DrawString(label + ":", PdfTheme.TableBold, labelBrush,
|
||||
new RectangleF(x, y, labelW, rh));
|
||||
g.DrawString(value, PdfTheme.TableFont, valueBrush,
|
||||
new RectangleF(x + labelW, y, valueW, rh));
|
||||
y += rh;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user