ArcGIS for Silverlight API中沒有像ArcGIS Engine中的BalloonCallout。最近花了兩天時間在Silverlight中實現了類似的效果。雖然比較粗糙,不過基本能滿座需求吧,後續急需完善。現將實現思路介紹如下。
1、bubble容器的兩條對角線將bubble容器分爲4個象限。當鼠標拖動該容器移動時,錨點會落到其中的一個象限中,從而改變箭頭的方向。
2、繪製bubble,從A點(起點)順時針繪製。
代碼如下:
GeneralTransform gt = _ContentContainer.TransformToVisual(Application.Current.RootVisual as UIElement); Point offset = gt.Transform(new Point()); Point ArrowHead = new Point(Anchor.X - offset.X, Anchor.Y - offset.Y); PathGeometry geometry = new PathGeometry(); PathFigure figure = new PathFigure { IsClosed = true }; geometry.Figures.Add(figure); figure.StartPoint = new Point(source.X, source.Y + CornerRadius); figure.Segments.Add(new ArcSegment { Point = new Point { X = source.X + CornerRadius, Y = source.Y }, SweepDirection = SweepDirection.Clockwise, Size = new Size { Width = CornerRadius, Height = CornerRadius } }); figure.Segments.Add(new LineSegment { Point = new Point { X = source.X + ContentWidth / 2 - Leaderwidth / 2, Y = source.Y } }); figure.Segments.Add(new LineSegment { Point = ArrowHead }); figure.Segments.Add(new LineSegment { Point = new Point { X = source.X + ContentWidth / 2 + Leaderwidth / 2, Y = source.Y } }); figure.Segments.Add(new LineSegment { Point = new Point { X = source.X + ContentWidth - CornerRadius, Y = source.Y } }); figure.Segments.Add(new ArcSegment { Point = new Point { X = source.X + ContentWidth, Y = source.Y + CornerRadius }, SweepDirection = SweepDirection.Clockwise, Size = new Size { Width = CornerRadius, Height = CornerRadius } }); figure.Segments.Add(new LineSegment { Point = new Point { X = source.X + ContentWidth, Y = source.Y + ContentHeight - CornerRadius } }); figure.Segments.Add(new ArcSegment { Point = new Point { X = source.X + ContentWidth - CornerRadius, Y = source.Y + ContentHeight }, SweepDirection = SweepDirection.Clockwise, Size = new Size { Width = CornerRadius, Height = CornerRadius } }); figure.Segments.Add(new LineSegment { Point = new Point { X = source.X + CornerRadius, Y = source.Y + ContentHeight } }); figure.Segments.Add(new ArcSegment { Point = new Point { X = source.X, Y = source.Y + ContentHeight - CornerRadius }, SweepDirection = SweepDirection.Clockwise, Size = new Size { Width = CornerRadius, Height = CornerRadius } }); figure.Segments.Add(new LineSegment { Point = new Point(source.X, source.Y + CornerRadius) });
3、拖動bubble容器,比較簡單,廢話不多講。代碼是沒有二義性的,看代碼就能明白。直接上代碼吧。
void Bubble_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) { ContentControl item = sender as ContentControl; if (isMouseCaptured) { // Calculate the current position of the object. double deltaV = e.GetPosition(null).Y - mouseVerticalPosition; double deltaH = e.GetPosition(null).X - mouseHorizontalPosition; double newTop = deltaV + (double)item.GetValue(Canvas.TopProperty); double newLeft = deltaH + (double)item.GetValue(Canvas.LeftProperty); // Set new position of object. item.SetValue(Canvas.TopProperty, newTop); item.SetValue(Canvas.LeftProperty, newLeft); // Update position global variables. mouseVerticalPosition = e.GetPosition(null).Y; mouseHorizontalPosition = e.GetPosition(null).X; Render(deltaH, deltaV); } } void Bubble_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { ContentControl item = sender as ContentControl; isMouseCaptured = false; item.ReleaseMouseCapture(); mouseVerticalPosition = -1; mouseHorizontalPosition = -1; } void Bubble_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { ContentControl item = sender as ContentControl; mouseVerticalPosition = e.GetPosition(null).Y; mouseHorizontalPosition = e.GetPosition(null).X; isMouseCaptured = true; item.CaptureMouse(); }
4、最終效果
下一篇介紹在ArcGIS for Silverlight API中集成該功能,實現地圖上的扯旗標註。