New to Telerik UI for WinUI? Download free 30-day trial

Clustering

Many applications operate with collections of items which are placed close to others and it's uncomfortable to use them as separate objects for low zoom levels. The VisualizationLayer supports the Clustering feature. It allows grouping of items according to condition.

Using of the clustering

The VisualizationLayer exposes the following properties which are related to the Clustering feature:

  • ClusterGenerator: Gets or sets an instance of the class which implements the IClusterGenerator interface. It can be used when you want to define your own grouping algorithm. As default it uses the instance of the built-in DefaultClusterGenerator class.

  • ClusteringEnabled: Gets or sets a boolean value which indicates whether the clustering is enabled.

  • ClusteringEnabledThreshold: A property of type int that gets or sets clustering enabled threshold. This value sets the max zoom level for clustering. If current zoom level of the control is greater than this value then clustering will be disabled.

You should set the AutoCalculateClusteringThreshold to False to allow the RadMap to respect the ClusteringEnabledThreshold. The default value of this property is True. This means that you need to explicitly set it to false in all cases when you need to predefine the clustering threshold.

  • ClusteringEnabledThresholdMinItems: A property of type int that gets or sets the minimum number of items in the cluster for auto calculated clustering threshold. The clustering threshold will be set if number of the items in every cluster is less than this value.

  • ClusterItemTemplate: Gets or sets the data template which represents the cluster item.

  • ClusterTemplateSelector: Gets or sets the custom logic for choosing a template used to display each cluster.

  • DefaultClusterTemplate: Gets or sets the default cluster data template. It’s used when the ClusterTemplateSelector and ClusterItemTemplate properties are not specified.

  • GenerateClustersOnZoom: A property of type bool that gets or sets value which indicates whether clusters should be re-generated when the zoom level is changed. The default value of this property is true.

In order to enable the Clustering feature you can specify just the ClusteringEnabled property to true. Also you can configure the ItemTemplate and ClusterItemTemplate properties for customizing the appearance of the item and of the cluster.

More information about using of the ItemTemplate property you can find in the Data Binding article.

ClustersInvalidated Event

To get notified when the cluster elements are created, the ClustersInvalidated event of the VisualizationLayer can be utilized.

Example 1: Subscribe to ClustersInvalidated event

<telerikMap:VisualizationLayer x:Name="VisualizationLayer1" ClustersInvalidated="VisualizationLayer_ClustersInvalidated"/> 

Example 2: ClustersInvalidated event handler

private void VisualizationLayer_ClustersInvalidated(object sender, System.EventArgs e) 
{ 
    // custom logic      
} 

Items Grouping Example

The following example demonstrates how to use the Clustering feature to display the airports of USA. The example displays the point type data which can be found in the “airports” shape-file of our Virtualization and Grouping demo. The file contains 940 airports. The reason to use the Clustering feature is to improve the performance of rendering. Also, it allows to avoid displaying the overlapped objects which are placed close to others. You can set the ClusteringEnabled property to true for enabling the feature.

Example 4: Enable clustering functionality

<telerikMap:VisualizationLayer x:Name="VisualizationLayer1" ClusteringEnabled="True"> 
</telerikMap:VisualizationLayer> 
You can configure the ItemTemplate and ClusterItemTemplate properties to customize the appearance of the item and of the cluster.

Example 5: Customizing the appearance of the cluster

