Skip to content

Repository files navigation

SquarifiedTreemapMaui

Build License: MIT

A small, copy-friendly squarified treemap control for .NET MAUI. The control uses GraphicsView and IDrawable; every tile is calculated algorithmically and painted on a canvas. It does not build the treemap from Grid, Border, or child-view tiles.

Squarified treemap sample running on the iOS Simulator

Highlights

  • Uses the squarify worst-aspect-ratio heuristic to calculate every rectangle.
  • Preserves proportional area: the numeric value controls the tile area.
  • Recalculates the complete layout whenever the available view size changes.
  • Draws spacing, rounded corners, borders, selection, values, and labels.
  • Scales typography from each tile's area and shortest side.
  • Selects readable light or dark text independently for every tile.
  • Supports bindings, observable collections, selection, tap events, and commands.
  • Has no package dependency beyond the normal .NET MAUI project references.

Requirements

  • .NET 10 SDK
  • The .NET MAUI workload
  • The platform tooling for the target you want to run, such as Xcode for iOS and Mac Catalyst or the Android SDK for Android

Install or restore the required workloads:

# Windows or macOS
dotnet workload install maui

# Linux (Android only)
dotnet workload install maui-android

dotnet workload restore SquarifiedTreemap.Sample.csproj

Run the sample

git clone https://github.com/darthza/SquarifiedTreemapMaui.git
cd SquarifiedTreemapMaui
dotnet workload restore SquarifiedTreemap.Sample.csproj

Build Android:

dotnet build SquarifiedTreemap.Sample.csproj \
  -f net10.0-android

Build for an Apple Silicon iOS Simulator:

dotnet build SquarifiedTreemap.Sample.csproj \
  -f net10.0-ios \
  -p:RuntimeIdentifier=iossimulator-arm64

Build Mac Catalyst on Apple Silicon:

dotnet build SquarifiedTreemap.Sample.csproj \
  -f net10.0-maccatalyst \
  -p:RuntimeIdentifier=maccatalyst-arm64

You can also open SquarifiedTreemap.Sample.csproj in your normal .NET MAUI IDE and select an installed simulator, emulator, or desktop target.

If Apple code signing reports Finder metadata, the checkout is probably in an iCloud or File Provider-backed folder. Move it to a normal local folder before running the Apple target.

Copy the control into an app

Copy these two files into your MAUI project:

  • Controls/SquarifiedTreemap.cs — the control, item model, drawing, text, selection, and tap handling.
  • Controls/SquarifiedTreemapLayout.cs — the squarified layout algorithm.

Change the SquarifiedTreemap.Controls namespace in both files to your app's controls namespace. No registration in MauiProgram.cs is required.

Use from XAML

<ContentPage
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:controls="clr-namespace:MyApp.Controls">

    <controls:SquarifiedTreemap
        ItemsSource="{Binding TreemapItems}"
        SelectedItem="{Binding SelectedTreemapItem, Mode=TwoWay}"
        ItemTappedCommand="{Binding OpenTreemapItemCommand}"
        TreemapPadding="0"
        ItemSpacing="4"
        CornerRadius="6"
        ScaleTextToFit="True"
        HorizontalOptions="Fill"
        VerticalOptions="Fill"
        SemanticProperties.Description="Portfolio allocation treemap" />
</ContentPage>

Example data:

using System.Collections.ObjectModel;
using Microsoft.Maui.Graphics;
using MyApp.Controls;

public ObservableCollection<TreemapItem> TreemapItems { get; } = new()
{
    new(
        "Equities",
        40,
        color: Color.FromArgb("#4611AE"),
        valueText: "40%"),
    new(
        "Bonds",
        25,
        color: Color.FromArgb("#00A5DB"),
        valueText: "25%"),
    new(
        "Cash",
        18,
        color: Color.FromArgb("#C6B6E9"),
        valueText: "18%"),
    new(
        "Options",
        11,
        color: Color.FromArgb("#C2E942"),
        valueText: "11%"),
};

Value always determines area. ValueText only changes presentation, such as adding a percent sign. Leave TextColor unset to let the control choose a high-contrast color from the tile background. Per-item text colors and base font sizes remain available when a design requires explicit overrides.

Or create the control directly in C#:

var treemap = new SquarifiedTreemap
{
    HorizontalOptions = LayoutOptions.Fill,
    VerticalOptions = LayoutOptions.Fill,
    ItemsSource = new[]
    {
        new TreemapItem("A", 50),
        new TreemapItem("B", 30),
        new TreemapItem("C", 20),
    },
};

treemap.ItemTapped += (_, eventArgs) =>
    Debug.WriteLine(
        $"{eventArgs.Item.Label}: {eventArgs.Item.Value}");

Common properties

Property Default Purpose
ItemsSource null Sequence of TreemapItem values.
SelectedItem null Two-way bindable selected item.
ItemTappedCommand null Command executed with the tapped item.
TreemapPadding 2 Padding around the complete treemap.
ItemSpacing 2 Visual gap between adjacent tiles.
CornerRadius 4 Tile corner radius.
ScaleTextToFit true Scales value and label text from tile geometry.
TextColor null Global override; null enables automatic contrast.
ShowValues / ShowLabels true Controls the two text lines.
ValueFormat "N0" Format used when ValueText is not supplied.
SelectionStrokeWidth 3 Width of the selected-tile outline.

ItemTapped and SelectionChanged events are also available. Assign Palette in C# to replace the built-in colors, and call Refresh() when a non-observable item sequence changes in place.

Layout behavior

  • Items are laid out from largest to smallest; equal values retain input order.
  • Zero, negative, NaN, and infinite values are ignored.
  • The layout normalizes areas to the current canvas and guards against numeric overflow and underflow.
  • Spacing is applied after the proportional rectangles are calculated, so the numeric layout remains faithful to the supplied values.
  • ObservableCollection<TreemapItem> additions and removals trigger a redraw. TreemapItem itself is immutable; replace an item when its value changes.
  • Values and labels are clipped to their tile. When space is tight, the label is hidden before the value is allowed to become unreadably small.

Algorithm

The implementation follows the classic squarified-treemap approach described by Mark Bruls, Kees Huizing, and Jarke J. van Wijk in Squarified Treemaps. It greedily builds rows while the worst rectangle aspect ratio improves, then places each completed row along the shortest side of the remaining bounds.

Accessibility

The control exposes a semantic description and supports keyboard-independent tap and command handling. Because the tiles are canvas drawings rather than native child controls, individual tiles are not separate screen-reader elements. Pair the treemap with an accessible list when every data item must be individually navigable.

Contributing

Contributions are welcome. See CONTRIBUTING.md for the expected build and validation steps.

License

Licensed under the MIT License.

About

Copy-friendly, canvas-drawn squarified treemap control and sample app for .NET MAUI.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages