Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement the deprecated full crosshair pointer functionality in MATLAB?

I'm trying to replace the pointer on a chart plot with a full crosshair (that is, a set of 2 perpendicular lines that stretch to the edges of the plot vertically and horizontally and follow the mouse cursor). Years ago, I was able to accomplish this with this line of code:

set(gcf,'Pointer','fullcross')

However, when I try to run this line now, I get the following message:

Warning: Full crosshair pointer is no longer supported. A crosshair pointer will be used instead.

I would really like to find an alternative way to implement this functionality, but have been unable to thus far. I have come across the following function: MYGINPUT, but it does not seem to accomplish what I'm looking for. Does anyone have any suggestions?

like image 318
Alarik Avatar asked Mar 08 '23 14:03

Alarik


1 Answers

You can actually do this by adding a 'WindowButtonMotionFcn' to your figure (assuming nothing else is using it) that will display crosshair lines in your axes when your mouse is over it. Here's a function that creates such functionality for all axes in a figure:

function full_crosshair(hFigure)

  % Find axes children:
  hAxes = findall(hFigure, 'Type', 'axes');

  % Get all axes limits:
  xLimits = get(hAxes, 'XLim');
  xLimits = vertcat(xLimits{:});
  yLimits = get(hAxes, 'YLim');
  yLimits = vertcat(yLimits{:});

  % Create lines (not displayed yet due to NaNs) and listeners:
  for iAxes = 1:numel(hAxes)
    hHoriz(iAxes) = line(xLimits(iAxes, :), nan(1, 2), 'Parent', hAxes(iAxes));
    hVert(iAxes) = line(nan(1, 2), yLimits(iAxes, :), 'Parent', hAxes(iAxes));
    listenObj(iAxes) = addlistener(hAxes(iAxes), {'XLim', 'YLim'}, ...
                                   'PostSet', @(~, ~) update_limits(iAxes));
  end

  % Set callback on the axes parent to the nested function below:
  set(hFigure, 'WindowButtonMotionFcn', @show_lines);

  function update_limits(axesIndex)
    xLimits(axesIndex, :) = get(hAxes(axesIndex), 'XLim');
    yLimits(axesIndex, :) = get(hAxes(axesIndex), 'YLim');
    set(hHoriz(axesIndex), 'XData', xLimits(axesIndex, :));
    set(hVert(axesIndex), 'YData', yLimits(axesIndex, :));
  end

  function show_lines(~, ~)

    % Get current cursor positions in axes:
    cursorPos = get(hAxes, 'CurrentPoint');
    cursorPos = vertcat(cursorPos{:});
    cursorPos = cursorPos(1:2:end, 1:2);

    % Determine if the cursor is within an axes:
    inAxes = (cursorPos(:, 1) >= xLimits(:, 1)) & ...
             (cursorPos(:, 1) <= xLimits(:, 2)) & ...
             (cursorPos(:, 2) >= yLimits(:, 1)) & ...
             (cursorPos(:, 2) <= yLimits(:, 2));

    % Update lines and cursor:
    if any(inAxes)  % Cursor within an axes
      set(hFigure, 'Pointer', 'custom', 'PointerShapeCData', nan(16));
      set(hHoriz(inAxes), {'YData'}, num2cell(cursorPos(inAxes, 2)*[1 1], 2));
      set(hVert(inAxes), {'XData'}, num2cell(cursorPos(inAxes, 1)*[1 1], 2));
      set(hHoriz(~inAxes), 'YData', nan(1, 2));
      set(hVert(~inAxes), 'XData', nan(1, 2));
    else  % Cursor outside axes
      set(hFigure, 'Pointer', 'arrow');
      set(hHoriz, 'YData', nan(1, 2));
      set(hVert, 'XData', nan(1, 2));
    end

  end

end

If you do the following:

full_crosshair(gcf);

Then as you move the cursor over each axes in your figure the cursor will disappear and you will see two lines appear and track the mouse position. If any of the axes limits change, then the event listeners in the above code will detect and account for it. If axes are added to or removed from the figure, you will need to call full_crosshair again to update 'WindowButtonMotionFcn' accordingly.

Finally, you can turn it off by just clearing 'WindowButtonMotionFcn':

set(gcf, 'WindowButtonMotionFcn', []);
like image 97
gnovice Avatar answered Apr 07 '23 07:04

gnovice