Skip to content

Instantly share code, notes, and snippets.

@flew2bits
Last active August 25, 2023 13:09
Show Gist options
  • Save flew2bits/8ca9647e838790a69f88873d8c0a9389 to your computer and use it in GitHub Desktop.
Save flew2bits/8ca9647e838790a69f88873d8c0a9389 to your computer and use it in GitHub Desktop.
QuestPDF pre-calculated column width based on content.
using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
public class OrderItem
{
public string ItemName { get; set; } = Placeholders.Sentence();
public int Price { get; set; } = Placeholders.Random.Next(1, 11) * 10;
public int Count { get; set; } = Placeholders.Random.Next(1, 11);
}
public struct OrdersTableState
{
public int ShownItemsCount { get; set; }
public float? AutoWidth { get; set; }
}
public class OptimizedOrdersTable : IDynamicComponent<OrdersTableState>
{
private ICollection<OrderItem> Items { get; }
public OrdersTableState State { get; set; }
public OptimizedOrdersTable(ICollection<OrderItem> items)
{
Items = items;
State = new OrdersTableState
{
ShownItemsCount = 0,
AutoWidth = null
};
}
public DynamicComponentComposeResult Compose(DynamicContext context)
{
var autoWidth = State.AutoWidth ?? CalculateAutoWidth(context);
var header = ComposeHeader(context, autoWidth);
var sampleFooter = ComposeFooter(context, Enumerable.Empty<OrderItem>());
var decorationHeight = header.Size.Height + sampleFooter.Size.Height;
var rows = GetItemsForPage(context, autoWidth, decorationHeight).ToList();
var footer = ComposeFooter(context, rows.Select(x => x.Item));
var content = context.CreateElement(container =>
{
container.MinimalBox().Decoration(decoration =>
{
decoration.Before().Element(header);
decoration.Content().Column(column =>
{
foreach (var row in rows)
column.Item().Element(row.Element);
});
decoration.After().Element(footer);
});
});
State = new OrdersTableState
{
AutoWidth = autoWidth,
ShownItemsCount = State.ShownItemsCount + rows.Count
};
return new DynamicComponentComposeResult
{
Content = content,
HasMoreContent = State.ShownItemsCount < Items.Count
};
}
private float CalculateAutoWidth(DynamicContext context)
{
return Items.Select(i => context.CreateElement(c => c.Text(i.ItemName)).Size.Width).Max();
}
private IDynamicElement ComposeHeader(DynamicContext context, float autoWidth)
{
return context.CreateElement(element =>
{
element
.Width(context.AvailableSize.Width)
.BorderBottom(1)
.BorderColor(Colors.Grey.Darken2)
.Padding(5)
.DefaultTextStyle(TextStyle.Default.SemiBold())
.Row(row =>
{
row.ConstantItem(30).Text("#");
row.ConstantItem(autoWidth).Text("Item name");
row.RelativeItem().AlignRight().Text("Count");
row.RelativeItem().AlignRight().Text("Price");
row.RelativeItem().AlignRight().Text("Total");
});
});
}
private IDynamicElement ComposeFooter(DynamicContext context, IEnumerable<OrderItem> items)
{
var total = items.Sum(x => x.Count * x.Price);
return context.CreateElement(element =>
{
element
.Width(context.AvailableSize.Width)
.Padding(5)
.AlignRight()
.DefaultTextStyle(TextStyle.Default.FontSize(14).SemiBold())
.Text($"Subtotal: {total}$");
});
}
private IEnumerable<(OrderItem Item, IDynamicElement Element)> GetItemsForPage(DynamicContext context, float autoWidth, float decorationHeight)
{
var totalHeight = decorationHeight;
foreach (var index in Enumerable.Range(State.ShownItemsCount, Items.Count - State.ShownItemsCount))
{
var item = Items.ElementAt(index);
var element = context.CreateElement(content =>
{
content
.Width(context.AvailableSize.Width)
.BorderBottom(1)
.BorderColor(Colors.Grey.Lighten2)
.Padding(5)
.Row(row =>
{
row.ConstantItem(30).Text(index + 1);
row.ConstantItem(autoWidth).DebugArea().Text(item.ItemName);
row.RelativeItem().AlignRight().Text(item.Count);
row.RelativeItem().AlignRight().Text($"{item.Price}$");
row.RelativeItem().AlignRight().Text($"{item.Count*item.Price}$");
});
});
var elementHeight = element.Size.Height;
if (totalHeight + elementHeight > context.AvailableSize.Height)
break;
totalHeight += elementHeight;
yield return (item, element);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment