Расположение элемента при наведении - WPF - C# - Динамическое отображение данных
В динамическом отображении данных есть класс MarkerPointsGraph. Это происходит от FrameWorkElement (через ряд других классов по пути, самым непосредственным родителем которого является PointsGraphBase) и переопределяет OnRenderMethod для рисования набора маркеров на диаграмме.
Это делается путем вызова метода рендеринга с соответствующим типом маркера (скажем, треугольник, круг и т. Д.) Один раз для каждой точки, отображаемой на экране. Мне нужно найти способ определить, когда мышь находится на одном из этих маркеров, чтобы я мог установить подсказку для этого маркера.
У меня есть набор методов, которые позволяют мне преобразовывать точку из положения экрана в положение области просмотра и в положение данных и обратно. т.е. преобразует экранное значение в соответствующее значение данных или значение области просмотра и наоборот.
У меня также есть событие открытия всплывающей подсказки для этого элемента структуры и размер пикселя каждого из этих маркеров. Пока пользователь наводит курсор на конкретный маркер, мне нужно определить, в какой точке он завис, и позволить маркерному точечному графику установить значение всплывающей подсказки.
Тем не менее, преобразования и методы для преобразования значений, кажется, не работают нормально, особенно в направлении х. У-направление кажется хорошим.
Ниже приведен пример кода, который объяснит идею:
double selectedPointX = 0;
double selectedPointY = 0;
CoordinateTransform transformLocal = this.primaryPlotter.Transform;
if (series.SeriesDescription.YAxisAffinity == AxisAffinity_Y.Y1)
{
selectedPointX = Mouse.GetPosition(this.primaryPlotter).ScreenToViewport(transformLocal).X; //Getting the mouse positions
selectedPointY = Mouse.GetPosition(this.primaryPlotter).ScreenToViewport(transformLocal).Y;
}
else if (series.SeriesDescription.YAxisAffinity == AxisAffinity_Y.Y2 && injSecondaryAxis != null)
{
transformLocal = injSecondaryAxis.Transform;
selectedPointX = Mouse.GetPosition(this.injSecondaryAxis).ScreenToViewport(transformLocal).X;
selectedPointY = Mouse.GetPosition(this.injSecondaryAxis).ScreenToViewport(transformLocal).Y;
}
else if (series.SeriesDescription.YAxisAffinity == AxisAffinity_Y.Y3 && injTertiaryAxis != null)
{
transformLocal = injTertiaryAxis.Transform;
selectedPointX = Mouse.GetPosition(this.injTertiaryAxis).ScreenToViewport(transformLocal).X;
selectedPointY = Mouse.GetPosition(this.injTertiaryAxis).ScreenToViewport(transformLocal).Y;
}
foreach (var item in SeriesList)
{
if (item.Key == GraphKey)
{
for (int i = 0; i < item.Value.Collection.Count; i++)
{
//Calculate the size of the marker on the screen and allow for some level of inaccuracy in identifying the marker i.e anywhere within the marker is allowed.
double xlowerBound = item.Value.Collection[i].DataToViewport(transformLocal).X - series.MarkerSize;
double xUpperBound = item.Value.Collection[i].DataToViewport(transformLocal).X + series.MarkerSize;
double ylowerBound = item.Value.Collection[i].DataToViewport(transformLocal).Y - series.MarkerSize;
double yUpperBound = item.Value.Collection[i].DataToViewport(transformLocal).Y + series.MarkerSize;
//If point is within bounds
if (!(selectedPointX < xlowerBound || selectedPointX > xUpperBound || selectedPointY < ylowerBound || selectedPointY > yUpperBound))
{
strToolTip = item.Value.Collection[i].X + ", " + item.Value.Collection[i].Y; //This point is set as the tooltip
break;
}
}
break;
}
}
Здесь injSecondary и injTertiary - это два инжектированных плоттера, которые обеспечивают две вертикальные оси Y. Они ведут себя очень похоже на основной график плоттера.
Здесь что-то не так? По какой-то причине точки, намного опережающие фактическую точку щелчка, проходят через условие буфера.
2 ответа
Хм, похоже, ты поступаешь из-за этого неправильно для меня. Если вы покопаетесь в исходном коде D3, вы можете открыть один из классов маркеров и напрямую отредактировать подсказку. Каждый элемент System.Windows.Shapes имеет свойство Tooltip, которое можно назначить прямо в классе маркера. Все, что вам нужно сделать, это решить, какие данные содержит подсказка.
Пример - класс CircleElementPointMarker:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
namespace Microsoft.Research.DynamicDataDisplay.PointMarkers
{
/// <summary>Adds Circle element at every point of graph</summary>
public class CircleElementPointMarker : ShapeElementPointMarker {
public override UIElement CreateMarker()
{
Ellipse result = new Ellipse();
result.Width = Size;
result.Height = Size;
result.Stroke = Brush;
result.Fill = Fill;
if (!String.IsNullOrEmpty(ToolTipText))
{
ToolTip tt = new ToolTip();
tt.Content = ToolTipText;
result.ToolTip = tt;
}
return result;
}
public override void SetMarkerProperties(UIElement marker)
{
Ellipse ellipse = (Ellipse)marker;
ellipse.Width = Size;
ellipse.Height = Size;
ellipse.Stroke = Brush;
ellipse.Fill = Fill;
if (!String.IsNullOrEmpty(ToolTipText))
{
ToolTip tt = new ToolTip();
tt.Content = ToolTipText;
ellipse.ToolTip = tt;
}
}
public override void SetPosition(UIElement marker, Point screenPoint)
{
Canvas.SetLeft(marker, screenPoint.X - Size / 2);
Canvas.SetTop(marker, screenPoint.Y - Size / 2);
}
}
}
Вы можете видеть, что в этом классе есть встроенный код для обработки всплывающих подсказок. ToolTipText - это свойство, которое наследуется от родительского класса - ShapeElementPointMarker. Все, что вам нужно сделать, это назначить это свойство с данными, которые вам нужно показать.
Используйте курсор-координату на графике вместо Mouse.GetPosition, чтобы получить правильное положение экрана и избежать преобразования ScreenToViewport. Также используйте DataToScreen при создании границ.