How to manipulate a circle in GeoGebra style?
This is what I find more intuitive:
circle[] := DynamicModule[{a = {0, 0}, b = {1, 0}, r = 1, w},
{
Dynamic@Circle[a, r],
Locator[Dynamic[a, {(w = b - a) &, (a = #; b = a + w) &, None}]],
Locator[Dynamic[b, (b = #; r = Norm[b - a]) &]]
}]
Graphics[circle[], Frame -> True, PlotRange -> 2]
And this is what fits well OP's example:
circle2[] := DynamicModule[{a = {0, 0}, b = {1, 0}, r = 1, s, p, hand},
{Thick,
EventHandler[
Dynamic@hand@Circle[a, r],
{"MouseDown" :> {s = {p[], a, b}; },
"MouseDragged" :> {{a, b} = (p[] - s[[1]] + #) & /@ Rest[s]}
}],
Locator[Dynamic[a, (a = #; r = Norm[b - a]) &]],
Locator[Dynamic[b, (b = #; r = Norm[b - a]) &]]}
,
Initialization :> (
p[] := MousePosition["Graphics"];
hand = MouseAppearance[#, "LinkHand"] &;
)]
Graphics[circle2[], Frame -> True, PlotRange -> 2]
You can improve styling ofc.
I do nor know how to implement what you want to do in a Manipulate
expression using locators, because I don't know how to handle mouse events in a Manipulate
expression. However, if you are willing to accept an answer using EventHandler
, the behavior you ask for isn't very difficult to implement.
With[{δ = .2},
DynamicModule[{p1 = {0, 0}, p2 = {2, 2}, mouse, action, dp},
EventHandler[
Dynamic @ Graphics[{
{PointSize[Large], Point[{p1, p2}]},
{Thick, Circle[p1, Norm[p2 - p1]]}},
Frame -> True,
PlotRange -> 5],
{"MouseDown" :>
(mouse = MousePosition["Graphics"];
action =
Which[
Norm[p1 - mouse] < δ , "p1",
Norm[p2 - mouse] < δ , "p2",
Abs[Norm[mouse - p1] - Norm[p2 - p1]] < δ , "circle"]),
"MouseDragged" :>
(mouse = MousePosition["Graphics"];
Switch[action,
"p1", p1 = mouse,
"p2", p2 = mouse,
"circle", dp = p2 - p1; p1 = mouse; p2 = p1 + dp])}]]]
The plan behind this code is
A mouse-down event detects what visual object the mouse is near. This in turn sets what action should be done during the drag.
A mouse-dragged event carries out the selected action.