The clustering algorithm is expected to run on a seperate cancellable thread to prevent blocking the UI. On completion, raise ClusteringCompleted by invoking OnClusteringCompleted. The event should not be raised if clustering was cancelled.
run on a seperate cancellable thread to prevent blocking the UI
raise ClusteringCompleted by invoking OnClusteringCompleted
Hi Phil,Thanks for sharing the code, it was indeed very helpful !!I got my code working to a point where I can cluster according to an attribute of the graphic.The problem I am facing however is that I am not able to control the Zoom level.I tried to play with the range property (Increasing the range) and that helps but I am not sure this is the right way to do it.Can you help me on this.I am trying to give user different views of data at different Zoom levels using cluster.So at minimum Zoom and -> On block appears (which clusters all the graphics of same type).In between -> I want the block to appear (only the information I am displaying on the block increases)Maximum Zoom I want to make visible all the graphics.
public override void ClusterGraphicsAsync(IEnumerable<Graphic> graphics, double resolution) { int incomingTotal = graphics.Count(); int total = 0; //TODO run on seperate cancellable thread //BackgroundWorkers or Tasks executed on the thread pool are possible options. //if (bw.IsBusy != true) //{ // bw.RunWorkerAsync(); //} //else //{ //} GraphicCollection returnGraphics = new GraphicCollection(); //Group graphics into collections that will be turned into clusters IEnumerable<GraphicCollection> graphicGroups = groupGraphics(graphics, resolution); GraphicCollection gCollection; for (int i = 0; i < graphicGroups.Count(); i++ ) { gCollection = graphicGroups.ElementAt(i); if (gCollection.Count > 2) { Utility.removeTextSymbols(ref gCollection); //need to remove TextSymbols or else they will be counted MapPoint mp = getCenter(gCollection); Graphic cluster = OnCreateGraphic2(gCollection, mp, gCollection.Count); returnGraphics.Add(cluster); total += gCollection.Count; } else //should just add one TextSymbol and one GraphicSymbol { foreach (Graphic g in gCollection) { returnGraphics.Add(g); } total += 1; } } //raise ClusteringCompleted by invoking OnClusteringCompleted OnClusteringCompleted(returnGraphics); } private IEnumerable<GraphicCollection> groupGraphics(IEnumerable<Graphic> graphics, double resolution) { Queue<Graphic> q = new Queue<Graphic>(graphics); Collection<GraphicCollection> clusters = new Collection<GraphicCollection>(); int totalCount = 0; double range = resolution * 50; while (q.Count > 0) { Graphic g = q.Dequeue(); GraphicCollection gCollection = new GraphicCollection(); Envelope searchEnvelope = g.Geometry.Extent; //expand the evelope to include the search resolution searchEnvelope.XMax += (60*resolution); searchEnvelope.YMax += (60*resolution); searchEnvelope.XMin -= (60*resolution); searchEnvelope.YMin -= (60*resolution); gCollection.Add(g); //iterate through q, finding all graphics within extent if (q.Count > 0) { Graphic searchG = null; Graphic firstSearchG = null; Graphic prevSearchG = null; //remove graphics from queue that are within searchEvelope while (q.Count > 0 && (searchG == null || searchG != firstSearchG || prevSearchG == null)) { prevSearchG = searchG; searchG = q.Dequeue(); //new search graphic if (firstSearchG == null) { firstSearchG = searchG; } //if (searchEnvelope.Intersects(searchG.Geometry.Extent) == true) //if (envelopesIntersect(searchEnvelope, searchG.Geometry.Extent) == true) if (withinRange(g, searchG, range) == true) { if (searchG.Symbol.GetType() == typeof(ESRI.ArcGIS.Client.FeatureService.Symbols.PictureMarkerSymbol)) { gCollection.Insert(0,searchG); } else { gCollection.Add(searchG); //send textsymbol to end of colelction, so drawn last } totalCount++; if (searchG == firstSearchG) { firstSearchG = null; } } else { q.Enqueue(searchG); } } } clusters.Add(gCollection); } return clusters; } private bool withinRange(Graphic g1, Graphic g2, double range) { double a = g2.Geometry.Extent.YMax - g1.Geometry.Extent.YMax; double b = g2.Geometry.Extent.XMax - g1.Geometry.Extent.XMax; double c = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2)); if (c <= range) { return true; } return false; }
I'm also guessing that ClusterGraphicsAsync calls OnCreateGraphic?, but in that case what does it do with the returned graphics?
How do I run on a seperate cancellable thread to prevent blocking the UI
How do raise ClusteringCompleted by invoking OnClusteringCompleted
How does CancelAsync factor into all of this? Much they also be overridden, if so how?
4a) Does ClusterGraphicsAsync call OnCreateGraphic? 4b) If so, what do you do with the returning graphics?
4c) If you create clusters from the "graphics" parameters based on the "resolution" parameter, is there a smart way of doing this, as this seems like it can be very complicated and easily could be O(n^2)?
Angemeldete Mitglieder können Beiträge verfassen, Updates folgen und mehr. Neu hier? Registriere ein kostenloses Konto.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.