Clicking on an annotation

Oystein Bjorke il y a 10 ans 0
This discussion was imported from CodePlex

Slxe wrote at 2014-05-01 17:46:

Hello! Just wanted to start by saying thanks for all the hard work on this awesome project. I'm hoping to move our current heavy chart implementation over to it in the coming months, just working on various demos to impress people that don't care about the code side of things.

I've read through the code for the various mouse event examples but haven't had one that covers my issue. I'm looking to dynamically add and remove events to annotations, which means I've had to implement them as methods instead of lambdas.

The issue I'm running into now is how to actually get the annotation clicked on from what's passed to the method. I haven't found a way to access it from the PlotController or OxyMouseDownEventArgs.

Any suggestions are much appreciated! It wouldn't be the first time I'd missed something obvious hehe. Hopefully when I'm done this I'll have something interesting to add to the WinForms demos and help other people out.

Slxe wrote at 2014-05-09 17:13:

I guess due to lack of response there's no way to do this right now unless I want to create my own Annotation or a similar strategy?

objo wrote at 2014-05-10 22:54:

Thanks for pointing us to this issue! I think the implementation of the EventHandler<T> pattern was wrong. The On* methods in the UIPlotElement should not take the sender as a parameter. Also, I see it is convenient to include the element that is hit in the HitTestResults.
I am submitting a change that should fix this. I have added two examples that should be close to what you need. Have a look at the source code!

Slxe wrote at 2014-05-12 16:07:

Hey! Thanks for the answer, sorry for taking a few days to respond, but I wanted to while I had my code in front of me.

Yea I noticed HitTestResults only had the item and index, it didn't actually have a reference to the element clicked on, so I was hoping to find another solution. Thanks for the examples and the fix, this is exactly what I was hoping for! I'm playing around with the idea of adding a drawing toolbar to the chart display to allow the users to draw annotations onto it without having to save it and editing it in paint, with the added bonus of having things drawn be below the series I figured it'd quite helpful and faster than what they're doing now for their reports. Hopefully when I'm done I can cut it up and submit it as an example too.

Now I just have to find a nice way to sync the Axes when the user Zooms. I've got it working for just plain zooming (and panning), but I had to disable mouse wheel and +/- zooming as using ZoomAt throws it all to hell (I'm essentially transforming the actual minimum and maximum points to a screen point, then back to points on the new axes). I noticed the wdf example, but it doesn't help much when the axes have very different data on them. Would be nice if the AxisChanged event somehow had access to the pan/zoom amounts.

Thanks again for the help objo.

objo wrote at 2014-05-12 16:34:

Yes, please create an example with an annotation toolbar. I am sure this can be a popular example.

We have a feature request for synchronization of the axes: https://oxyplot.codeplex.com/workitem/9945
I am not sure if this covers your case, I don't quite understand your usage.
It should be easy to add pan/zoom deltas in the axis changed event arguments, but I have not yet seen a need for this.

Slxe wrote at 2014-05-12 17:20:

Yea I saw that request while looking around for a solution. Basically I just want to be able to zoom into an area using the Zoom Rectangle feature, and have all axes change their min and max for the area zoomed into, instead of just the primary vertical and horizontal axes. Like I said I'm currently doing it like so:
private void axis_AxisChanged(object sender, AxisChangedEventArgs args)
{
    if (_syncChange || ((Axis) sender).IsHorizontal())
        return;
    
    _syncChange = true;
    switch (args.ChangeType)
    {
        case AxisChangeTypes.Zoom:
        case AxisChangeTypes.Pan:
            _pauseChartUpdate = true;
            foreach (Axis a in mainPlot.Model.Axes)
            {
                if (a.Key == ((Axis) sender).Key || a.IsHorizontal())
                    continue;

                double min = a.InverseTransform(((Axis) sender).Transform(((Axis) sender).ActualMinimum));
                double max = a.InverseTransform(((Axis) sender).Transform(((Axis) sender).ActualMaximum));

                a.Zoom(min, max);
            }
            break;

        case AxisChangeTypes.Reset:
            _pauseChartUpdate = false;
            break;
    }

    mainPlot.InvalidatePlot(false);
    _syncChange = false;
}
Ignore the _pauseChartUpdate bool, since this is being used for real time data, they wanted two different kinds of zooms, essentially one that pauses the chart when zoomed in on an area, and one that you can actually watch the chart update in the zoomed area, and I'm still playing with it.

But yea, this is basically how I'm handling syncing panning and zooming to the other axes. Probably not the best way to do it, but I'm still learning, and it works. This is why I mentioned it'd be nice for AxisChangedEventArgs to have the various zoom and pan values so if required it can transfer them to other axes (a way to tell the difference between Zoom and ZoomAt, basically points vs factor, would be nice too). Although because of how I've done this, if you use a zoom factor instead of screen points it doesn't translate properly to the other axes (the primary axes goes out of sync with the others).

guilhermecgs wrote at 2014-05-16 23:56:

I´m always getting HitTestResult.Item = null on a ScatterSeries MouseDown Event. Is it related to this discussion. (I´m using the latest version)