1
$\begingroup$

I've created a keyboard-free panning system within Mathematica. The code does the job, but I continually get errors in relation to it, and I cannot seem to get it to perform within a CDF because of it. The main line of code that seems to be problematic is

ViewCenter -> {{1/2, 1/2, 1/2}, 
               {Dynamic[x = CurrentPosition[[1]] + panvalue[[1]]], 
                Dynamic[y = CurrentPosition[[2]] - panvalue[[2]]]}}

It may look messy, but basically it maps the center of a graphic, (1/2,1/2,1/2), to a new two-dimensional point based on the click and drag of the mouse. This seems fairly logical to me, but some may notice the seemingly unnecessary use of Dynamic in the above. These are created because the code only works until I manually interact with the craft through the use of Shift or Ctrl. Meaning, I can freely pan with my right-click and drag function until I decide to use the built in Mathematica interactons.

I think I may have discovered part of the error, in that the errors that I mentioned before say that I am calling ListQ with 0 arguments, but this function appears nowhere in my code. Furthermore, I was originally getting errors saying that CurrentPosition[[2]] and the other references to list elements were longer than the depth of their objects. However, with these all being references to points, shouldn't they have as many elements as I'm referencing? Any ideas on what could be the source of my issue?

I did my best to simplify the code, but it's still quite extensive. Feel free to ask for clarification and I will do my best. Looking at the Initialization should help a little.

Without the Dynamic around the Position updating,

Manipulate[
EventHandler[
Dynamic[Show[graphic, 
ViewCenter -> {{1/2, 1/2, 
   1/2}, {x = CurrentPosition[[1]] + panvalue[[1]], 
   y = CurrentPosition[[2]] - panvalue[[2]]}}]],
If[CurrentValue["AltKey"],
{{"MouseDown", 
  1} :> (a = CurrentValue[MousePosition]), {"MouseDragged", 
  1} :> {b = CurrentValue[MousePosition], drag = b - a, 
  panvalue = {drag[[1]]/(pt[[1]]), 
    drag[[2]]/(pt[[2]])}}, {"MouseUp", 1} :> {drag = {0, 0}, 
  panvalue = {0, 0}, CurrentPosition[[1]] = x, 
  CurrentPosition[[2]] = y}}]], SynchronousUpdating -> True, 
Initialization :> (CurrentPosition = {1/2, 1/2}; panvalue = {0, 0}; 
pt = CurrentValue[ImageSize]; drag = {0, 0}; a = {0, 0}; 
b = {0, 0})]

Feel free to try this, but it will likely allow you to pan by clicking and dragging when the Alt key is depressed, but only until you manually interact with the graphic. Adding Dynamic around the ViewCenter argument fixes the problem, but gives errors.

$\endgroup$
  • $\begingroup$ I'm not sure you've given enough details to figure it out. It works for me, given what I made up to control panvalue. The simplified option ViewCenter -> {{0.5, 0.5, 0.5}, Dynamic[{x, y} = CurrentPosition + {1, -1} panvalue]} works just as well, too. In other words, I think the problem is in the code you're not showing us. $\endgroup$ – Michael E2 Jul 22 '13 at 21:34
  • $\begingroup$ Need a full example to test but why not try ViewCenter->Dynamic[...] and report what happens $\endgroup$ – Mike Honeychurch Jul 22 '13 at 22:04
  • $\begingroup$ @MichaelE2 I edited the question to be far more detailed, sorry about the extensive code. $\endgroup$ – Matt Jul 23 '13 at 13:13
  • $\begingroup$ @MikeHoneychurch I tried your advice and get the same problem. Care to take a look at the updated question? $\endgroup$ – Matt Jul 23 '13 at 14:23
  • $\begingroup$ @Matt it wasn't so much advice as a guess because there was insufficient information to offer advice. For advice I'd suggest now to strip it right back and remove the event handler. $\endgroup$ – Mike Honeychurch Jul 23 '13 at 21:19
1
$\begingroup$

