10
$\begingroup$

We can restrict the movement of locators in a LocatorPane as follows:

locator movement

In the following example, the first locator's movement is confined to the x-axis and the second locator's movement is confined to the y-axis.

Manipulate[LocatorPane[Dynamic[pts], 
 Graphics[{}, PlotRange -> max, Axes -> True, ImageSize -> 350],
 {{{-max, 0}, {max, 0}},
 {{0, -max}, {0, max}}}],
{{pts, {{9, 0}, {0, 11}}}, ControlType -> None}, Initialization :> {max = 25}]

enter image description here

However, a locator can be dragged without necessarily being selected. You can begin dragging a locator by clicking down on just about any point in the four quadrants and dragging from there.

I would like to have the locator respond only to drags that are initiated by "mousedown"ing on the locator itself.

Any ideas as to how I might achieve this?


Addendum In my the more complicated example I've been working with, I've made use of jump parameters to confine locators to integer values:

{{{-maxX, 0}, {maxX, 0}, {1, 0}},
{{0, -maxY}, {0, maxY}, {0, 1}}}

I'm not sure whether such constraints (to integers) can be imposed on locators outside of LocatorPanes.

$\endgroup$

2 Answers 2

9
$\begingroup$

That is the default (and expected) behaviour of LocatorPane. This is useful in implementing things like colour pickers, for example, where it is convenient to simply click on any point to select that colour and have the locator move there automatically to indicate selection.

To create locators that move only when explicitly clicked and dragged, use a Locator. Here's an example for the scenario in the question:

DynamicModule[{pt1 = {-5, 0}, pt2 = {0, 5}},
    With[{max = 25},
        Graphics[{
            Locator[Dynamic[pt1, (pt1 = {First@#, 0}) &]], 
            Locator[Dynamic[pt2, (pt2 = {0, Last@#}) &]]
            }, PlotRange -> max, Axes -> True, ImageSize -> 350
        ]
    ]
]
$\endgroup$
15
  • $\begingroup$ They behave very nicely! $\endgroup$
    – DavidC
    Jul 30, 2012 at 21:31
  • $\begingroup$ The LocatorPane doc says: "LocatorPane[pts,back,range] by default directs any click to the nearest locator." It makes you wonder if there is a non-default setting. I couldn't find anything about that. I also note that this behaviour is the same in a Locator in a Manipulate. It is actually strange that a Locator in a Graphics has a different behaviour. $\endgroup$ Jul 30, 2012 at 21:46
  • $\begingroup$ There is one minor drawback with R.M.'s otherwise excellent solution: if you click away from the Locator, a graphics boarder will appear and remain visible. This does not occur with LocatorPane. $\endgroup$
    – DavidC
    Jul 30, 2012 at 21:49
  • $\begingroup$ @SjoerdC.deVries The next sentence says what the non-default option is — it creates new locators where you clicked, instead of moving the nearest one. So "default" in that context refers to some other behaviour $\endgroup$
    – rm -rf
    Jul 30, 2012 at 21:56
  • 1
    $\begingroup$ @DavidCarraher issue with frame can be fixed with Style[Graphics[...], Selectable -> False] $\endgroup$ Jul 30, 2012 at 22:10
3
$\begingroup$

This is the bare bone implementation with direct control of mouse events:

DynamicModule[{p = {0, 0}}, EventHandler[Framed@Dynamic[Style[
  Graphics[{Red, Disk[p, 0.2]}, PlotRange -> 2], Selectable -> False]], 
      {"MouseDragged" :> (p = MousePosition["Graphics"])}]]

And this is more or less what you need:

DynamicModule[{p1 = {0, 2}, p2 = {2, 0}}, EventHandler[
  Dynamic[Style[Graphics[{{Red, Disk[{0, Round@p1[[2]]}, .2]}, {Blue, 
       Disk[{Round@p2[[1]], 0}, .2]}}, PlotRange -> 5, Axes -> True], 
    Selectable -> False]],{"MouseDragged" :> (If[
       EuclideanDistance[p1, MousePosition["Graphics"]] < 
        EuclideanDistance[p2, MousePosition["Graphics"]], 
       p1 = MousePosition["Graphics"], p2 = MousePosition["Graphics"]];)}]]

enter image description here

It is a bit hacky, but because of integer settings it works.

$\endgroup$
1
  • $\begingroup$ This code selects which locator is closer to the mouse position. It's a nice approach, but unfortunately it doesn't solve my problem. In a more complex implementation that I am designing, there are other graphics objects on the screen (points that look somewhat like the locators). The locators affect, for instance the slope of a line going through the origin. I want to leave it unambiguous about which object,i.e. a particular locator (and not a nearby point) is "responding" to the actions of the mouse. $\endgroup$
    – DavidC
    Aug 1, 2012 at 13:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.