Interactive 2d zoom and some Dynamic questions
- To: mathgroup at smc.vnet.net
- Subject: [mg84524] Interactive 2d zoom and some Dynamic questions
- From: Szabolcs Horvát <szhorvat at gmail.com>
- Date: Wed, 2 Jan 2008 01:17:54 -0500 (EST)
Happy new year, MathGroup! And now, the question: First of all, those people who haven't seen it yet should definitely check out Daniel Huber's very nice Zoom2D palette: http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/58c77e4614440e57/5876f0611112765e But I would like to have something simpler, a "quick and dirty" zoom that has the simplest possible UI, and keeps the graphic in the notebook. So I came up with this: zoomGraphics[graph_Graphics] := With[ {gr = First[graph], opt = DeleteCases[Options[graph], PlotRange -> _], plr = PlotRange /. Options[graph, PlotRange], rectangle = {Dashing[Small], Line[{#1, {First[#2], Last[#1]}, #2, {First[#1], Last[#2]}, #1}]} & }, DynamicModule[{dragging = False, first, second, range = plr}, Panel@EventHandler[ Dynamic@Graphics[ If[dragging, {gr, rectangle[first, second]}, gr], PlotRange -> range, Sequence @@ opt ], {{"MouseDown", 1} :> (first = MousePosition["Graphics"]), {"MouseDragged", 1} :> (dragging = True; second = MousePosition["Graphics"]), {"MouseUp", 1} :> If[dragging, dragging = False; range = Transpose@{first, second}, range = plr] } ] ]] Usage example: Plot[1/x, {x, 0, 1}] // zoomGraphics Drag to zoom, click to reset. Remove Panel if you don't like it (or replace it with Framed). It's there to show the active ("draggable") area. I do not understand Dynamic things well, so comments, suggestions (e.g. for improving performance), problem cases where zoomGraphics fails are most welcome. One of the biggest problems with this is that EvantHandler prevents resizing the graphic from working. This is unacceptable because if we want to zoom, most likely we also want to keep the resize functionality. It also prevents dynamic things, like Locators from working properly. I could set PassEventsDown -> True in EventHandler, but zooming would still interfere with resizing or moving a Locator (and other strange behaviour appears too.) One solution that I can imagine is to zoom only while CTRL (or some other modifier key) is pressed. But I do not know how to implement this properly. This is what I have so far: zoomGraphics[graph_Graphics] := With[ {gr = First[graph], opt = DeleteCases[Options[graph], PlotRange -> _], plr = PlotRange /. Options[graph, PlotRange], rectangle = {Dashing[Small], Line[{#1, {First[#2], Last[#1]}, #2, {First[#1], Last[#2]}, #1}]} &, keyCheck = Function[{arg}, If[CurrentValue["ControlKey"], arg], HoldAll]}, DynamicModule[{dragging = False, first, second, range = plr}, Panel@EventHandler[ Dynamic[ Graphics[ If[dragging, {gr, rectangle[first, second]}, gr], PlotRange -> range, Sequence @@ opt ]], {{"MouseDown", 1} :> keyCheck[first = MousePosition["Graphics"]], {"MouseDragged", 1} :> keyCheck[dragging = True; second = MousePosition["Graphics"]], {"MouseUp", 1} :> keyCheck@ If[dragging, dragging = False; range = Transpose@{first, second}, range = plr]}] ]] OK, now zooming only works while CTRL is pressed. Now it is somewhat safer to set PassEventsDown -> True, and resizing works when CTRL is not pressed. But resizing and selecting graphics interferes with zooming when CTRL is pressed. The zoom level is also often reset unexpectedly if CTRL is not released (and pressed again), and the graphics are not deselected, between consecutive zoom attempts. I don't completely understand what is happening here. Is it possible to somehow set PassEventsDown -> True only when CTRL is not pressed? As a desperate attempt, I tried PassEventsDown -> Dynamic@Not@CurrentValue["ControlKey"], but, unsurprisingly, it does not work. As an alternative solution, I also tried using GraphicsGrid[{{zoomGraphics[someGraphic]}}] with the original version of zoomGraphics to enable resizing (not moving Locators), but now the events don't seem to reach the EventHandler. Another question: Could someone please explain, preferably with a working example, what PassEventsUp is for? Szabolcs