[Tex/LaTex] How to make the hyperlink point to the top of linked figure and item of enumeration

#enumeratecross-referencinghyperreflabelslinks

I want to create a problem booklet. Each problem numbered by enumerate has at most one figure that may either be in marginpar or float and occupy the full width.

The caption for each figure has a hyperlink to the corresponding question. From the question, we also has a link to the corresponding figure.

I use auto-generated labels

\def\qMark{Q.\arabic{chapter}.\arabic{section}.\arabic{enumi}}
\def\fMark{F.\arabic{chapter}.\arabic{section}.\arabic{enumi}}

to establish the linking.

I add \usepackage[all]{hypcap} to get a better linking behavior, i.e., clicking a hyperlink will direct us to the top of the linked object rather than to the point that requires us to adjust the view.

\documentclass[12pt]{book}
\usepackage[
    a4paper,
    vmargin=2cm,
    outermargin=9cm,
    innermargin=2cm,
    marginparwidth=7cm,
    marginparsep=20pt
]{geometry}


\usepackage{graphicx}
\usepackage{marginfix}
\usepackage{ifoddpage}
\usepackage{caption}

\usepackage{lipsum}

\usepackage[colorlinks,bookmarksnumbered]{hyperref}
\usepackage[all]{hypcap}


\def\qMark{Q.\arabic{chapter}.\arabic{section}.\arabic{enumi}}
\def\fMark{F.\arabic{chapter}.\arabic{section}.\arabic{enumi}}

\let\tempItem=\item
\renewcommand\item{\tempItem\label{\qMark}}

\def\getQRef{Problem~\ref{\qMark}}
\def\getFRef{\figurename~\ref{\fMark}}


\newcommand\MarginFig{%
\marginpar{\includegraphics[width=\linewidth]{example-image-a}
\captionof{figure}{For \getQRef.}\label{\fMark}%
}}

\newcommand\FullFig{%
\begin{figure}[hbtp]
    \checkoddpage
  \edef\side{\ifoddpage l\else r\fi}%
    \makebox[\textwidth][\side]{% 
    \parbox{\dimexpr\textwidth+\marginparwidth+\marginparsep\relax}{%
        \includegraphics[width=\linewidth]{example-image-b}
        \caption{For \getQRef.}
        \label{\fMark}}}
\end{figure}
}


\begin{document}
\chapter{Higgs Boson}

\begin{enumerate}
\item
\MarginFig
\getFRef\
\lipsum[1]

\item
\lipsum[1]

\item
\FullFig
\lipsum[1]\getFRef.

\item
\MarginFig
\lipsum[1]\getFRef.

\item
\FullFig
\lipsum[1]\getFRef.

\item
\MarginFig
\lipsum[1]\getFRef.

\item
\lipsum[1]
\end{enumerate}

\end{document}

Unfortunately, clicking, for example, Figure 1.3 or Problem 3 does not behave as they are supposed to be. Please try them by yourself to get the idea.

How to fix this issue?

Best Answer

You can put the \label at the top of the box. (I also added some % at ends of lines)

\documentclass[12pt]{book}
\usepackage[
    a4paper,
    vmargin=2cm,
    outermargin=9cm,
    innermargin=2cm,
    marginparwidth=7cm,
    marginparsep=20pt
]{geometry}


\usepackage{graphicx}
\usepackage{marginfix}
\usepackage{ifoddpage}
\usepackage{caption}

\usepackage{lipsum}

\usepackage[colorlinks,bookmarksnumbered]{hyperref}
\usepackage[all]{hypcap}


\def\qMark{Q.\arabic{chapter}.\arabic{section}.\arabic{enumi}}
\def\fMark{F.\arabic{chapter}.\arabic{section}.\arabic{enumi}}

\let\tempItem=\item
\renewcommand\item{\tempItem\leavevmode\label{\qMark}\ignorespaces}

\def\getQRef{Problem~\ref{\qMark}}
\def\getFRef{\figurename~\ref{\fMark}}

\makeatletter
\newcommand\MarginFig{%
\marginpar{%
\refstepcounter{figure}%
\label{\fMark}%
\let\refstepcounter\@gobble
\let\H@refstepcounter\@gobble
\let\hyper@@anchor\@gobble
\includegraphics[width=\linewidth]{example-image-a}%
\captionof{figure}{For \getQRef.}%
}}

\newcommand\FullFig{%
\begin{figure}[hbtp]%
    \checkoddpage
  \edef\side{\ifoddpage l\else r\fi}%
\refstepcounter{figure}%
    \makebox[\textwidth][\side]{\label{\fMark}% 
    \parbox{\dimexpr\textwidth+\marginparwidth+\marginparsep\relax}{%
\let\refstepcounter\@gobble
\let\H@refstepcounter\@gobble
\let\hyper@@anchor\@gobble
        \includegraphics[width=\linewidth]{example-image-b}%
        \caption{For \getQRef.}}}%
\end{figure}%
}
\makeatother

\begin{document}
\chapter{Higgs Boson}

\begin{enumerate}
\item
\MarginFig
\getFRef\
\lipsum[1]

\item
\lipsum[1]

\item
\FullFig
\lipsum[1]\getFRef.

\item
\MarginFig
\lipsum[1]\getFRef.

\item
\FullFig
\lipsum[1]\getFRef.

\item
\MarginFig
\lipsum[1]\getFRef.

\item
\lipsum[1]
\end{enumerate}

\end{document}