开发者

Circular/Angular slider

开发者 https://www.devze.com 2023-01-29 22:44 出处:网络
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.

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]]]

Circular/Angular slider


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}
]

Circular/Angular slider

0

精彩评论

暂无评论...
验证码 换一张
取 消