This is a partial answer. I'm not sure what the point is, since Shift-dragging does the same thing, only more reliably. (Holding down the Alt or Command key is not keyboard-free, so maybe there's more to the story.) One caveat: I'm working on a Mac and the OP perhaps is using a Windows machine. Perhaps there's a difference in how things work that I cannot appreciate.

The following works pretty well -- extremely well if SphericalRegion -> True in uncommented. Otherwise it's about 2-3% off when dragging the graphic in its default view point up to 50% off when dragging it from a view point more or less directly above the graph. Nonetheless it works in that dragging the mouse moves the graphics.

Note that ImageSizeCache -> Dynamic@pt reliably gets the size of the image even if the image is resized. It is of the form {width, {depth, height}} or {width, {height, depth}} -- I'm not sure which (it seems to be undocumented).

graphic = Plot3D[Sin[u v], {u, -2, 2}, {v, -2, 2}];

Manipulate[
 EventHandler[
  Dynamic[
    Show[graphic, ViewCenter -> Dynamic[vc](*, SphericalRegion\[Rule]True*)],
    ImageSizeCache -> Dynamic@pt],
  If[CurrentValue["AltKey"],
   {{"MouseDown", 1} :>
     (a = MousePosition["GraphicsImageScaled"];
      CurrentPosition = vc[[2]]),
    {"MouseDragged", 1} :>
     (b = MousePosition["GraphicsImageScaled"];
      drag = b - a;
      panvalue = drag (MapAt[Total, pt, 2]/pt[[1]]);
      vc[[2]] = panvalue + CurrentPosition)}]],
 SynchronousUpdating -> True,
 Initialization :> (vc = {{0.5, 0.5, 0.5}, {0.5, 0.5}})]
$\endgroup$
  • $\begingroup$ Thank you very much, this is very helpful. To clarify, I intend to make this keyboard-free by mapping a mouse command to a key press as a trigger. However, I first have to make sure that it works when the key is manually pressed. Thanks again. $\endgroup$ – Matt Jul 24 '13 at 12:41
0
$\begingroup$

In case anyone is wondering, using the above response and some of my own work, I was able to essentially make what I was going for. This example uses a basic Red Cylinder and allows you to Pan and Zoom when a Checkbox is True just by clicking and dragging, and rotate when the Checkbox is False. The following code is extensive, but may help if you're having problems similar to those that I was having, though I realize that these are pretty specific problems.

Manipulate[EventHandler[Dynamic[
Show[obj1,
ViewAngle -> Dynamic[va], ViewCenter -> Dynamic[vc], 
RotationAction -> "Clip", Axes -> False, Boxed -> False], 
ImageSizeCache -> Dynamic@pt],
If[enabler, If[setter,
{{"MouseDown", 1} :> (a = MousePosition["GraphicsImageScaled"];
   CurrentPosition = vc[[2]]), {"MouseDragged", 
   1} :> (b = MousePosition["GraphicsImageScaled"];
   drag = b - a;
   zoomvalue = 0.5*Norm[drag];
   If[drag[[2]] < 0, va = Min[Pi/2, va + zoomvalue*(Pi - va)], 
    va = Max[Pi/18, va - zoomvalue*(Pi - va)]])},
{{"MouseDown", 1} :> (a = MousePosition["GraphicsImageScaled"];
   CurrentPosition = vc[[2]]), {"MouseDragged", 
   1} :> (b = MousePosition["GraphicsImageScaled"];
   drag = b - a;
   panvalue = drag (MapAt[Total, pt, 2]/pt[[1]]);
   vc[[2]] = panvalue + CurrentPosition)}]]],
{{enabler, True, Style["Enable:", 18]}, {True, False}},
Style[""],
{{setter, True, ""}, {True -> Style["Zoom", 14], 
False -> Style["Pan", 16]}},
ControlPlacement -> Left, SynchronousUpdating -> True, 
Initialization :> (
obj1 = Graphics3D[{Red, Cylinder[]}];
va = 35 Degree; vc = {{0.5, 0.5, 0.5}, {0.5, 0.5}};)]

Final Working Cylinder

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.