<UserControl.Resources> 
    <Style x:Key="CustomPushpin" TargetType="telerikMap:Pushpin"> 
        <Setter Property="Template"> 
            <Setter.Value> 
                <ControlTemplate TargetType="telerikMap:Pushpin"> 
                    <Border> 
                        <telerikMap:MapLayer.HotSpot> 
                            <telerikDataViz:HotSpot X="0.5" Y="1.0" ElementName="Pin" /> 
                        </telerikMap:MapLayer.HotSpot> 
                        <Canvas x:Name="Pin" Height="32" Width="20"> 
                            <Path 
                                Fill="{ThemeResource SystemAccentColor}" 
                                Height="32.005" 
                                StrokeStartLineCap="Flat" 
                                Stretch="Fill" 
                                StrokeEndLineCap="Flat" 
                                Stroke="Black" 
                                StrokeThickness="1" 
                                StrokeMiterLimit="10" 
                                StrokeLineJoin="Miter" 
                                Width="20.01" 
                                Data="M1054.5,458.1L1065.5,458.1C1067.7,458.1,1069.5,459.8,1069.5,462.1L1069.5,473.0C1069.5,475.2,1067.7,477.0,1065.5,477.0C1065.5,477.0,1062.6,476.8,1062.2,479.1C1061.6,481.7,1060.2,489.1,1060.2,489.1L1059.3,489.1C1059.3,489.1,1058.0,482.5,1057.2,479.1C1056.8,477.0,1054.5,477.0,1054.5,477.0C1052.2,477.0,1050.5,475.2,1050.5,473.0L1050.5,462.1C1050.5,459.8,1052.2,458.1,1054.5,458.1z" /> 
                            <Path 
                                Canvas.Top="2.989" Canvas.Left="3.188"  
                                Data="M1066.6,472.8C1066.6,473.9,1065.7,474.8,1064.6,474.8L1055.2,474.8C1054.1,474.8,1053.2,473.9,1053.2,472.8L1053.1,462.5C1053.1,461.4,1054.0,460.5,1055.1,460.5L1064.5,460.5C1065.6,460.5,1066.5,461.4,1066.5,462.5z"  
                                Fill="Black" 
                                Height="14.219" 
                                Stretch="Fill" 
                                Width="13.42"/> 
                        </Canvas> 
                    </Border> 
                </ControlTemplate> 
            </Setter.Value> 
        </Setter> 
    </Style> 
 
    <DataTemplate x:Key="ItemTemplate"> 
        <telerikMap:Pushpin 
            telerikMap:MapLayer.Location="{Binding ImageLocation}" 
            Style="{StaticResource CustomPushpin}" 
            PointerReleased="ClusteredItemPointerReleased"> 
            <telerikMap:MapLayer.HotSpot> 
                <telerikDataViz:HotSpot X="0.5" Y="0.5" /> 
            </telerikMap:MapLayer.HotSpot> 
        </telerikMap:Pushpin> 
    </DataTemplate> 
    <DataTemplate x:Key="ClusterTemplate"> 
        <Grid x:Name="ParentRoot" 
                Width="40" Height="25" 
                PointerReleased="ClusterPointerReleased"> 
            <telerikMap:MapLayer.HotSpot> 
                <telerikDataViz:HotSpot X="0.5" Y="1.0" /> 
            </telerikMap:MapLayer.HotSpot> 
            <Path Width="{Binding Width,ElementName=ParentRoot}"  
                    Height="{Binding Height,ElementName=ParentRoot}"  
                    Stretch="Fill" Fill="#7F000000" 
                    Data="M978.6509,491.334L958.6109,491.334L954.4549,500.874L949.9999,491.334L930.6259,491.334C928.4169,491.334,926.6259,489.543,926.6259,487.334L926.6259,433.272C926.6259,431.063,928.4169,429.272,930.6259,429.272L978.6509,429.272C980.8599,429.272,982.6509,431.063,982.6509,433.272L982.6509,487.334C982.6509,489.543,980.8599,491.334,978.6509,491.334z"  
                    StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" Stroke="White" StrokeThickness="1" StrokeMiterLimit="10" StrokeLineJoin="Miter" /> 
            <StackPanel Margin="5,2,5,5"> 
                <TextBlock Foreground="White" HorizontalAlignment="Center" Text="{Binding Path=Count}" /> 
            </StackPanel> 
        </Grid> 
    </DataTemplate> 
</UserControl.Resources> 
 
<Grid x:Name="LayoutRoot"> 
    <telerikDataViz:RadMap x:Name="RadMap" ZoomLevel="4"> 
        <telerikMap:VisualizationLayer 
        ItemTemplate="{StaticResource ItemTemplate}" 
        ClusterItemTemplate="{StaticResource ClusterTemplate}" 
        AutoCalculateClusteringThreshold="False" 
        ClusteringEnabledThreshold="8" 
        ClusteringEnabled="True"> 
            <telerikMap:VisualizationLayer.VirtualizationSource> 
                <telerikMap:MapShapeDataVirtualizationSource x:Name="VirtualizationSource"> 
                    <telerikMap:MapShapeDataVirtualizationSource.Reader> 
                        <telerikMap:AsyncShapeFileReader/> 
                    </telerikMap:MapShapeDataVirtualizationSource.Reader> 
                </telerikMap:MapShapeDataVirtualizationSource> 
            </telerikMap:VisualizationLayer.VirtualizationSource> 
            <telerikMap:VisualizationLayer.ZoomLevelGridList> 
                <telerikMap:ZoomLevelGrid MinZoom="1" /> 
                <telerikMap:ZoomLevelGrid MinZoom="2" /> 
                <telerikMap:ZoomLevelGrid MinZoom="3" /> 
                <telerikMap:ZoomLevelGrid MinZoom="4" /> 
                <telerikMap:ZoomLevelGrid MinZoom="5" /> 
                <telerikMap:ZoomLevelGrid MinZoom="6" /> 
                <telerikMap:ZoomLevelGrid MinZoom="7" /> 
                <telerikMap:ZoomLevelGrid MinZoom="8" /> 
                <telerikMap:ZoomLevelGrid MinZoom="20" /> 
            </telerikMap:VisualizationLayer.ZoomLevelGridList> 
        </telerikMap:VisualizationLayer> 
    </telerikDataViz:RadMap> 
