I have a linechart (i.e. a series segments linking my set of datapoints).
The ultrachart tooltip functionality only works when the mouse is near a datapoint. No tooltip is displayed when the mouse hovers on/near the segments between the datapoints, i.e. the points interpolated between the datapoints.
Is there a way to implement that myself?
I guess it would involve listening for mouse move events, take the mouse position, map it back to data coordinates, find the 2 neighboord data points in the data set, and see if the mouse lies close enough (by some threshold) to the interpolated segments between those 2 points. Is there a better way?
Thanks in advance.
that would be one way. you could also handle the FillSceneGraph, find the Polyline objects in your SceneGraph, and overlay Polygons. This will cause the polygons to show tooltips as well as raise DataItemOver and other chart events.
to make the polygons interactive, do this before adding them to the SceneGraph.
oly.Caps = PCaps.HitTest | PCaps.Tooltip
oly.Chart = myChart.ChartType
oly.Layer = e.ChartCore.GetChartLayer()
oly.Row = oly.Column = 0
Hi David,
Could you provide a sample of your solution? I can't figure out how you do this. I have a scatter chart where 2 points are connected with a line and I want to display a tooltip when my mouse is over the line as well as the mouse is over the datapoints
Thanks,
here you go.
in the Windows Forms ultrachart, polylines don't normally participate in hit testing, so what you need to do is create a transparent polygon to overlay the polyline.
the code goes like this:
private void ultraChart1_FillSceneGraph(object sender, FillSceneGraphEventArgs e)
{
PrimitiveCollection primitivesToAdd = new PrimitiveCollection();
foreach (Primitive currentPrimitive in e.SceneGraph)
Polyline currentPolyline = currentPrimitive as Polyline;
if (currentPolyline != null)
Polygon overlayPolygon = this.PolylineToPolygon(currentPolyline);
overlayPolygon.Caps |= PCaps.HitTest | PCaps.Tooltip;
overlayPolygon.PE.FillOpacity = overlayPolygon.PE.StrokeOpacity = 0;
overlayPolygon.Value = overlayPolygon.Row = overlayPolygon.Column = 0;
overlayPolygon.Chart = e.ChartCore.ChartType;
overlayPolygon.Layer = e.ChartCore.GetChartLayer();
primitivesToAdd.Add(overlayPolygon);
}
e.SceneGraph.AddRange(primitivesToAdd.ToArray());
private Polygon PolylineToPolygon(Polyline input)
double halfThickness = input.PE.StrokeWidth / 2.0;
double halfPi = Math.PI / 2.0;
//DataPoint[] newPoints = new DataPoint[input.points.Length * 2 + 1];
Point[] newPoints = new Point[input.points.Length * 2 + 1];
double[] slopes = new double[input.points.Length - 1];
for (int i = 0; i < input.points.Length - 1; i++)
slopes[i] = Slope(input.points[i].point, input.points[i + 1].point);
double segmentAngle = Math.Atan(slopes[i]);
double perpendicularAngle1 = segmentAngle + halfPi;
double perpendicularAngle2 = segmentAngle - halfPi;
Point segmentStart1 = Geometry.AngularToCartesian(input.points[i].point, halfThickness, perpendicularAngle1);
Point segmentStart2 = Geometry.AngularToCartesian(input.points[i].point, halfThickness, perpendicularAngle2);
Point segmentEnd1 = Geometry.AngularToCartesian(input.points[i + 1].point, halfThickness, perpendicularAngle1);
Point segmentEnd2 = Geometry.AngularToCartesian(input.points[i + 1].point, halfThickness, perpendicularAngle2);
newPoints[i] = segmentStart1;
newPoints[i + 1] = segmentStart2;
newPoints[newPoints.Length - i - 2] = segmentEnd1;
newPoints[newPoints.Length - i - 3] = segmentEnd2;
newPoints[newPoints.Length - 1] = newPoints[0];
return new Polygon(newPoints);
public static double Slope(PointF point1, PointF point2)
return (point2.Y - point1.Y) / (point2.X - point1.X);