question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IHittable: add snapping and respect data area clipping

See original GitHub issue

Feature Suggestion

Feature description:

Hello Scott, I just played a bit with the IHittable interface, and here are some comments about it and potential ideas to improve it I hope

  1. The current implementation of IHittable does not account for margins, as IDraggable does. There is no snap distance, making it difficult to implement and use IHittable on points (instead of polygons)
  2. At the moment, it seems IHittable can only be activated/disactivated, allowing to hit an object on an event (e.g) mouse click could be a nice addition if not already possible. This would improve performance for IHittable ScatterPlots
  3. I think the detection performed on draggables with the isUnderMouse is redundant with what should be implemented in HitTest, especially considering the addition of the snap distances. There is a probable refactor to be done here since IDraggable seems to be a IHittable (or more likely IHoverable but that just semantics) with extra steps.

The most difficult thing, with respect to the current implementation seems to be the ability to catch mouse events. Do you think this could be done without too much hassle ? Also that would be really nice to have that in v5 don’t you think ?

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
swhardencommented, Jul 29, 2022

How to select the nearest point on click (not on mouse move)

I have a set of points plotted and when clicking on one of these points I want to be able to find which one of them.

Hi @BambOoxX, I think I found a solution! Let me know if this helps you get your job done, and if not I’m happy to work together to come up with one. We can continue the conversation here or on the Discord! (#1966)

Does this code/screenshot adequately demonstrate the idea? This can be achieved using the existing published library.

click nearest

public partial class Form1 : Form
{
    Random Rand = new(0);
    double[] Xs;
    double[] Ys;
    ScottPlot.Plottable.MarkerPlot Marker;
    double SnapDistancePx = 50;

    public Form1()
    {
        InitializeComponent();
        (Xs, Ys) = DataGen.RandomWalk2D(Rand, 50);
        formsPlot1.Plot.AddScatter(Xs, Ys);
        Marker = formsPlot1.Plot.AddMarker(0, 0, MarkerShape.openCircle, 20, Color.Red);
        formsPlot1.LeftClicked += FormsPlot1_LeftClicked;
        formsPlot1.Plot.Title("Waiting for click...");
        formsPlot1.Refresh();
    }

    private void FormsPlot1_LeftClicked(object sender, EventArgs e)
    {
        (double mousePixelX, double mousePixelY) = formsPlot1.GetMousePixel();
        (double mouseX, double mouseY) = formsPlot1.GetMouseCoordinates();

        // determine the point in the scatter plot closest to the mouse
        double closestDistance = double.PositiveInfinity;
        int closestIndex = 0;
        for (int i = 0; i < Xs.Length; i++)
        {
            (double x, double y) = formsPlot1.Plot.GetPixel(Xs[i], Ys[i]);
            double dX = mousePixelX - x;
            double dY = mousePixelY - y;
            double distance = Math.Sqrt(dX * dX + dY * dY);
            if (distance < closestDistance)
            {
                closestDistance = distance;
                closestIndex = i;
            }
        }

        // take action based on whether the click engaged a point
        if (closestDistance < SnapDistancePx)
        {
            double x = Xs[closestIndex];
            double y = Ys[closestIndex];
            formsPlot1.Plot.Title($"Clicked point [{closestIndex}] (X={x:0.00}, Y={y:0.00})");
            Marker.IsVisible = true;
            Marker.X = x;
            Marker.Y = y;
        }
        else
        {
            formsPlot1.Plot.Title($"Clicked empty space (X={mouseX:0.00}, Y={mouseY:0.00})");
            Marker.IsVisible = false;
        }

        formsPlot1.Refresh();
    }
}

Let’s not modify IHittable

One of my big design goals for ScottPlot 5 is to make it easier to customize behavior using client-side code (rather than requiring a developer to anticipate and build-in all the various combinations of functionality users may want).

I still have some work to do figuring out the best API here, but I’m considering not supporting IHittable or even IDraggable, but instead trying to make it as easy as possible for the user to implement their own hit detection and/or dragging code on their side. We’ll see how it goes 🤞

I’m happy this issue resulted in a new WinForms demo showing how IHittable works (#1985), but I don’t think I’ll go all the way and add the complexity of unit/pixel state management necessary for IHittable to support pixel snapping.

0reactions
BambOoxXcommented, Jul 28, 2022

Regarding v5. I know very little about such complex designs, but would it be possible for each plottable to have a MouseEvent and KeyboardEvent property so that one could link actions to plottables?

Also, I think some sort of ReturnOnEvent could have practical use. Because in general when I want interaction in a plottable it’s because I need to retrieve some information about it related to the action I performed with either mouse or key.

Not sure if this helps but these are my two cents

Read more comments on GitHub >

github_iconTop Results From Across the Web

Plottable: IHittable · Issue #1844 · ScottPlot ...
I just added this internally to my program for vLines using the ... IHittable: add snapping and respect data area clipping #1962.
Read more >
Position elements with snapping in Photoshop
Use snapping. Snapping helps with precise placement of selection edges, cropping marquees, slices, shapes, and paths. However, if snapping ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found