</Grid> 
There are the results of using custom templates for clusters and items:

WinUI RadMap Rad Map Features Virtualization Layer Clustering 2

WinUI RadMap Rad Map Features Virtualization Layer Clustering 3

DefaultClusterGenerator class

The VisualizationLayer has an IClusterGenerator instance member which is responsible for the clustering behavior. By default it uses an instance of the built-in DefaultClusterGenerator class. This class can be used to customize the default grouping algorithm. The DefaultClusterGenerator class exposes the following properties:

  • AutoExpandWhenSingle: A property of type Boolean that gets or sets the value which indicates whether cluster should be automatically expanded when it contains one data item only.
  • CloseDistance: A property of type double[] that gets or sets an array of the doubles which every item define the max distance between the cluster center and the item for the corresponding ZoomLevel.
  • DeleteWhenEmpty: A property of type Boolean that gets or sets the value which indicates whether cluster should be deleted if it is empty.
  • ExpandRadius: A property of type double that gets or sets the radius (in pixels) which will be used to calculate coordinates of the items when a cluster is expanded to the polygon vertices.
  • HideExpanded: A property of type Boolean that gets or sets whether expanded cluster should be hidden or not.
  • Layer: A property of type VisualizationLayer that gets or sets layer which the current map belongs to.

The DefaultClusterGenerator class also provides several methods which can be overridden in order to further customize the clustering algorithm.

  • CreateCluster(Location center, object item): This method creates a cluster at the specified location.
  • IsItemInClusterRegion(ClusterData cluster, MapObjectInfo info, int zoomLevel): This method checks if a data item belongs to a given cluster.
  • RegenerationNeeded(ClusterData cluster, int zoomLevel): This method can be overridden so you can customize if given cluster should be regenerated at a given zoom level. The default value is true.

The ClusterData object

The VisualizationLayer uses the ClusterData object to visualize the cluster. The ClusterData exposes the following properties which can be used in applications:

  • AutoCalculateBounds: Gets or sets value which indicates whether bounding box of the cluster should be calculated automatically.

  • AutoExpandWhenSingle: Gets or sets value which indicates whether cluster should be automatically expanded when it contains 1 data item only.

  • Bounds: Gets or sets bounding box of the cluster.

  • Children: Gets data items which belong to this cluster.

  • ClusterState: A property of type ClusterState that gets or sets state of the cluster. It can be Collapsed, Expanded and ExpandedToPolygon. The difference between expanded cluster and cluster expanded to polygon is as following: the expanded cluster uses original locations of the items to show them, the cluster which is expanded to polygon uses vertices of the regular polygon with center at the cluster’s center to show items.

  • Count: Gets number of the items in the cluster.

  • Data: Gets or sets additional cluster's data. This data can be used to pass extra information to the cluster's data template or by cluster generator when detecting belonging of the item to the particular cluster.

  • DeleteWhenEmpty: Gets or sets value which indicates whether cluster should be deleted if it is empty.

  • ExpandRadius: Gets or sets radius (in pixels) which will be used to calculate coordinates of the items when cluster is expanded to the polygon vertices.

  • HideExpanded: Gets or sets value which indicates whether the expanded cluster should be hidden.

  • Hotspot: Gets or sets hotspot of the cluster.

  • Location: Gets or sets center of the cluster.

  • ZIndex: Gets or sets the Z-Index of the cluster.

Many of these properties are used by the cluster generator, only. It calculates them automatically during the process of generating clusters. Usually, applications use the ClusterState property to expand the cluster’s items. The following example demonstrates how this can be achieved.

See Also

In this article
Not finding the help you need?