A recent SO question reminded me of some code I tried to write a while back. The aim is to make a CircularSlider[]
object that can be used for angle-like variables in dynamic objects.
The framework for my solution (below) comes from the ValueThumbSlider[]
defined in the Advanced Manipulate Functionality tutorial. The main difference is that in ValueThumbSlider[]
the value of the slider and the position of the LocatorPlane[]
are the same thing, whilst in my CircularSlider[]
they are not - and this leads to problems.
The first problem is that moving the Locator
will not change the slider value. This is fixed by using the 2nd argument in the Dynamic
: (x = #/Abs[Complex @@ #]) &
.
This in turn leads to the problem that if you externally set the value of the slider (t
) from outside, it will immediately revert to its previous value. This is fixed by keeping the old value (t0
) and comparing to t
. If they don't match then it's assumed that t has changed and so the Locator
position x
is updated to its new position.
CircularSlider[t_] := CircularSlider[t, {0, 1}];
CircularSlider[Dynamic[t_], {min_, max_}] /; max > min :=
With[{d = (max - min)/(2. Pi)},
DynamicModule[{td = t/d, x, t0}, x = {Cos[td], Sin[td]};
LocatorPane[
Dynamic[If[!NumberQ[t], t = min; x = {Cos[td], Sin[td]}];
If[t != t0, t0 = t; x = {Cos[td], Sin[td]}];
t = Mod[Arg[Complex @@ x] d, max, min]; t0 = t;
x, (x = #/Abs[Complex @@ #]) &],
Graphics[{AbsoluteThickness[1.5], Circle[],
Dynamic[{Text[NumberForm[t, {3, 2}], {0, 0}]}]}],
ImageSize -> Sma开发者_开发问答ll]]]
So my question is: can someone make this work with out the above kludges?
As for problem#1, I wouldn't consider the use of the second argument to Dynamic
as a kludge -- that is what the second argument is for. Therefore, I don't have an alternative solution for that one.
Problem #2 can be avoided if you refrain from assigning t
in the first argument to Dynamic
.
With this in mind, here is another implementation:
CircularSlider2[Dynamic[t_], r:{min_, max_}:{0, 1}] :=
DynamicModule[{scale, toXY, fromXY},
scale = (max - min) / (2. Pi);
toXY[a_?NumberQ] := Through@{Cos, Sin}[a / scale];
toXY[a_] := {1, 0};
fromXY[{x_, y_}] := Mod[Arg[x + I y] scale, max, min];
LocatorPane[
Dynamic[toXY[t], (t = fromXY[#])&],
Graphics[{
AbsoluteThickness[1.5], Circle[],
Dynamic[{Text[NumberForm[t, {3,2}], {0, 0}]}]
}],
ImageSize -> Small
]
]
The only material difference between this version and the original version is that the first argument to Dynamic
is an expresssion that is free of side-effects.
Edit
I just stumbled across this undocumented experimental feature in Mathematica 8:
DynamicModule[{x = RandomReal[{0, 50}]},
{Experimental`AngularSlider[Dynamic@x], Dynamic@x}
]
精彩评论