FlexChart > FlexChart の操作 > FlexChart の要素 > 注釈 > 吹き出しの作成 |
チャート内で吹き出しを使用して、データ系列や個別のデータポイントの詳細を読みやすい形式で表示できます。データポイントに接続された吹き出しは、チャート領域内の見た目の乱雑さを最小限に抑え、チャートデータを見やすく、かつわかりやすくします。FlexChart では、Polygon 型の注釈をカスタマイズして、直線または矢印の接続線が付いた吹き出しをチャートに作成できます。
この例では、クイックスタートで作成したサンプルを使用して、矢印付き吹き出しと接続線付きの多角形注釈を作成します。それには、Points プロパティと ContentCenter プロパティを使用して、それぞれ多角形の頂点の座標と注釈のコンテンツの中心を定義します。
それぞれのデータポイントに接続される吹き出しを作成するには、次の手順に従います。
次の図に、矢印と接続線でデータポイントに接続される多角形注釈を示します。
直線付きの吹き出しを作成するには、次のコードを使用します。
... ' 多角形の線吹き出しの注釈を作成する Dim lineCallout = New C1.WPF.Chart.Annotation.Polygon() With { .Content = "最高", .Style = New ChartStyle() With { .Fill = New SolidColorBrush(Colors.Red) With { .Opacity = 200.0 / 255 }, .Stroke = New SolidColorBrush(Colors.Red) }, .Attachment = AnnotationAttachment.DataIndex, .SeriesIndex = 0, .PointIndex = 1, .ContentCenter = New Point(25, -40), .Points = New PointCollection(New Point() {New Point(0, 0), New Point(25, -25), New Point(50, -25), New Point(50, -50), New Point(25, -75), New Point(0, -50), New Point(0, -25), New Point(25, -25), New Point(0, 0)}) } ...
... // 多角形の線吹き出しの注釈を作成する var lineCallout = new C1.WPF.Chart.Annotation.Polygon() { Content = "最高", //多角形の線吹き出しの注釈のスタイル設定 Style = new ChartStyle() { Fill = new SolidColorBrush(Colors.Red) { Opacity = 200.0 / 255 }, Stroke = new SolidColorBrush(Colors.Red), }, Attachment = AnnotationAttachment.DataIndex, SeriesIndex = 0, PointIndex = 1, ContentCenter = new Point(25, -40), Points = new PointCollection(new Point[] { new Point(0, 0), new Point(25, -25), new Point(50, -25), new Point(50, -50), new Point(25, -75), new Point(0, -50), new Point(0, -25), new Point(25, -25), new Point(0, 0) }) }; ...
Private Sub SetUpAnnotations() annotationLayer.Annotations.Clear() ' 多角形の矢印吹き出しの注釈を作成する Dim contentCenter = New Point(25, -50) '矢印吹き出しの注釈のスタイル設定 Dim arrowCallout = New Annotation.Polygon() With { .Content = "最低", .Style = New ChartStyle() With { .Fill = New SolidColorBrush(Colors.Green) With { .Opacity = 200.0 / 255 }, .Stroke = New SolidColorBrush(Colors.Green) }, .Attachment = AnnotationAttachment.DataIndex, .SeriesIndex = 1, .PointIndex = 1, .ContentCenter = contentCenter, .Points = GetPointsForArrowCallout(contentCenter.X, contentCenter.Y, "最低") } ...
private void SetUpAnnotations() { annotationLayer.Annotations.Clear(); // 多角形の矢印吹き出しの注釈を作成する var contentCenter = new Point(25, -50); var arrowCallout = new Annotation.Polygon() { Content = "最低", //矢印吹き出しの注釈のスタイル設定 Style = new ChartStyle() { Fill = new SolidColorBrush(Colors.Green) { Opacity = 200.0 / 255 }, Stroke = new SolidColorBrush(Colors.Green), }, Attachment = AnnotationAttachment.DataIndex, SeriesIndex = 1, PointIndex = 1, ContentCenter = contentCenter, Points = GetPointsForArrowCallout(contentCenter.X, contentCenter.Y, "最低") }; ...
Private Function GetPointsForArrowCallout(centerX As Double, centerY As Double, content As String) As PointCollection Dim size As _Size = _engine.MeasureString(content) Return GetPointsForArrowCallout(centerX, centerY, CSng(size.Width) + 10, CSng(size.Height) + 10) End Function
PointCollection GetPointsForArrowCallout(double centerX, double centerY, string content) { _Size size = _engine.MeasureString(content); return GetPointsForArrowCallout(centerX, centerY, (float)size.Width + 10, (float)size.Height + 10); }
Private Function GetPointsForArrowCallout(centerX As Double, centerY As Double, rectWidth As Double, rectHeight As Double) As PointCollection Dim points = New PointCollection() Dim rectLeft As Double = centerX - rectWidth / 2 Dim rectRight As Double = centerX + rectWidth / 2 Dim rectTop As Double = centerY - rectHeight / 2 Dim rectBottom As Double = centerY + rectHeight / 2 Dim angle As Double = Math.Atan2(-centerY, centerX) Dim angleOffset1 As Double = 0.4 Dim angleOffset2 As Double = 0.04 Dim arrowHeight As Double = 0.4 * rectHeight Dim hypotenuse As Double = arrowHeight / Math.Cos(angleOffset1) Dim subHypotenuse As Double = arrowHeight / Math.Cos(angleOffset2) Dim isNearBottom As Boolean = Math.Abs(rectTop) > Math.Abs(rectBottom) Dim nearHorizontalEdge As Double = If(isNearBottom, rectBottom, rectTop) Dim isNearRight As Boolean = Math.Abs(rectLeft) > Math.Abs(rectRight) Dim nearVerticalEdge As Double = If(isNearRight, rectRight, rectLeft) Dim isHorizontalCrossed As Boolean = Math.Abs(nearHorizontalEdge) > Math.Abs(nearVerticalEdge) Dim nearEdge As Double = If(isHorizontalCrossed, nearHorizontalEdge, nearVerticalEdge) Dim factor As Integer = If(nearEdge > 0, -1, 1) Dim crossedPointOffsetToCenter As Double = If(isHorizontalCrossed, rectHeight / (2 * Math.Tan(angle)) * factor, rectWidth * Math.Tan(angle) * factor / 2) ' 矢印のポイント points.Add(New Point(0, 0)) points.Add(New Point(Math.Cos(angle + angleOffset1) * hypotenuse, -Math.Sin(angle + angleOffset1) * hypotenuse)) points.Add(New Point(Math.Cos(angle + angleOffset2) * subHypotenuse, -Math.Sin(angle + angleOffset2) * subHypotenuse)) ' 四角形のポイント If isHorizontalCrossed Then points.Add(New Point(-nearEdge / Math.Tan(angle + angleOffset2), nearEdge)) If isNearBottom Then points.Add(New Point(rectLeft, rectBottom)) points.Add(New Point(rectLeft, rectTop)) points.Add(New Point(rectRight, rectTop)) points.Add(New Point(rectRight, rectBottom)) Else points.Add(New Point(rectRight, rectTop)) points.Add(New Point(rectRight, rectBottom)) points.Add(New Point(rectLeft, rectBottom)) points.Add(New Point(rectLeft, rectTop)) End If points.Add(New Point(-nearEdge / Math.Tan(angle - angleOffset2), nearEdge)) Else points.Add(New Point(nearEdge, -nearEdge * Math.Tan (angle + angleOffset2))) If isNearRight Then points.Add(New Point(rectRight, rectBottom)) points.Add(New Point(rectLeft, rectBottom)) points.Add(New Point(rectLeft, rectTop)) points.Add(New Point(rectRight, rectTop)) Else points.Add(New Point(rectLeft, rectTop)) points.Add(New Point(rectRight, rectTop)) points.Add(New Point(rectRight, rectBottom)) points.Add(New Point(rectLeft, rectBottom)) End If points.Add(New Point(nearEdge, -nearEdge * Math.Tan (angle - angleOffset2))) End If ' 矢印のポイント points.Add(New Point(Math.Cos(angle - angleOffset2) * subHypotenuse, -Math.Sin(angle - angleOffset2) * subHypotenuse)) points.Add(New Point(Math.Cos(angle - angleOffset1) * hypotenuse, -Math.Sin(angle - angleOffset1) * hypotenuse)) Return points End Function
PointCollection GetPointsForArrowCallout(double centerX, double centerY, double rectWidth, double rectHeight) { var points = new PointCollection(); double rectLeft = centerX - rectWidth / 2; double rectRight = centerX + rectWidth / 2; double rectTop = centerY - rectHeight / 2; double rectBottom = centerY + rectHeight / 2; double angle = Math.Atan2(-centerY, centerX); double angleOffset1 = 0.4; double angleOffset2 = 0.04; double arrowHeight = 0.4 * rectHeight; double hypotenuse = arrowHeight / Math.Cos(angleOffset1); double subHypotenuse = arrowHeight / Math.Cos(angleOffset2); bool isNearBottom = Math.Abs(rectTop) > Math.Abs(rectBottom); double nearHorizontalEdge = isNearBottom ? rectBottom : rectTop; bool isNearRight = Math.Abs(rectLeft) > Math.Abs(rectRight); double nearVerticalEdge = isNearRight ? rectRight : rectLeft; bool isHorizontalCrossed = Math.Abs(nearHorizontalEdge) > Math.Abs(nearVerticalEdge); double nearEdge = isHorizontalCrossed ? nearHorizontalEdge : nearVerticalEdge; int factor = nearEdge > 0 ? -1 : 1; double crossedPointOffsetToCenter = isHorizontalCrossed ? rectHeight / (2 * Math.Tan(angle)) * factor : rectWidth * Math.Tan(angle) * factor / 2; // 矢印のポイント points.Add(new Point(0, 0)); points.Add(new Point(Math.Cos(angle + angleOffset1) * hypotenuse, -Math.Sin(angle + angleOffset1) * hypotenuse)); points.Add(new Point(Math.Cos(angle + angleOffset2) * subHypotenuse, -Math.Sin(angle + angleOffset2) * subHypotenuse)); // 四角形のポイント if (isHorizontalCrossed) { points.Add(new Point(-nearEdge / Math.Tan(angle + angleOffset2), nearEdge)); if (isNearBottom) { points.Add(new Point(rectLeft, rectBottom)); points.Add(new Point(rectLeft, rectTop)); points.Add(new Point(rectRight, rectTop)); points.Add(new Point(rectRight, rectBottom)); } else { points.Add(new Point(rectRight, rectTop)); points.Add(new Point(rectRight, rectBottom)); points.Add(new Point(rectLeft, rectBottom)); points.Add(new Point(rectLeft, rectTop)); } points.Add(new Point(-nearEdge / Math.Tan(angle - angleOffset2), nearEdge)); } else { points.Add(new Point(nearEdge, -nearEdge * Math.Tan(angle + angleOffset2))); if (isNearRight) { points.Add(new Point(rectRight, rectBottom)); points.Add(new Point(rectLeft, rectBottom)); points.Add(new Point(rectLeft, rectTop)); points.Add(new Point(rectRight, rectTop)); } else { points.Add(new Point(rectLeft, rectTop)); points.Add(new Point(rectRight, rectTop)); points.Add(new Point(rectRight, rectBottom)); points.Add(new Point(rectLeft, rectBottom)); } points.Add(new Point(nearEdge, -nearEdge * Math.Tan(angle - angleOffset2))); } // 矢印のポイント points.Add(new Point(Math.Cos(angle - angleOffset2) * subHypotenuse, -Math.Sin(angle - angleOffset2) * subHypotenuse)); points.Add(new Point(Math.Cos(angle - angleOffset1) * hypotenuse, -Math.Sin(angle - angleOffset1) * hypotenuse)); return points; }
チャートの注釈をレンダリングするには、次の手順に従います。
XAML |
コードのコピー
|
---|---|
<c1:C1FlexChart.Layers> <c1:AnnotationLayer x:Name="annotationLayer" /> </c1:C1FlexChart.Layers> |
annotationLayer.Annotations.Add(arrowCallout)
annotationLayer.Annotations.Add(lineCallout)
End Sub
annotationLayer.Annotations.Add(arrowCallout); annotationLayer.Annotations.Add(lineCallout); }
Private Sub flexChart_Rendered(sender As Object, e As C1.WPF.Chart.RenderEventArgs) Handles flexChart.Rendered If _engine Is Nothing Then _engine = e.Engine SetUpAnnotations() End If End Sub
private void flexChart_Rendered(object sender, C1.WPF.Chart.RenderEventArgs e) { if (_engine == null) { _engine = e.Engine; SetUpAnnotations(); } }