forked from kndiaye/matlab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
drag.m
289 lines (269 loc) · 9.25 KB
/
drag.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
function drag(varargin)
%DRAG Move around on a 2-D or 3-D plot.
% DRAG with no arguments toggles the plot dragging state.
% DRAG ON turns plot dragging on for the current figure.
% DRAG XON, YON, or ZON turns plot dragging on for the x, y, or z axis only.
% DRAG OFF turns plot dragging off in the current figure.
% DRAG RESET resets the restore point to the current axis settings.
%
% When plot dragging is on, you can click and drag the axes around while
% maintaining the current level of zoom. If DRAG RESET has not been
% called the restore point is the original non-explored plot. If DRAG
% RESET has been called the restore point is the retore point that existed
% when it was called. Double clicking retores the axes to the current
% restore point - the point at which plot dragging was first turned on for
% this figure (or to the state to which the restore point was set by DRAG
% RESET).
%
% In a figure with multiple subplots, pressing and holding the left mouse
% button drags around the currently active subplot, while pressing and
% holding the right mouse button drags around all subplots simultaneously.
% Double clicking with the left mouse button restores the currently active
% plot to its restore point, while double clicking with the right mouse
% button restores all subplots to their defined restore point.
%
% DRAG(FIG,OPTION) applies the drag command to the figure specified by
% FIG. OPTION can be any of the above arguments.
%
% Example:
% x = 0:0.1:5; y = exp(x);
% figure; subplot(211); plot(x,y,'r.'); subplot(212); plot(y,x,'g.');
% drag xon;
%
% Ryan M. Eustice 08-15-2003
% Woods Hole Oceanographic Institution, MS 7
% Woods Hole, MA 02543
% 508.289.3269 ryan@whoi.edu
% History
% DATE WHO WHAT
%---------- ------------------ ------------------------------
%2003-07-23 Ryan Eustice Created & written.
%2003-08-15 Boyko Stoimenov Modified the private function
% dragreset to correctly count the
% number of axes. Also, switched
% short-circuit && to & for matlab
% backwards compatability.
%2004-01-29 Ryan Eustice Fixed bug in private function
% dragreset to properly count
% number of axes and not count
% legend or colorbar objects.
% Note: drag uses the figure buttondown and buttonmotion functions
%
% PARSE ARGS - set fig and drag command
%
fignum = get(0,'CurrentFigure');
if isempty(fignum)
return; % no figure
end
switch nargin
case 0 % no arg in
switch get(fignum,'Tag')
case 'dragon' % toggle state
dragoff(fignum);
otherwise % turn on
figstate.motion = 'all';
set(fignum,'UserData',figstate);
dragon(fignum);
end % switch get(fignum,'Tag')
case 1 % one arg in
switch lower(varargin{1})
case 'on'
figstate.motion = 'all';
set(fignum,'UserData',figstate);
dragon(fignum);
case 'off'
dragoff(fignum);
case 'reset'
dragreset(fignum);
case 'xon'
figstate.motion = 'xon';
set(fignum,'UserData',figstate);
dragon(fignum);
case 'yon'
figstate.motion = 'yon';
set(fignum,'UserData',figstate);
dragon(fignum);
case 'zon'
figstate.motion = 'zon';
set(fignum,'UserData',figstate);
dragon(fignum);
otherwise
error(sprintf('Unrecognized argument ''%s''',varargin{1}));
end % switch varargin{1}
case 2 % two args in
fignum = varargin{1};
switch lower(varargin{2})
case 'on'
figstate.motion = 'all';
set(fignum,'UserData',figstate);
dragon(fignum);
case 'off'
dragoff(fignum);
case 'reset'
dragreset(fignum);
case 'xon'
figstate.motion = 'xon';
set(fignum,'UserData',figstate);
dragon(fignum);
case 'yon'
figstate.motion = 'yon';
set(fignum,'UserData',figstate);
dragon(fignum);
case 'zon'
figstate.motion = 'zon';
set(fignum,'UserData',figstate);
dragon(fignum);
otherwise
error(sprintf('Unrecognized argument ''%s''',varargin{1}));
end % switch varargin{2}
otherwise % too many args
error(nargchk(0,2,nargin));
end % switch nargin
%====================================================================
% drag: private
%====================================================================
function dragon(fignum)
figstate = get(fignum,'UserData');
dragreset(fignum);
set(fignum,'Interruptible','on');
set(fignum,'DoubleBuffer','on');
set(fignum,'Tag','dragon');
set(fignum,'WindowButtonDownFcn',@startexploring);
set(fignum,'WindowButtonUpFcn',@stopexploring);
function dragoff(fignum)
set(fignum,'DoubleBuffer','off');
set(fignum,'Tag','');
set(fignum,'WindowButtonDownFcn','');
set(fignum,'WindowButtonUpFcn','');
function dragreset(fignum)
figstate = get(fignum,'UserData');
kids = get(fignum,'Children');
cc = 1;
for ii=1:length(kids)
% check for regular axes handles by keying off the Tag field which should be
% empty. note that objects like legend and colorbar fill in the Tag field.
if strcmp(get(kids(ii),'Type'),'axes') & strcmp(get(kids(ii),'Tag'),'')
figstate.axishandle(cc) = kids(ii);
figstate.origlimits(cc,:) = axis(kids(ii));
cc = cc+1;
end
end
figstate.numaxes = length(figstate.axishandle);
set(fignum,'UserData',figstate);
%====================================================================
% callbacks
%====================================================================
function startexploring(obj,eventdata)
fignum = gcbf;
figstate = get(fignum,'UserData');
switch get(fignum,'SelectionType')
case 'normal' %mouse left single-click
figstate.whichaxes = 'current'; % only drag current axis
axishandle = gca;
initaxis(axishandle);
case 'open' %mouse left or right double-click
axishandle = gca;
for ii=1:figstate.numaxes
if strcmp(figstate.whichaxes,'current') & figstate.axishandle(ii) == axishandle
% restore currently active axis limits to orig state
axis(axishandle,figstate.origlimits(ii,:));
break;
elseif strcmp(figstate.whichaxes,'all')
% restore other subplot axis limits to orig state
axis(figstate.axishandle(ii),figstate.origlimits(ii,:));
end
end
case 'alt' %mouse right single-click
figstate.whichaxes = 'all'; % drag all axes simultaneously
for ii=1:figstate.numaxes
axishandle = figstate.axishandle(ii);
initaxis(axishandle);
end
otherwise
error('Mouse SelectionType unknown');
end
set(fignum,'WindowButtonMotionFcn',@setnewview);
set(fignum,'Pointer','Fleur');
set(fignum,'UserData',figstate); % store figure state
function setnewview(obj,eventdata)
persistent cc;
fignum = gcbf;
figstate = get(fignum,'UserData');
switch figstate.whichaxes
case 'current'
axishandle = gca;
updateaxes(axishandle,figstate.motion);
case 'all'
for ii=1:figstate.numaxes
axishandle = figstate.axishandle(ii);
updateaxes(axishandle,figstate.motion);
end
otherwise
%do nothing
end % switch figstate.whichaxes
cc = cc+1;
if mod(cc,2)
drawnow; % force screen update every other motion cycle (lowers cpu usage)
end
function stopexploring(obj,eventdata)
fignum = gcbf;
set(fignum,'WindowButtonMotionFcn','');
set(fignum,'Pointer','arrow');
%====================================================================
% callbacks: private
%====================================================================
function pos = getcurrentposition(axishandle)
pos = get(axishandle,'CurrentPoint');
pos = mean(pos);
pos = round(pos*1000)/1000;
function initaxis(axishandle)
state.currentaxislimits = axis(axishandle);
state.startpoint = getcurrentposition(axishandle);
set(axishandle,'UserData',state); % store axis state
function updateaxes(axishandle,motion)
state = get(axishandle,'UserData');
state.endpoint = getcurrentposition(axishandle);
motionvector = state.startpoint - state.endpoint;
if length(state.currentaxislimits) == 4 % 2D plot
switch motion
case 'all'
state.currentaxislimits = ...
[state.currentaxislimits(1:2) + motionvector(1), ...
state.currentaxislimits(3:4) + motionvector(2)];
case 'xon'
state.currentaxislimits = ...
[state.currentaxislimits(1:2) + motionvector(1), ...
state.currentaxislimits(3:4)];
case 'yon'
state.currentaxislimits = ...
[state.currentaxislimits(1:2), ...
state.currentaxislimits(3:4) + motionvector(2)];
otherwise %do nothing
end % switch motion
elseif length(state.currentaxislimits) == 6 % 3D plot
switch motion
case 'all'
state.currentaxislimits = ...
[state.currentaxislimits(1:2) + motionvector(1), ...
state.currentaxislimits(3:4) + motionvector(2), ...
state.currentaxislimits(5:6) + motionvector(3)];
case 'xon'
state.currentaxislimits = ...
[state.currentaxislimits(1:2) + motionvector(1), ...
state.currentaxislimits(3:4), ...
state.currentaxislimits(5:6)];
case 'yon'
state.currentaxislimits = ...
[state.currentaxislimits(1:2), ...
state.currentaxislimits(3:4) + motionvector(2), ...
state.currentaxislimits(5:6)];
case 'zon'
state.currentaxislimits = ...
[state.currentaxislimits(1:2), ...
state.currentaxislimits(3:4), ...
state.currentaxislimits(5:6) + motionvector(3)];
otherwise %do nothing
end % switch motion
end
axis(axishandle,state.currentaxislimits);
set(axishandle,'UserData',state);