Moving a locator based on the movement of another


My problem is:

I want two Locators to simulate a vector in the following sense:

  • The first Locator is the base and the second the tip of the vector.

  • When I move the tip, the base does not move (hence the vector changes).

  • When I move the base, the vector is unchanged, and therefore the tip (and the Locator) moves.

How can I achieve that?

I have tried storing the previous value of the base and then test if the current value is different. And if so updated the position of the tip. I can however not make that work, when using 'Module'. I suspect that there is a more elegant solution.


Posted 2013-08-13T10:34:18.703

Reputation: 633


This you look at the other related answers? Such as this:

– C. E. – 2013-08-13T10:36:58.900



This seems to be a duplicate but I can't find it :). Meanwhile, you can use second argument of Dynamic.

x = {0, 0}; y = {1, 1}; w = y - x;

                 Locator@Dynamic[x, (x = #; y = x + w;) &],
                 Locator@Dynamic[y, (y = #; w = y - x;) &],
                 Dynamic@Arrow[{x, y}]
                , PlotRange -> 2]

enter image description here

In case of multiple vectors one may want to save space and make code more transparent so we can use extended version of Dynamic second argument to achieve this:

                 Locator@Dynamic[x, {(w = y - x;) &, (x = #; y = x + w) &, None}],
                 Dynamic@Arrow[{x, y}]
               , PlotRange -> 2]

Now we are working only with base, moreover w can be scoped to particular Locator.

There is huge advantage of the second method, well, not exactly the method but the usage of f_start and f_end. You can calculate w once, not all the time you are dragging the Locator.


Posted 2013-08-13T10:34:18.703

Reputation: 129 207

+1 I like this answer a lot and a learned something from it! btw. while I researched it I noticed that the exact number of times w is calculated in the second version is twice every time you drag that locator. (Method; first n=0; and then inside the anonymous function Print[n++]). – C. E. – 2013-08-13T13:41:48.620

@Anon Indeed, I saw this too with Print. Do you know why it is so? – Kuba – 2013-08-13T13:45:11.597

No! I became very curious but I suppose there is no good answer. It's not what is says in the documentation so I guess that's just "how it is". – C. E. – 2013-08-13T13:47:13.390


p1save = {0, 0}; p2save = {1, 1};
        If[p1 != p1save, p2 = p2 + p1 - p1save; p1save = p1];
        Graphics[Arrow[{p1, p2}], PlotRange -> {{-5, 5}, {-5, 5}}, AspectRatio -> 1],
 {{p1, p1save}, Locator}, {{p2, p2save}, Locator}

or a little bit more sophisticated, preventing the arrow to overflow the graphics window:

p1save = {0, 0}; p2save = {1, 1};  min = -5; max = 5;
 If[Or @@ ((min > # || # > max) & /@ Flatten[{p1, p2 + p1 - p1save}]),
                                               p1 = p1save; p2 = p2save];
 If[p1 != p1save, p2 = p2 + p1 - p1save; p1save = p1; p2save = p2];
 Graphics[Arrow[{p1, p2}], PlotRange -> {{min, max}, {min, max}},  AspectRatio -> 1],
 {{p1, p1save}, Locator}, {{p2, p2save}, Locator}

Dr. belisarius

Posted 2013-08-13T10:34:18.703

Reputation: 112 848

Looking good. But somehow in the second example if I move the base of the arrow, the head of the arrow moves at constant speed. – Jacob Akkerboom – 2013-08-15T21:22:29.147