Select to view content in your preferred language

How to customize the symbols of FlareCluster ?

4061
10
06-13-2012 06:51 AM
FabienNAPPA
Regular Contributor
Hi,

How to customize the symbols of FlareCluster ?

Thank you.
Fabiano
0 Kudos
10 Replies
DominiqueBroux
Esri Frequent Contributor
The FlareSymbol is closely tied to the FlareClusterer and you can't change it.

However you can define your own clusterer class by sybclassing the GraphicsClusterer class and by overriding the method OnCreateGraphic.

There is sample here : http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#CustomClusterer
0 Kudos
FabienNAPPA
Regular Contributor
Hi Dominique,

Thank you very much for your response.

The example you gave me it's for customizing the "Large Cluster Symbol".

First question : how to transform the circles into a triangles?

Second question : is it possible to customize the rounds into a triangles "Flare Cluster Symbol"?

            [ATTACH=CONFIG]15208[/ATTACH]

In advance thank you.
Fabiano
0 Kudos
DominiqueBroux
Esri Frequent Contributor
The example you gave me it's for customizing the "Large Cluster Symbol".


Not only. The large cluster symbol is just a particular case of the FlareClusterer.

By overriding OnCreateGraphics (as in the sample) you can assign the symbol you want depending on the size of the cluster:

        protected override Graphic OnCreateGraphic(GraphicCollection cluster, MapPoint point, int maxClusterCount)
        {
            if (cluster.Count == 1) return cluster[0];
            Symbol symbol;
            if (cluster.Count == 2) symbol = mySymbol2;
            if (cluster.Count == 3) symbol = mySymbol3;
            if (cluster.Count == 4) symbol = mySymbol4;
            ........
            else symbol = myLargeSymbol;


.........


Then you need to create your nice symbols but that's a design matter.

Though, I am not clear if it's possible to define a symbol allowing to get the maptips corresponding to the underlying graphics.
If nobody answers to that question, I'll try to look at that and let you know.
0 Kudos
FabienNAPPA
Regular Contributor
Thank you for your help...

I wait forward to your response.
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Thank you for your help...

I wait forward to your response.


I found out about the way to create cluster symbols allowing maptips on the underlying graphics.
We have to use the Clusterer.ClusterChildElement attached property.

As I didn't find any sample showing how it works, I created one that should be close of your need.

Screenshot of the result:
[ATTACH=CONFIG]15272[/ATTACH]
0 Kudos
FabienNAPPA
Regular Contributor
Exelent !!!

Thank you very much Dominique.
0 Kudos
SamRosewall
Emerging Contributor
Thanks for the help Dominique, you got me started on the right path. However, I took it one step further for my needs and thought I would repost for any of those who are needing a little more customization. Basically, I wanted the individual smaller spin out graphics to represent the color of their respective layer graphic instead of being stuck with one color. So if anyone else needs to maintain color or image respect to original layer graphic here is an example that you could tweek for your own needs. I do find it a bit odd that we have no control over the cluster without overriding it's symbol though. Shouldn't this be a built in function to set the symbol equal to the graphic layer's symbol or at least bind something of each individual flare to an attribute of the graphic without having to override the template.

Everything should be completely copy and pasteable assuming you have the respective dll's

Step 1:
Create a Control Template Factory to dynamically create the XAML needed for each symbol.
Purpose --> If you use a resource dictionary control template you will have a REF issue when you change a Resource Dictionary template colors for a cluster it affects ALL clusters using that template, thus losing their original values. Colors are made static so that they can be put in strings preConstructor.


See Attached ControlTemplateFactory, it is a bit too long for this post.

Step 2:
Create internal class ClusterSymbol: MarkerSymbol
Purpose --> changes the Symbol to the respective count symbol

See Attached ClusterSymbol or below code


using System;
using System.Windows.Controls;
using ESRI.ArcGIS.Client.Symbols;

namespace FMH.Shared.XAML.ViewModels.Utilities
{
    internal class ClusterSymbol : MarkerSymbol
    {
        //Constructors
        public ClusterSymbol(int clusterCount)
        {
            ControlTemplateFactory factory = new ControlTemplateFactory();
            string template = factory.GetClusterControlTemplate(clusterCount);
            this.ControlTemplate = System.Windows.Markup.XamlReader.Load(template) as ControlTemplate;
        }

        
        public double Size { get; set; }
        public override double OffsetX
        {
            get
            {
                return Size / 2;
            }
            set
            {
                throw new NotSupportedException();
            }
        }
        public override double OffsetY
        {
            get
            {
                return Size / 2;
            }
            set
            {
                throw new NotSupportedException();
            }
        }
    }
}



Step 3:
Create ColorClusterer : FlareClustere Class
Purpose --> Used to override default symbol when clustering is creating graphics.

See Attached ColorClusterer or Below


using System;
using System.Windows;
using System.Windows.Media;
using ESRI.ArcGIS.Client;

namespace FMH.Shared.XAML.ViewModels.Utilities
{
    /// <summary>
    /// Created to customize the FlareClusterer with custom flare out graphics
    /// </summary>
    public class ColorClusterer : FlareClusterer
    {
        //Constructors
        public ColorClusterer()
        {

        }


        /// <summary>
        /// Happens each time clustering changes
        /// </summary>
        protected override Graphic OnCreateGraphic(GraphicCollection cluster, ESRI.ArcGIS.Client.Geometry.MapPoint point, int maxClusterCount)
        {
            if (cluster.Count == 1)
                return cluster[0];

            //Factory used to get correct Control template for respective number of graphics in cluster, set Hex Colors necessary for each cluster
            ControlTemplateFactory.Cluster1HexColor = ((Color)Application.Current.Resources[((ClaimStatusColor)(Convert.ToInt32(cluster[0].Attributes["CLM_STAT_ID"]))).ToString()]).ToString();
            ControlTemplateFactory.Cluster2HexColor = ((Color)Application.Current.Resources[((ClaimStatusColor)(Convert.ToInt32(cluster[1].Attributes["CLM_STAT_ID"]))).ToString()]).ToString();

            if (cluster.Count > 2)
                ControlTemplateFactory.Cluster3HexColor = ((Color)Application.Current.Resources[((ClaimStatusColor)(Convert.ToInt32(cluster[2].Attributes["CLM_STAT_ID"]))).ToString()]).ToString();
            if (cluster.Count > 3)
                ControlTemplateFactory.Cluster4HexColor = ((Color)Application.Current.Resources[((ClaimStatusColor)(Convert.ToInt32(cluster[3].Attributes["CLM_STAT_ID"]))).ToString()]).ToString();
            if (cluster.Count > 4)
                ControlTemplateFactory.Cluster5HexColor = ((Color)Application.Current.Resources[((ClaimStatusColor)(Convert.ToInt32(cluster[4].Attributes["CLM_STAT_ID"]))).ToString()]).ToString();
            if (cluster.Count > 5)
                ControlTemplateFactory.Cluster6HexColor = ((Color)Application.Current.Resources[((ClaimStatusColor)(Convert.ToInt32(cluster[5].Attributes["CLM_STAT_ID"]))).ToString()]).ToString();

            //Internal Class ClusterSymbol overriden to replace Control Template
            var graphic = new Graphic { Symbol = new ClusterSymbol(cluster.Count), Geometry = point };
            graphic.Attributes.Add("Count", cluster.Count);

            return graphic;
        }


        //Enums used to get respective color from Resource Dictionary
        public enum ClaimStatusColor
        {
            ClaimStatusPendingBlueColor = 1,
            ClaimStatusOpenLightBlueColor = 2,
            ClaimStatusAdjustedGreenColor = 3,
            ClaimStatusDeferredYellowColor = 4,
            ClaimStatusReceivedOrangeColor = 5,
            ClaimStatusProcessedPurpleColor = 6,
            ClaimStatusCancelledRedColor = 7,
            ClaimStatusNODLightPurpleColor = 8
        }
    }
}



Step 4:
Set up your layer. I'm using MVVM so mine is all done in C#


        public void CreateClaimPointsLayer()
        {
            _claimsPinLayer = new FeatureLayer();
            _claimsPinLayer.Url = "https://" + WebServiceDomain + "/arcgis/rest/services/Claim/myLayer/FeatureLayer/0";
            
            _claimCluster = new ColorClusterer();
            _claimsPinLayer.Clusterer = _claimCluster;
            
            _claimsPinLayer.ID = "ClaimsPinLayer";
            _claimsPinLayer.OutFields.Add("*");
            _claimsPinLayer.Visible = true;

            _claimsPinLayer.InitializationFailed += this.OnClaimsPinLayer_InitializationFailed;
            _claimsPinLayer.UpdateCompleted += this.OnClaimsPinLayer_UpdateCompleted;

            _claimsPinLayer.Initialize();
            VisibleLayers.Add(_claimsPinLayer);
        }



The end result is:
Each cluster graphic will determine it's count
Set the Static Colors in the factory
Creates the Control Template each time to avoid a REF issue in the resource dictionary and does not require cloning of templates

There is still room for improvement if someone wants to take this and run with it. For example, this is only written to allow 6 mini graphics out of a cluster, and beyond that you have the same big circle. This could be writen as a loop that dynamically appends the String returned for the XAML Reader foreach count in the cluster as long as it doesn't exceed MaxCount Cluster ect... Point being, this is a quick fix to get it running and for my need I only need up to six coming out of my cluster so if you need more, you can either create an additional string template or implement a loop to dynamically create the string instead of remaking it each time.

Hope this helps someone save the time I went through. Props to Dominique for the template and starting point that I went off.

Thanks,

Sam
0 Kudos
DominiqueBroux
Esri Frequent Contributor
I agree with you that might be a built in function but strangly it's the first time I heard about such need.

Anyway, nice customization.
Thanks for sharing your code.
0 Kudos
AdamBauer
Deactivated User
I agree with you that might be a built in function but strangly it's the first time I heard about such need.


Dominique,  ESRI never heard of such a need? That surprises me.   I am having problems with this very issue right now.  I have a map with crime locations for our police force.  Every crime type is symbolized by a different symbol.  Where you have locations of higher crime you end up with stacked or clumped points.  I remembered seeing the silverlight demos some time back and the flare cluster and thought it would be perfect.   After trying it out a bit I found it actually ended up being useless for my needs as it makes everything the same symbol.  What I need is the cluster symbol with the number to explode out into the individual points with their respective symbols not to explode out into individual points with a single symbol.  Is there any way to do that either out of the box or through scripting (and if so is it possible by a very novice programmer)?
0 Kudos