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
Hi Szabolcs,
nice little tool. If you don't mind, I like to propose to add axes to
the zoomed picture by adding:
AxesOrigin -> {Min[range[[1]]], Min[range[[2]]]}
to your graphics.
happy New Year, Daniel
You can dynamically change Deployed:
DynamicModule[{mp, pos = {.5, .5}, sz = {1, 1}, mpos, f = True},
mp[] := MousePosition["GraphicsScaled"];
EventHandler[
Style[Graphics[
Inset[GraphData["HundredTwentyCellGraph"],
Center, Dynamic@Scaled@pos, Dynamic@Scaled@sz],
ImageSize -> 500], Deployed -> Dynamic[f]],
{"MouseDown" :>
(If[f && CurrentValue["MouseButtonTest"] &&
CurrentValue["MouseClickCount"] == 2,
pos = {.5, .5}; sz = {1, 1},
If[f && CurrentValue["ControlKey"],
f = False,
If[! f && CurrentValue["AltKey"],
f = True]]];
mpos = mp[]),
"MouseDragged" :>
(If[f,
If[CurrentValue["MouseButtonTest"],
pos -= 2/sz[[1]] (mp[] - mpos),
sz += 4 sz[[1]] (mp[][[2]] - mpos[[2]])];
mpos = mp[]])},
PassEventsDown -> True]]
Here dragging the mouse with the left button pressed pans the graphic,
dragging the mouse up/down with the right button pressed zooms in/out,
left double click resets to defaults, but if you do Control-click, you
switch to the standard interactive editing mode. Alt-click switches
back to zoom mode.
Maxim Rytin
m...@inbox.ru