function out = zoom(varargin)
%ZOOM Zoom in and out on a 2-D plot.
% ZOOM with no arguments toggles the zoom state.
% ZOOM(FACTOR) zooms the current axis by FACTOR.
% Note that this does not affect the zoom state.
% ZOOM ON turns zoom on for the current figure.
% ZOOM XON or ZOOM YON turns zoom on for the x or y axis only.
% ZOOM OFF turns zoom off in the current figure.
%
% ZOOM RESET resets the zoom out point to the current zoom.
% ZOOM OUT returns the plot to its current zoom out point.
% If ZOOM RESET has not been called this is the original
% non-zoomed plot. Otherwise it is the zoom out point
% set by ZOOM RESET.
%
% When zoom is on, click the left mouse button to zoom in on the
% point under the mouse. Click the right mouse button to zoom out.
% Each time you click, the axes limits will be changed by a factor
% of 2 (in or out). You can also click and drag to zoom into an area.
% It is not possible to zoom out beyond the plots' current zoom out
% point. If ZOOM RESET has not been called the zoom out point is the
% original non-zoomed plot. If ZOOM RESET has been called the zoom out
% point is the zoom point that existed when it was called.
% Double clicking zooms out to the current zoom out point -
% the point at which zoom was first turned on for this figure
% (or to the point to which the zoom out point was set by ZOOM RESET).
% Note that turning zoom on, then off does not reset the zoom out point.
% This may be done explicitly with ZOOM RESET.
%
% ZOOM(FIG,OPTION) applies the zoom command to the figure specified
% by FIG. OPTION can be any of the above arguments.
%
% Use LINKAXES to link zooming across multiple axes.
%
% See also PAN, LINKAXES.
% Copyright 1993-2004 The MathWorks, Inc.
% Internal use undocumented syntax (this may be removed in a future
% release)
% Additional syntax not already ded in zoom m-help
%
% ZOOM(FIG,'UIContextMenu',...)
% Specify UICONTEXTMENU for use in zoom mode
% ZOOM(FIG,'Constraint',...)
% Specify constrain option:
% 'none' - No constraint (default)
% 'horizontal' - Horizontal zoom only for 2-D plots
% 'vertical' - Vertical zoom only for 2-D plots
% ZOOM(FIG,'Direction',...)
% Specify zoom direction 'in' or 'out'
% OUT = ZOOM(FIG,'IsOn')
% Returns true if zoom is on, otherwise returns false.
% OUT = ZOOM(FIG,'Constraint')
% Returns 'none','horizontal', or 'vertical'
% OUT = ZOOM(FIG,'Direction')
% Returns 'in' or 'out'
% Undocumented syntax that will never get documented
% (but we have to keep it around for legacy reasons)
% OUT = ZOOM(FIG,'getmode') 'in'|'out'|'off'
%
% Undocumented zoom object registration methods
% OUT = ZOOM(FIG,'getzoom')
% Get zoom object
% ZOOM(FIG,'setzoom',...)
% Set zoom object
% Note: zoom uses the figure buttondown and buttonmotion functions
%
% ZOOM XON zooms x-axis only
% ZOOM YON zooms y-axis only
% ZOOM v6 off Switches to new zoom implementation
% ZOOM v6 on Switches to old zoom implementation
% ZOOM FILL scales a plot such that it is as big as possible
% within the axis position rectangle for any azimuth and elevation.
% Undocumented switch to v6 zoom implementation. This will be removed.
if nargin==2 && ...
isstr(varargin{1}) && ...
strcmp(varargin{1},'v6') && ...
isstr(varargin{2})
if strcmp(varargin{2},'on')
localSetV6Zoom(true);
else
localSetV6Zoom(false);
end
return;
end
% Bypass to v6 zoom
if localIsV6Zoom
if nargout==0
v6_zoom(varargin{:});
else
out = v6_zoom(varargin{:});
end
return;
end
% Parse input arguments
[target,action,action_data] = localParseArgs(varargin{:});
% If setting zoom object, ZOOM(H,HZOOM), then return early
if strcmp(action,'setzoom')
localRegisterZoomObject(action_data);
return;
end
% Return early if target is not an axes or figure
if isempty(target) || ...
(~isa(target,'hg.axes') && ~isa(target,'hg.figure'))
return;
end
hFigure = ancestor(target,'hg.figure');
% Return early if setting zoom off and there's no app data
% this avoids making any objects or setting app data when
% it doesn't need to. For example, hgload calls zoom(fig,'off')
appdata = localGetData(hFigure);
if strcmp(action,'off') && isempty(appdata.uistate)
return;
end
% Get zoom object
hZoom = localGetRegisteredZoomObject(hFigure);
% Update zoom target in case it changed
set(hZoom,'target',target);
% Get current axes
hCurrentAxes = get(hFigure,'CurrentAxes');
% Parse various zoom options
change_ui = [];
%========================================================
% Part of modification for ADDAXIS commands
ystart = get(gca,'ylim');
%========================================================
switch lower(action)
case 'on'
set(hZoom,'Constraint','none');
change_ui = 'on';
case 'xon'
set(hZoom,'Constraint','horizontal');
change_ui = 'on';
case 'yon'
set(hZoom,'Constraint','vertical');
change_ui = 'on';
case 'getzoom'
out = hZoom;
case 'getmode'
if localIsZoomOn(hZoom)
out = get(hZoom,'Direction');
else
out = 'off';
end
case 'constraint'
out = get(hZoom,'Constraint');
case 'direction'
out = get(hZoom,'Direction');
case 'ison'
out = localIsZoomOn(hZoom);
case 'ison' %TBD: Remove
out = localIsZoomOn(hZoom);
case 'getstyle' %TBD: Remove
out = get(hZoom,'Constraint');
case 'getdirection' %TBD: Remove
out = get(hZoom,'Direction');
case 'toggle'
if localIsZoomOn(hZoom)
change_ui = 'off';
else
change_ui = 'on';
end
% Undocumented legacy API, used by 'ident', see g194435
% It would be nice to get rid to dependencies on this API, but
% many old toolboxes seem to be calling this API.
case 'down'
buttondownfcn(hZoom,'dorightclick',true);
hLine = get(hZoom,'LineHandles');
if ishandle(hLine)
% Mimic rbbox, don't return until line handles are
% removed
waitfor(hLine(1));
end
case 'off'
change_ui = 'off';
case 'inmode'
set(hZoom,'Direction','in');
change_ui = 'on';
case 'outmode'
set(hZoom,'Direction','out');
change_ui = 'on';
case 'scale'
if ~isempty(hCurrentAxes)
% Register current axes view for reset view support
resetplotview(hCurrentAxes,'InitializeCurrentView');
applyzoomfactor(hZoom,hCurrentAxes,action_data);
end
case 'fill'
if ~isempty(hCurrentAxes)
resetplot(hZoom,hCurrentAxes);
end
case 'reset'
resetplotview(hCurrentAxes,'SaveCurrentView');
case 'out'
if ~isempty(hCurrentAxes)
resetplot(hZoom,hCurrentAxes);
end
case 'setzoomproperties'
% undocumented
set(hZoom,action_data{:});
otherwise
return
end
%====================================================================
% This is a modification to accomodate the ADDAXIS commands.
% Check to see if add axis has been used and update the axes using
% the same scale factors. (also put ystart = get(gca,'ylim');
% before the zoom is started above)
yend = get(gca,'ylim');
% ystart and yend are the starting and ending yaxis limits
% now go through all of the added axes and scale their limits
%axh = get(gca,'userdata');
axh = getaddaxisdata(gca,'axisdata');
if ~isempty(axh)
for I = 1:length(axh)
axhan = axh{I}(1);
axyl = get(axhan,'ylim');
axylnew(1) = axyl(1)+(yend(1)-ystart(1))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
axylnew(2) = axyl(2)-(ystart(2)-yend(2))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
set(axhan,'ylim',axylnew);
end
end
% END of modification
%================================================================
% Update the user interface
if ~isempty(change_ui)
localSetZoomState(hZoom,change_ui);
end
%-----------------------------------------------%
function localSetZoomState(hZoom,state)
hFigure = get(hZoom,'FigureHandle');
appdata = localGetData(hFigure);
uistate = appdata.uistate;
if strcmp(state,'on')
% Turn off all other interactive modes
if isempty(uistate)
% Specify uninstaller callback: zoom(fig,'off')
uistate = uiclearmode(double(hFigure),...
'docontext',...
'zoom',double(hFigure),'off');
% restore button down functions for uicontrol children of the figure
uirestore(uistate,'uicontrols');
appdata.uistate = uistate;
end
% Enable zoom mode
appdata.ison = true;
set(hZoom,'IsOn',true);
localSetData(hFigure,appdata);
set(hFigure,'WindowButtonMotionFcn',{@localMotionFcn,hZoom});
set(hFigure,'WindowButtonUpFcn',[])
set(hFigure,'WindowButtonDownFcn',{@localWindowButtonDownFcn,hZoom});
set(hFigure,'KeyPressFcn',{@localKeyPressFcn,hZoom});
set(hFigure,'PointerShapeHotSpot',[5 5]);
localMotionFcn(hFigure,[],hZoom);
% Flush queue to update figure pointer display asap.
drawnow expose;
% Turn on Zoom UI (i.e. toolbar buttons, menus)
% This must be called AFTER uiclear to avoid uiclear state munging
zoom_direction = get(hZoom,'Direction');
switch zoom_direction
case 'in'
localUISetZoomIn(hFigure);
case 'out'
localUISetZoomOut(hFigure);
end
local_scribefiglisten(hFigure,'on');
% Define appdata to avoid breaking code in
% scribefiglisten, hgsave, and figtoolset
setappdata(hFigure,'ZoomOnState','on');
% zoom off
elseif strcmp(state,'off')
if ~isempty(uistate)
% restore figure and non-uicontrol children
% don't restore uicontrols because they were restored
% already when zoom was turned on
uirestore(uistate,'nouicontrols');
% Turn off Zoom UI (i.e. toolbar buttons, menus)
localUISetZoomOff(hFigure);
local_scribefiglisten(hFigure,'off');
% Remove uicontextmenu
hui = get(hZoom,'UIContextMenu');
if ishandle(hui)
delete(hui);
end
end
% Reset appdata
localRmData(hFigure);
% Remove appdata to avoid breaking code in
% scribefiglisten, hgsave, and figtoolset
if isappdata(hFigure,'ZoomOnState');
rmappdata(hFigure,'ZoomOnState');
end
end
%-----------------------------------------------%
function [bool] = localIsZoomOn(hZoom)
% TBD, when zoom enabled property is wired correctly
% do the following:
%bool = strcmp(get(hZoom,'Enabled'),'on'));
% For now, use app data
hFigure = get(hZoom,'FigureHandle');
appdata = localGetData(hFigure);
bool = appdata.ison;
%-----------------------------------------------%
function localWindowButtonDownFcn(hFigure,evd,hZoom)
if ~ishandle(hZoom)
return;
end
fig_sel_type = get(hFigure,'SelectionType');
fig_mod = get(hFigure,'CurrentModifier');
%========================================================
% Part of modification for ADDAXIS commands
ystart = get(gca,'ylim');
%========================================================
switch (lower(fig_sel_type))
case 'alt' % right click
% display context menu
hui = localGetContextMenu(hZoom);
curr_point = get(hFigure,'CurrentPoint');
curr_pixel = hgconvertunits(hFigure,[curr_point 0 0],...
get(hFigure,'Units'),'pixels',hFigure);
set(hui,'Position',curr_pixel(1:2),'Visible','on')
otherwise % left click, center click, double click
% Zoom out if user clicked on 'alt'
if strcmp(fig_mod,'alt')
switch get(hZoom,'Direction')
case 'in'
applyzoomfactor(hZoom,findaxes(hZoom),.9);
case 'out'
applyzoomfactor(hZoom,findaxes(hZoom),2);
end
% Delegate to registered zoom object
else
buttondownfcn(hZoom);
end
end
%====================================================================
% This is a modification to accomodate the ADDAXIS commands.
% Check to see if add axis has been used and update the axes using
% the same scale factors. (also put ystart = get(gca,'ylim');
% before the zoom is started above)
yend = get(gca,'ylim');
% ystart and yend are the starting and ending yaxis limits
% now go through all of the added axes and scale their limits
%axh = get(gca,'userdata');
axh = getaddaxisdata(gca,'axisdata');
if ~isempty(axh)
for I = 1:length(axh)
axhan = axh{I}(1);
axyl = get(axhan,'ylim');
axylnew(1) = axyl(1)+(yend(1)-ystart(1))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
axylnew(2) = axyl(2)-(ystart(2)-yend(2))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
set(axhan,'ylim',axylnew);
end
end
% END of modification
%================================================================
%-----------------------------------------------%
function localMotionFcn(hFigure,evd,hZoom)
if ishandle(hZoom)
hTarget = handle(hittest(hFigure));
if ~isempty(ancestor(hTarget,'axes'))
if strcmp(get(hZoom,'Direction'),'in')
setptr(hFigure,'glassplus');
else
setptr(hFigure,'glassminus');
end
else
setptr(hFigure,'arrow');
end
end
%-----------------------------------------------%
function localKeyPressFcn(hFigure,evd,hZoom)
% Delegate to registered zoom object
if ishandle(hZoom)
keypressfcn(hZoom,evd);
end
%-----------------------------------------------%
function [hZoom] = localGetRegisteredZoomObject(hFigure,dopeek)
% TBD Get Zoom object from Figure Tool Manager
hZoom = getappdata(hFigure,'ZoomObject');
if isempty(hZoom) || ~isa(hZoom,'graphics.zoom')
hZoom = graphics.zoom(hFigure);
setappdata(hFigure,'ZoomObject',hZoom);
end
%-----------------------------------------------%
function localRegisterZoomObject(hFigure,hZoom)
hFigure = hZoom.FigureHandle;
setappdata(hFigure,'ZoomObject',hZoom);
%-----------------------------------------------%
function [appdata] = localGetData(fig)
appdata = getappdata(fig,'ZoomFigureState');
if isempty(appdata) || ~isfield(appdata,'uistate')
appdata.uistate = [];
appdata.ison = false;
end
%-----------------------------------------------%
function localSetData(fig,appdata)
setappdata(fig,'ZoomFigureState',appdata);
%-----------------------------------------------%
function localRmData(fig)
appdata = localGetData(fig);
appdata.uistate = [];
appdata.ison = false;
localSetData(fig,appdata);
%-----------------------------------------------%
function [hui] = localUICreateDefaultContextMenu(hZoom)
% Create default context menu
hFig = get(hZoom,'FigureHandle');
props_context.Parent = hFig;
props_context.Tag = 'ZoomContextMenu';
props_context.Callback = {@localUIContextMenuCallback,hZoom};
props_context.ButtonDown = {@localUIContextMenuCallback,hZoom};
hui = uicontextmenu(props_context);
% Generic attributes for all zoom context menus
props.Callback = {@localUIContextMenuCallback,hZoom};
props.Parent = hui;
props.Label = 'Zoom Out Alt-Click';
props.Tag = 'ZoomInOut';
props.Separator = 'off';
uzoomout = uimenu(props);
% Full View context menu
props.Label = 'Reset to Original View';
props.Tag = 'ResetView';
props.Separator = 'off';
ufullview = uimenu(props);
% Zoom Constraint context menu
props.Callback = '';
props.Label = 'Zoom Options';
props.Tag = 'Constraint';
props.Separator = 'on';
uConstraint = uimenu(props);
props.Parent = uConstraint;
props.Callback = {@localUIContextMenuCallback,hZoom};
props.Label = 'Unconstrained Zoom';
props.Tag = 'ZoomUnconstrained';
props.Separator = 'off';
uimenu(props);
props.Label = 'Horizontal Zoom (2-D Plots Only)';
props.Tag = 'ZoomHorizontal';
uimenu(props);
props.Label = 'Vertical Zoom (2-D Plots Only)';
props.Tag = 'ZoomVertical';
uimenu(props);
localUIContextMenuUpdate(hZoom,get(hZoom,'Constraint'));
%-----------------------------------------------%
function [hui] = localGetContextMenu(hZoom)
% Create context menu
hui = get(hZoom,'UIContextMenu');
if isempty(hui) || ~ishandle(hui)
local_scribefiglisten(get(hZoom,'Figure'),'off');
hui = localUICreateDefaultContextMenu(hZoom);
local_scribefiglisten(get(hZoom,'Figure'),'on');
set(hZoom,'UIContextMenu',hui);
localUIUpdateContextMenuLabel(hZoom);
drawnow expose;
end
%-------------------------------------------------%
function localUIContextMenuCallback(obj,evd,hZoom)
tag = get(obj,'tag');
%========================================================
% Part of modification for ADDAXIS commands
ystart = get(gca,'ylim');
%========================================================
switch(tag)
case 'ZoomInOut'
switch get(hZoom,'Direction')
case 'in'
applyzoomfactor(hZoom,findaxes(hZoom),.9);
case 'out'
applyzoomfactor(hZoom,findaxes(hZoom),2);
end
case 'ResetView'
hAxes = findaxes(hZoom);
resetplotview(hAxes,'ApplyStoredView');
case 'ZoomContextMenu'
localUIContextMenuUpdate(hZoom,get(hZoom,'Constraint'));
case 'ZoomUnconstrained'
localUIContextMenuUpdate(hZoom,'none');
case 'ZoomHorizontal'
localUIContextMenuUpdate(hZoom,'horizontal');
case 'ZoomVertical'
localUIContextMenuUpdate(hZoom,'vertical');
end
%====================================================================
% This is a modification to accomodate the ADDAXIS commands.
% Check to see if add axis has been used and update the axes using
% the same scale factors. (also put ystart = get(gca,'ylim');
% before the zoom is started above)
yend = get(gca,'ylim');
% ystart and yend are the starting and ending yaxis limits
% now go through all of the added axes and scale their limits
%axh = get(gca,'userdata');
axh = getaddaxisdata(gca,'axisdata');
if ~isempty(axh)
for I = 1:length(axh)
axhan = axh{I}(1);
axyl = get(axhan,'ylim');
axylnew(1) = axyl(1)+(yend(1)-ystart(1))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
axylnew(2) = axyl(2)-(ystart(2)-yend(2))/(ystart(2)-ystart(1)).*...
(axyl(2)-axyl(1));
set(axhan,'ylim',axylnew);
end
end
% END of modification
%================================================================
%-------------------------------------------------%
function localUIContextMenuUpdate(hZoom,zoom_Constraint)
hFigure = get(hZoom,'FigureHandle');
ux = findall(hFigure,'Tag','ZoomHorizontal','Type','UIMenu');
uy = findall(hFigure,'Tag','ZoomVertical','Type','UIMenu');
uxy = findall(hFigure,'Tag','ZoomUnconstrained','Type','UIMenu');
switch(zoom_Constraint)
case 'none'
set(hZoom,'Constraint','none');
set(ux,'checked','off');
set(uy,'checked','off');
set(uxy,'checked','on');
case 'horizontal'
set(hZoom,'Constraint','horizontal');
set(ux,'checked','on');
set(uy,'checked','off');
set(uxy,'checked','off');
case 'vertical'
set(hZoom,'Constraint','vertical');
set(ux,'checked','off');
set(uy,'checked','on');
set(uxy,'checked','off');
end
%-----------------------------------------------%
function localUIMenuUpdate(fig)
set(findall(fig,'Tag','figMenuZoomIn'),'Checked','on');
%-----------------------------------------------%
function localUISetZoomIn(fig)
set(uigettoolbar(fig,'Exploration.ZoomIn'),'State','on');
set(uigettoolbar(fig,'Exploration.ZoomOut'),'State','off');
%-----------------------------------------------%
function localUISetZoomOut(fig)
h = findall(fig,'type','uitoolbar');
set(uigettool(h,'Exploration.ZoomIn'),'State','off');
set(uigettool(h,'Exploration.ZoomOut'),'State','on');
%-----------------------------------------------%
function localUISetZoomOff(fig)
h = findall(fig,'type','uitoolbar');
set(uigettool(h,'Exploration.ZoomIn'),'State','off');
set(uigettool(h,'Exploration.ZoomOut'),'State','off');
% Remove the following lines after UITOOLBARFACTORY API is on by default
set(findall(fig,'Tag','figToolZoomIn'),'State','off');
set(findall(fig,'Tag','figToolZoomOut'),'State','off');
%-----------------------------------------------%
function localUIUpdateContextMenuLabel(hZoom);
h = findobj(get(hZoom,'UIContextMenu'),'Tag','ZoomInOut');
zoom_direction = get(hZoom,'Direction');
if strcmp(zoom_direction,'in')
set(h,'Label','Zoom Out Alt-Click');
else
set(h,'Label','Zoom In Alt-Click');
end
%-----------------------------------------------%
function localSetNewZoom(bool)
setappdata(0,'NewZoomImplementation',bool);
%-----------------------------------------------%
function [target,action,action_data] = localParseArgs(varargin)
target = [];
action = [];
action_data = [];
errstr = {'Zoom:InvalidSyntax','Invalid Syntax'};
target = get(0,'CurrentFigure');
% zoom
if nargin==0
action = 'toggle';
elseif nargin==1
arg1 = varargin{1};
% zoom(SCALE)
if all(size(arg1)==[1,1]) & isnumeric(arg1)
action = 'scale';
action_data = arg1;
% zoom(OPTION)
elseif isstr(arg1)
action = arg1;
% zoom(FIG)
% zoom(HZOOM)
elseif ishandle(arg1)
if isa(handle(arg1),'graphics.zoom')
target = get(arg1,'target');
action = 'setzoom';
elseif isa(handle(arg1),'hg.figure')
target = arg1;
action = 'toggle';
end
else
error(errstr{:});
end
elseif nargin==2
% zoom('newzoom',0)
if isstr(varargin{1})
action = varargin{1};
action_data = varargin{2};
% zoom(FIG,SCALE)
% zoom(FIG,OPTION)
elseif ishandle(varargin{1})
target = varargin{1};
arg2 = varargin{2};
if isstr(arg2)
action = arg2;
elseif isnumeric(arg2)
action = 'scale';
action_data = arg2;
end
end
% zoom(FIG,<paramater/value pairs>);
elseif nargin>=3
target = varargin{1};
arg2 = varargin{2};
if ishandle(target) & isstr(arg2)
action = 'setzoomproperties';
action_data = {varargin{2:end}};
end
end
target = handle(target);
%-----------------------------------------------%
function localSetV6Zoom(bool)
setappdata(0,'V6Zoom',bool);
%-----------------------------------------------%
function [bool] = localIsV6Zoom
bool = getappdata(0,'V6Zoom');
%-----------------------------------------------%
function local_scribefiglisten(hFigure,val)
scribefiglisten(hFigure,val);