2
$\begingroup$

I'm having trouble finding a way to play an animation (inside Manipulate) if a certain condition is met.

I'm representing liquid volume with rectangles and if the controls result in the liquid volume exceeding 1 (liter), then the liquid should "drain" from the container. I have not been able to figure out how to run an animation inside Manipulate that plays once and only if the volume limit is exceeded.

Here is a simplified version of the code, where vLIQ represents the calculated volume:

Manipulate[
 Module[{vol},
  vol := If[vLIQ <= 1, vLIQ, 0];
  Graphics[{
FaceForm[Opacity[0.6, Green]], Rectangle[{0, 0}, {0.5, vol}], 
EdgeForm[Thick], FaceForm[None], Rectangle[{0, 0}, {0.5, 1}],
Thick, Black, Line[{{0, vol}, {0.6, vol}}],
Text[Style[vol, 16], {0.7, vol}],
},
 ImageSize -> 230, PlotRange -> {-0.1, 1.1}, ImagePadding -> 10]],
 {{vLIQ, 0.75, ""}, 0.25, 1.2, 0.1, Appearance -> "Labeled"}]

And the behavior I want to show (minus the animation of the green rectangle slowly going to zero if vLIQ is greater than 1):

enter image description here

$\endgroup$

2 Answers 2

2
$\begingroup$

DynamicWrapper is a way to introduce such a dynamically updated animation. In the code below, the animation is not started until the user lets go of the control (via $ControlActiveSetting).

Manipulate[
 Graphics[
  DynamicWrapper[
   {FaceForm[Opacity[0.6, Green]],
    Rectangle[{0, 0}, {0.5, vLIQ}],
    EdgeForm[Thick], FaceForm[None], Rectangle[{0, 0}, {0.5, 1}], 
    Thick, Black, Line[{{0, vLIQ}, {0.6, vLIQ}}], 
    Text[Style[vLIQ, 16], {0.7, vLIQ}]
    },
   If[vLIQ >= 1 || draining,
    If[vLIQ >= 1,
     vLIQ = 1;                           (* keep the control from exceeding 1 *)
     start = SessionTime[]; draining = ! $ControlActiveSetting;];
    If[draining, vLIQ = 1 + start - SessionTime[]];  (* decrement vLIQ *)
    If[vLIQ <= 0.25, vLIQ = 0.25; draining = False]; (* reset when hit bottom *)
    ]
   ], ImageSize -> 230, PlotRange -> {-0.1, 1.1}, 
  ImagePadding -> 10],
 {{vLIQ, 0.75, ""}, 0.25, 1.2, 0.1, Appearance -> "Labeled", 
  Enabled -> Dynamic@Not@draining},                  (* turn off control while draining *)
 {draining, {False, True}, ControlType -> None},
 {start, ControlType -> None}
 ]
$\endgroup$
0
$\begingroup$

Here's one approach:

Manipulate[
 Module[{}, 
  If[0 < vLIQ <= 1, Pause[0.1]; vLIQ = vLIQ + 0.01;, vLIQ = 0];
  vol = vLIQ;
  Graphics[{FaceForm[Opacity[0.6, Green]], 
    Rectangle[{0, 0}, {0.5, vol}], EdgeForm[Thick], FaceForm[None], 
    Rectangle[{0, 0}, {0.5, 1}], Thick, Black, 
    Line[{{0, vol}, {0.6, vol}}], Text[Style[vol, 16], {0.7, vol}],}, 
   ImageSize -> 230, PlotRange -> {-0.1, 1.1}, 
   ImagePadding -> 10]], {{vLIQ, 0.15, ""}, 0.0, 1.2, 0.1, 
  Appearance -> "Labeled"}]

Change the length of the Pause or the size of the increment (0.01) to change the speed of the simulation. As you can see, it only plays once. because the increment only happens when vLIQ is (strictly) positive.

$\endgroup$
1
  • $\begingroup$ Bill, I'm afraid you might have misunderstood the desired behavior. In my understanding, the OP wanted the Manipulate to work normally at all times, except that, if the user hits a value of vLIQ that's higher than 1, an Animation kicks in to slowly "drain" the green rectangle down to zero, after which the Manipulate is reset to normal behavior once again. BTW, if that's really what he's asking, I have no idea how to achieve that :-) $\endgroup$
    – MarcoB
    Commented Jul 23, 2015 at 1:19

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.