/// <summary> /// A callback method that is used to generate a pushpin for a cluster of entities. /// </summary> /// <param name="cluster">A clustered point.</param> /// <returns>A pushpin that represents the clustered entities.</returns> public abstract ColoredPushpin RenderCluster(ClusteredPoint cluster);
private void Cluster(int zoom) { BackgroundWorker worker = new BackgroundWorker(); worker.WorkerSupportsCancellation = true; worker.DoWork += (s, a) => { _zoomLocked[zoom] = true; if (_clusteredData[zoom] == null) { _clusteredData[zoom] = new List <ClusteredPoint>(); } if (_entities != null && _entities.Count > 0) { double tileZoomRatio = 256 * Math.Pow(2, zoom); Point pixel; bool IsInCluster; //Itirate through the data foreach (var entity in _entities) { IsInCluster = false; pixel = Helpers.CalculateGlobalPixel(entity.Location, tileZoomRatio); foreach (var cluster in _clusteredData[zoom]) { //See if pixel fits into any existing clusters if (pixel.Y >= cluster.Top && pixel.Y <= cluster.Bottom && ((cluster.Left <= cluster.Right && pixel.X >= cluster.Left && pixel.X <= cluster.Right) || (cluster.Left >= cluster.Right && (pixel.X >= cluster.Left || pixel.X <= cluster.Right)))) { cluster.EntityIds.Add(entity.ID); IsInCluster = true; break; } } //If entity is not in a cluster then it does not fit an existing cluster if (!IsInCluster) { ClusteredPoint cluster = new ClusteredPoint(); cluster.Location = entity.Location; cluster.Left = pixel.X - _options.ClusterRadius; cluster.Right = pixel.X + _options.ClusterRadius; cluster.Top = pixel.Y - _options.ClusterRadius; cluster.Bottom = pixel.Y + _options.ClusterRadius; cluster.Zoom = zoom; cluster.EntityIds = new List <int>() { entity.ID }; if (cluster.Left < 0) { cluster.Left += tileZoomRatio; } if (cluster.Right > tileZoomRatio) { cluster.Right -= tileZoomRatio; } _clusteredData[zoom].Add(cluster); } } } }; worker.RunWorkerCompleted += (s, a) => { _zoomLocked[zoom] = false; Render(); }; worker.RunWorkerAsync(); }
private void Cluster() { int zoom = (int)Math.Round(_map.ZoomLevel); if (_worker == null) { _worker = new BackgroundWorker(); _worker.WorkerSupportsCancellation = true; _worker.DoWork += (s, a) => { if (_entities != null && _entities.Count > 0) { int gridSize = _options.ClusterRadius * 2; int numXCells = (int)Math.Ceiling(_map.ViewportSize.Width / gridSize); int numYCells = (int)Math.Ceiling(_map.ViewportSize.Height / gridSize); int numCells = numXCells * numYCells; ClusteredPoint[] clusteredData = new ClusteredPoint[numCells]; Point pixel; int k, j, key; int maxX = (int)Math.Ceiling(_map.ViewportSize.Width + _options.ClusterRadius); int maxY = (int)Math.Ceiling(_map.ViewportSize.Height + _options.ClusterRadius); //Itirate through the data foreach (var entity in _entities) { if (_worker.CancellationPending) { a.Cancel = true; break; } pixel = _map.LocationToViewportPoint(entity.Location); //Check to see if the pin is within the bounds of the viewable map if (pixel != null && pixel.X <= maxX && pixel.Y <= maxY && pixel.X >= -_options.ClusterRadius && pixel.Y >= -_options.ClusterRadius) { //calculate the grid position on the map of where the location is located k = (int)Math.Floor(pixel.X / gridSize); j = (int)Math.Floor(pixel.Y / gridSize); //calculates the grid location in the array key = k + j * numXCells; if (key >= 0 && key < numCells) { if (clusteredData[key] == null) { clusteredData[key] = new ClusteredPoint() { Location = entity.Location, EntityIds = new List <int>() { entity.ID }, Zoom = zoom }; } else { clusteredData[key].EntityIds.Add(entity.ID); } } } } if (!a.Cancel) { a.Result = clusteredData.ToList(); } } }; _worker.RunWorkerCompleted += (s, a) => { if (!a.Cancelled) { if (a.Result != null) { Render(a.Result as List <ClusteredPoint>); } else { Render(null); } } else { _worker.RunWorkerAsync(); } }; } if (_worker != null && _worker.IsBusy && _worker.WorkerSupportsCancellation) { _worker.CancelAsync(); } else { _worker.RunWorkerAsync(); } }