怎么运行的:

怎么运行的:

我正在尝试模仿我(最喜欢的)宏观经济学教科书中的边注。

在此处输入图片描述

这里的关键是小箭头指向设置边注的行。我得出了以下肮脏的代码。

编辑:我更新了下面的代码,提供了一些命令,可以将音符居中,将其向上推,或者允许手动调整(感谢 egreg、Andrew Swann 和 Martin Scharrer 帮助我解决与此相关的问题)。

普通\marginpar命令用来设置注释,\marginnote用来设置文本。

marginfix妥善保管页面底部的注释(参见图片中的最后一条注释)。但是,我想创建一些自动移动注释的过程:

  • 如果注释位于段落/节/章的末尾,请将其上移(参见第二条注释)。
  • 如果有足够的空间,找到与 marginfix 等效的选项,将注释移动到页面的顶部边缘。

这并不能涵盖所有用例,因此需要一些巧妙的自动机制来调整注释的位置但保持箭头固定。可以做这样的事情吗?是否有任何“ifatendparagraph”或“ifatendsection”钩子可以使用?

\documentclass[12pt]{scrartcl}

\usepackage{lmodern}
\usepackage{geometry}
\usepackage{etoolbox}

\usepackage{marginfix}
\setlength{\parskip}{0pt}% fix as marginfix inserts a 1pt ghost parskip

% Create length for the baselineskip of text in footnotesize
\newdimen\footnotesizebaselineskip
\newcommand{\test}[1]{%
 \setbox0=\vbox{\footnotesize\strut Test \strut}
 \global\footnotesizebaselineskip=\ht0 \global\advance\footnotesizebaselineskip by \dp0
}

% Use the measure to offset marginpars by one baseline using marginfix command
\AtBeginDocument{%
 \test{}%
 \marginposadjustment=1\footnotesizebaselineskip
}

\geometry{left=2.5cm,textwidth=130mm}

\setlength{\marginparwidth}{4cm}
\setlength{\marginparsep}{2em}

\usepackage[noadjust]{marginnote}

\newdimen\myheight
\newcommand{\boxheight}[1]{%
 \setbox0=\vbox{\strut#1\strut}
 \global\myheight=\ht0 \global\advance\myheight by \dp0
}

\newrobustcmd{\mynote}[2][]{% first the settings that are equal for all
 \linespread{1.0}% reset line spacing if using setspace
 \parbox[t]{\marginparwidth}{\footnotesize\itshape\raggedright\boxheight{#2}}% set text in parbox to measure the height of the marginnote
 \setbox0=\vtop{\footnotesize\llap{$\leftarrow$\,\,}}\marginnote{\footnotesize{\llap{$\leftarrow$\,\,}}}[2.7pt]% set the arrow
 \ifstrequal{#1}{up}{% option UP
   \setbox0=\vtop{#2}\marginpar{\footnotesize\itshape\raggedright\vspace{-\ht0}\vspace{-1\dimexpr1\myheight-1\baselineskip}#2}%
   }{% option MIDDLE
   \ifstrequal{#1}{middle}{%
    \setbox0=\vtop{#2}\marginpar{\footnotesize\itshape\raggedright\vspace{-\ht0}\vspace{-.5\dimexpr1\myheight-1\baselineskip}#2}%
    }{% nothing specified
    \ifstrempty{#1}{%
     \setbox0=\vtop{#2}\marginpar{\footnotesize\itshape\raggedright\vspace{-\ht0}#2}%
     }{% something specified
     \setbox0=\vtop{#2}\marginpar{\footnotesize\itshape\raggedright\vspace{-\ht0}\vspace{#1}#2}%
   }{\relax}%
  }{\relax}%
 }%
}%

\begin{document}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum
gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulpu-
tate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Mauris
ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibu- lum urna
fringilla ultrices.\mynote[middle]{\textbf{This note is centered because
there is enough space below and it is in the middle of a paragraph.} Erat
ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl
hendrerit mollis.} Phasellus eu tellus sit amet tortor gravida placerat.
Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Nam arcu
libero, nonummy eget, consectetuer id, vulpu- tate a, magna. Donec
vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et
netus et malesuada fames ac turpis egestas.

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi.
Morbi auctor lorem non justo. Nam lacus libero, pretium at, lobortis
vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et
nisl hendrerit mollis.Suspendisse ut massa. Cras nec ante. Pellen- tesque
a nulla. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Aliquam tincidunt urna. Nulla ullam- corper
vestibulum turpis. Pellentesque cursus luctus
mauris.\mynote[up]{\textbf{This note is pushed upwards because it is at
the end of a pragraph}}

Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at,
tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec
nonummy pellentesque ante. Phasellus adipiscing semper elit. Proin
fermentum massa ac quam. Sed diam turpis, molestie vitae, placerat a,
molestie nec, leo. Maecenas lacinia. Nam ipsum ligula, eleifend at,
accumsan nec, suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc
eleifend consequat lorem. Sed lacinia nulla vitae enim. Pellentesque
tincidunt purus vel magna. Integer non enim. Praesent euismod nunc eu
purus. Donec bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec
et mi. Nam vulputate metus eu enim. Vestibulum pellentesque felis eu
massa.

Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vi- tae
lacus tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. In hac habitasse platea dictumst. Integer tempus con-
vallis augue. Etiam facilisis. Nunc elementum fermentum wisi. Aenean
placerat. Ut imperdiet, enim sed gravida sollicitudin, felis odio placerat
quam, ac pulvinar elit purus eget enim. Nunc vitae tortor. Proin tempus
nibh sit amet nisl. Vivamus quis tortor vitae risus porta
vehicula.\mynote{\textbf{This note is automatically adjusted by
`marginfix'.} Phasellus adipiscing semper elit. Proin fermentum massa ac
quam. Sed diam turpis, molestie vitae, placerat a, molestie nec, leo.
Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec, suscipit a,
ipsum.} Fusce mauris. Vestibulum luctus nibh at lectus. Sed bibendum,
nulla a vel justo vi- tae lacus tinci dunt ultrices. Lorem ipsum dolor sit
amet. Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec,
suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc eleifend
consequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt
purus vel magna. Integer non enim. Praesent euismod nunc eu purus. Donec
bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec et mi. Nam
vulputate metus eu enim. Vestibulum pellentesque felis eu massa.

\end{document}

与 David 的回答和我的评论相关,如果两个注释靠得很近,那么两者之间最好有一个最小的间隙,正如您在图片中看到的“注释 1”和“注释 2”之间的那样:

在此处输入图片描述

答案1

由于只在这一页上进行了测试,因此它可能不够强大,但它展示了一种机制(\pdfsavepos此版本依赖于 pdftex),该机制会自动将注释移到(明确)段落末尾,并根据需要缩小注释间的空间,以避免注释从页面上掉下来。在此版本中,它永远不会将注释拆分到页面上,如果页面上的注释不适合,它们将产生一个 over=full 框。

我留下了一条垂直线和两条水平线作为调试辅助来显示边距区域。

在此处输入图片描述

\documentclass[12pt]{scrartcl}

\usepackage{lmodern}
\usepackage{geometry}

\geometry{left=2.5cm,textwidth=130mm}

\setlength{\marginparwidth}{4cm}
\setlength{\marginparsep}{2em}
\newcounter{mpcnt}

\makeatletter


\gdef \@makecol {%
   \ifvoid\footins
     \setbox\@outputbox \box\@cclv
   \else
     \setbox\@outputbox \vbox {%
       \boxmaxdepth \@maxdepth
       \unvbox \@cclv
       \vskip \skip\footins
       \color@begingroup
         \normalcolor
         \footnoterule
         \unvbox \footins
       \color@endgroup
       }%
   \fi
%
   \let\@elt\relax
   \xdef\@freelist{\@freelist\@midlist}%
   \global \let \@midlist \@empty
   \@combinefloats
   \ifvbox\@kludgeins
     \@makespecialcolbox
   \else
\ifvoid\mpins
     \setbox\@outputbox \vbox to\@colht {%
       \@texttop
       \dimen@ \dp\@outputbox
       \unvbox \@outputbox
       \vskip -\dimen@
       \@textbottom
       }%
\else
     \setbox\@outputbox \hbox{\vbox to\@colht {%
       \@texttop
       \dimen@ \dp\@outputbox
       \unvbox \@outputbox
       \vskip -\dimen@
       \@textbottom
       }%
\vrule
\kern\marginparsep
%\showboxdepth1
%\tracingonline3\tracingoutput\@ne
%\showboxbreadth20
%\showbox\mpins
\ifx\mpins@@\@undefined
\@tempdima\@colht
\else
\@tempdima\expandafter\@gobble\mpins@@
\fi
%\showthe\@colht
\vbox to \dimexpr\@colht\relax{%2
\pdfsavepos
\edef\tmp{\write\noexpand\@auxout{%
\string\mpardata{@}{\noexpand\thepage}{\noexpand\the\noexpand\pdflastypos}}}\tmp
\hrule
\vbadness\maxdimen
\loop
\setbox0=\vsplit\mpins to \maxdimen
\setbox0\vbox{\unvbox\z@\global\setbox\@ne\lastbox}%
\@tempdimb=\dimexpr\@tempdima-\wd\@ne-(\ht\z@+\dp\z@)/2\relax
\ifdim\@tempdimb<\z@\@tempdimb\z@\fi
\vskip\@tempdimb \@minus\@tempdimb
\@tempdima=\dimexpr\@tempdima-\@tempdimb-\ht\z@-\dp\z@\relax
\box\z@
\ifvoid\mpins\else
\repeat
\vskip\z@\@plus\@colht
\hrule
}%
}
\fi
   \fi
   \global \maxdepth \@maxdepth
}


\def\mpardata#1#2#3{%
\expandafter\gdef\csname mpins@#1\endcsname{\kern#3sp}%
}


\long\def\mynote#1{%
\refstepcounter{mpcnt}%
\strut
\pdfsavepos
\edef\tmp{\write\noexpand\@auxout{%
\string\mpardata{\the\c@mpcnt}{\noexpand\thepage}{\noexpand\the\noexpand\pdflastypos}}}\tmp
\vadjust{%
\hbox to \linewidth{%
\hfill\smash{\raise\dp\strutbox\hbox to \z@{$\leftarrow$\hss}}}}
\@savemarbox\@ne{\raggedright\footnotesize#1\par}%
\@ifnextchar\par{%
\expandafter\ifx\csname mpins@\the\c@mpcnt\endcsname\relax
\@insertmpins{}%
\else
\edef\@tmp{\kern\the\dimexpr (\ht\@ne+\dp\@ne)/2\relax}%
\@insertmpins{%
\csname mpins@\the\c@mpcnt\endcsname\relax
\@tmp
}%
\fi}{%
\@insertmpins{\csname mpins@\the\c@mpcnt\endcsname}}}

\def\@insertmpins#1{%
\insert\mpins{%
\box\@ne
\nointerlineskip
\hbox{#1}%
\penalty-\@M}}

\newinsert\mpins
\skip\mpins\z@
\count\mpins\z@
\dimen\mpins\textheight

\begin{document}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum
gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulpu-
tate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Mauris
ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibu- lum urna
fringilla ultrices.\mynote{\textbf{This note is centered because
there is enough space below and it is in the middle of a paragraph.} Erat
ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl
hendrerit mollis.} Phasellus eu tellus sit amet tortor gravida placerat.
Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Nam arcu
libero, nonummy eget, consectetuer id, vulpu- tate a, magna. Donec
vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et
netus et malesuada fames ac turpis egestas.

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi.
Morbi auctor lorem non justo. Nam lacus libero, pretium at, lobortis
vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et
nisl hendrerit mollis.Suspendisse ut massa. Cras nec ante. Pellen- tesque
a nulla. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Aliquam tincidunt urna. Nulla ullam- corper
vestibulum turpis. Pellentesque cursus luctus
mauris.\mynote{\textbf{This note is pushed upwards because it is at
the end of a pragraph}}

Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at,
tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec
nonummy pellentesque ante. Phasellus adipiscing semper elit. Proin
fermentum massa ac quam. Sed diam turpis, molestie vitae, placerat a,
molestie nec, leo. Maecenas lacinia. Nam ipsum ligula, eleifend at,
accumsan nec, suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc
eleifend consequat lorem. Sed lacinia nulla vitae enim. Pellentesque
tincidunt purus vel magna. Integer non enim. Praesent euismod nunc eu
purus. Donec bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec
et mi. Nam vulputate metus eu enim. Vestibulum pellentesque felis eu
massa.

Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vi- tae
lacus tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. In hac habitasse platea dictumst. Integer tempus con-
vallis augue. Etiam facilisis. Nunc elementum fermentum wisi. Aenean
placerat. Ut imperdiet, enim sed gravida sollicitudin, felis odio placerat
quam, ac pulvinar elit purus eget enim. Nunc vitae tortor. Proin tempus
nibh sit amet nisl. Vivamus quis tortor vitae risus porta
vehicula.\mynote{\textbf{This note is automatically adjusted by
`marginfix'.} Phasellus adipiscing semper elit. Proin fermentum massa ac
quam. Sed diam turpis, molestie vitae, placerat a, molestie nec, leo.
Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec, suscipit a,
ipsum. make ot just a bit longer to show it moving better.} Fusce mauris. Vestibulum luctus nibh at lectus. Sed bibendum,
nulla a vel justo vi- tae lacus tinci dunt ultrices. Lorem ipsum dolor sit
amet. Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec,
suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc eleifend
consequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt
purus vel magna. Integer non enim. Praesent euismod nunc eu purus. Donec
bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec et mi. Nam
vulputate metus eu enim. Vestibulum pellentesque felis eu massa.

\end{document}

答案2

更新:

这些稍后会被删除。在开发/测试期间,现在添加到此处。

  • 2012-11-23:添加了\AtEndDocument钩子以在文档末尾添加幻像段落。这纠正了开发过程中发现的问题,即最后一段底部的边距段落无法自动向上移动。

这是使用臭名昭著tikz\tikzmark的版本。这最初是从我之前的解决方案开始的,在我怎样才能在页边空白处做真正的注释?

怎么运行的:

它用于\everypar{}将 放置\tikzmark在每个段落的开头。然后,当\MarginPar遇到时\tikzmark,将访问当前段落和后续段落的 ,并从 的源头\MarginPar到段落的结尾进行测量。由此确定垂直偏移。

基本用法:

使用 just会产生以下结果。请注意,我已调整了最后\MarginPar{<content>}的注释,因为此处未使用。marginfix\MarginParmarginfix

为了更容易看到箭头指向的实际来源\MarginPar,我手动为之前的单词添加了红色,为之后的单词添加了蓝色\MarginPar

在此处输入图片描述

想要:

由于这一点,\tikz它具有很大的固有灵活性。在您想要如何设置边距样式方面,有常见的方法,但还有一个附加方法,即如果您使用yshift=<length>垂直向上移动边距,箭头将以不同的方式绘制(但前提是有足够的垂直移动)。以下内容由以下代码生成:

\MarginPar[draw=brown, fill=yellow!20, inner sep=2pt, yshift=2cm][green]
    {<content>}

第一个可选参数应用于边距和内容,第二个可选参数应用于箭头。

在此处输入图片描述

笔记:

  • 与大多数\tikzmark解决方案一样,这确实需要运行两次。如果您看到非常奇怪的结果,请在惊慌之前尝试重新运行。
  • 如果您取消注释,%\def\DebugMarginPar{}则调试输出将启用并显示在文本顶部。左侧的文本是中间长度。橙色实线是从源到当前段落的开头,红色虚线是从源到当前段落的结尾。
  • 要更改边距部分的默认样式,您可以调整\MarginParStyle宏。

参考:

进一步增强/已知问题

  • 需要纳入 Andrew Stacey 即将推出的tikzmark套餐。

  • 如果箭头调整功能有用,可能需要进行更多调整才能确定其启用的具体位置。我进行了初步尝试,但只进行了少量测试,因此不确定它会在哪里出现问题。

  • 需要更多测试...

算法:

这可能是比这里实现的更好的算法,但这里简要解释了它如何确定要应用哪些移位(如果有的话)。这里的距离是从箭头位置(即 的源头)到 的垂直距离\MarginPar

if (distance to end of para > 0.5*(height of margin par) then
    margin par can be centered about this point.
    It may go above start of para but I think that is ok
 else 
    move margin par so that bottom of the margin par is at end of para.

代码:

%% Uncomment to enable debug output. Note that this also enable `\layout` 
%% so the text will shift forward. So don't panic, just go to the next page.
%%
%\def\DebugMarginPar{}% 

\documentclass[12pt]{scrartcl}

\usepackage{lmodern}
\usepackage{geometry}
\usepackage{etoolbox}
\usepackage{xcolor}
%\usepackage{marginfix}% Not used

\usepackage{etoolbox}
\usepackage{xparse}
\usepackage{xstring}
\usepackage{tikz}
\usetikzlibrary{calc}

\ifdefined\DebugMarginPar% For debug use only
    % https://tex.stackexchange.com/questions/558/is-there-a-show-for-lengths
    \usepackage{printlen}\uselengthunit{mm}
    \usepackage{layout}
\fi

\geometry{left=2.5cm,textwidth=130mm}

\setlength{\marginparwidth}{4cm}
\setlength{\marginparsep}{2em}
\usepackage[noadjust]{marginnote}


% https://tex.stackexchange.com/questions/33703/extract-x-y-coordinate-of-an-arbitrary-point-in-tikz
\newdimen\XCoord
\newdimen\YCoord
\newcommand*{\ExtractCoordinate}[1]{\path (#1); \pgfgetlastxy{\XCoord}{\YCoord};}%
%
\newcommand*{\SetLengthToYCoordinate}[2]{%
    \ExtractCoordinate{#2}%
    \setlength{#1}{\YCoord}%
}%

% Default style for the margin par node.
\ifdefined\DebugMarginPar
    \tikzset{Default Marginpar Style/.style={
            shape=rectangle,inner sep=0, draw=blue, 
            rounded corners=2pt, blue, font=\itshape}
        }
\else
    \tikzset{Default Marginpar Style/.style={
            shape=rectangle,inner sep=0, draw=none, 
            rounded corners=2pt, blue, font=\itshape}
        }
\fi

\tikzset{Default Arrow Style/.style={red, ultra thick, -stealth, shorten <= 2pt, shorten >= 2pt}}

% Following determined via \layout: 
\newlength{\EndOfTextOffsetFromWest}
\newlength{\StartOfMarginNotes}
\setlength{\EndOfTextOffsetFromWest}{\dimexpr1in+\hoffset+\textwidth\relax}
\setlength{\StartOfMarginNotes}{\dimexpr\EndOfTextOffsetFromWest+\marginparsep\relax}

% Change this to set the default style for the margin par.
\newcommand*{\MarginParStyle}[2][\marginparwidth]{%
    % #1 = optional width of parbox
    % #2 = content of margin par
    %
    % We don't want `\everypar` to have any effect on these paragraphs so
    % disable that while we are in here.
    \global\toggletrue{InMarginNote}% 
    \parbox[t]{#1}{%
        \footnotesize\itshape\raggedright%
        #2%
    }%
    \global\togglefalse{InMarginNote}%
}%

\newlength{\CurrentParHeight}
\newlength{\CurrentMargiparHeight}
\newlength{\CurrentPointToStartOfPara}
\newlength{\CurrentPointToEndOfPara}
\newlength{\VerticalShift}
\newlength{\VerticalDistanceToMarginParSouth}% for fancy arrow
\newcounter{NextPara}
\NewDocumentCommand{\MarginPar}{%
    O{}% #1 = draw options for the marginpar
    O{}% #2 = draw options for the arrow
    m  % #3 = margin par text
    }{%
    \setbox0=\vtop{\MarginParStyle{#3}}%
    \setlength{\CurrentMargiparHeight}{\ht0}% height of this marginpar
    \addtolength{\CurrentMargiparHeight}{\dp0}%
    \begin{tikzpicture}[overlay,remember picture, thick]
        \coordinate (EdgeOfText) at 
            ($(current page.west |- 0,0) 
            + (\EndOfTextOffsetFromWest,0.5ex)$);
        \coordinate (MarginParWestSide) at ($(EdgeOfText)+(\marginparsep,0)$);
        \setcounter{NextPara}{\arabic{ParaCount}};
        \stepcounter{NextPara}

        \path (pic cs:Para\arabic{ParaCount},{(0, \paperheight)}) + 
                  (0, 0.7\baselineskip) coordinate (CurrentParStart);
        \path (pic cs:Para\arabic{NextPara},{(0,-\paperheight)}) + 
                  (0,-0.3\baselineskip) coordinate (NextParStart);

        \ifdefined\DebugMarginPar
            % Debug: Location of start of paragraphs with a marginpar
            \draw [line width=0.5cm,green,opacity=.3] 
                    (CurrentParStart) circle (2pt);
        \fi

        \coordinate (VectorParHeight) at ($(CurrentParStart)-(NextParStart)$);
        \SetLengthToYCoordinate{\CurrentParHeight}{VectorParHeight}

        % Now check that current para does not continue on to the next page.
        % If it does we need to do me some tweakin' and set the end of this
        % para to be the end of the text on this page
        \pgfmathtruncatemacro{\ParaContinuesToNextPage}
                {\CurrentParHeight >  0 ? 0 : 1}
        \IfEq{\ParaContinuesToNextPage}{0}{}{%
            \coordinate (NextParStart) at 
                ($(current page.north)   % top of page
                - (0, 1.0in + \voffset)  % (2) in \layout
                - (0, \headsep)          % (6) in \layout
                - (0, \textheight)       % (7) in \layout
                - (0, 0.7\baselineskip)
                $);
            \coordinate (VectorParHeight) at 
                    ($(CurrentParStart)-(NextParStart)$);
            \SetLengthToYCoordinate{\CurrentParHeight}{VectorParHeight}
        }

        \coordinate (VectorToStartOfPara) at 
                (MarginParWestSide |- CurrentParStart);
        \SetLengthToYCoordinate{\CurrentPointToStartOfPara}{VectorToStartOfPara}

        \ifdefined\DebugMarginPar
        \draw [orange, ultra thick,-latex] 
            ([xshift=-0.25\arabic{ParaCount} cm]MarginParWestSide) -- 
            ([xshift=-0.25\arabic{ParaCount} cm]VectorToStartOfPara);
        \fi

        % The \baselineskip adjustment is so that we are measuring to the end
        % of the current para, as opposed to the start of the next para.
        \coordinate (VectorToEndOfPara) at 
            ($(MarginParWestSide |- NextParStart) +(0,\baselineskip)$);
        \SetLengthToYCoordinate{\CurrentPointToEndOfPara}{VectorToEndOfPara}

        \ifdefined\DebugMarginPar
            % Debugging: line from arrow to end of para
            \draw [red!40, dotted, ultra thick,-latex]% 
                ([xshift=-0.35\arabic{ParaCount} cm]MarginParWestSide) -- 
                ([xshift=-0.35\arabic{ParaCount} cm]VectorToEndOfPara);
        \fi

        % Now we have: 
        %
        % \CurrentParHeight      = the height of the current paragraph saved as 
        % \CurrentMargiparHeight = height of the margin par
        % (MarginParWestSide)    = coordinate of start of arrow
        % \CurrentPointToStartOfPara = distance from start of para to arrow
        % \CurrentPointToEndOfPara   = distance from end of para to arrow
        %
        % So it is just a matter of applying some algorithm to tweak the 
        % vertical placement.  Here  is one possible algorithm: 
        %
        % Note: Distances are measured from the vertical location of the arrow.
        %
        % if (distance to end of para > 0.5*(height of margin par) then
        %    margin par can be centered about this point
        %    it may go above start of para but I think that is ok
        % else 
        %    move margin par so that bottom of the margin par is at end of para.        
        \pgfmathsetlength{\VerticalShift}{
                -\CurrentPointToEndOfPara > 0.5*\CurrentMargiparHeight  ? 0cm :
                % First version aligns bottom of marginpar with arrow location.
                %0.5*(\CurrentMargiparHeight - 0.5*\baselineskip)%
                0.5*(\CurrentMargiparHeight - 0.0*\baselineskip) +
                \CurrentPointToEndOfPara
            }

        \node [Default Marginpar Style, anchor=west, #1] (marginpar) at 
                ($(MarginParWestSide) + (0,\VerticalShift)$)  
                 {\MarginParStyle{#3}};

        % Well, since this is a tikz solution we need to do
        % something slightly fancy, so check if the margin par was
        % moved above far enough that a simple horizontal arrow 
        % is not enough.
        %
        % The last coordinate below is tweak so that we don't end up
        % with a vertical component of the arrow that is hardly visible.
        \coordinate (VerticalVectorFromMarginParToArrow) at 
            ($(marginpar.south) - (EdgeOfText) - (0,4.0pt)$);
        \SetLengthToYCoordinate{\VerticalDistanceToMarginParSouth}{VerticalVectorFromMarginParToArrow}

        \pgfmathtruncatemacro{\NeedFancyArrow}
                {\VerticalDistanceToMarginParSouth >  0 ? 1 : 0}

        \IfEq{\NeedFancyArrow}{0}{%
            \draw [Default Arrow Style, #2] (MarginParWestSide) to (EdgeOfText);
        }{%
            \draw [Default Arrow Style, #2] 
                    (marginpar.south) -- 
                    (marginpar.south |- EdgeOfText) --
                    (EdgeOfText);
        }%

        \ifdefined\DebugMarginPar
       %% Debugging: Y = vertical location of arrow pointing to source
            \node [
                text width=8.5cm, font=\tiny, draw=red, anchor=south, 
                fill=white, fill opacity=1
                ] 
                at  ($(EdgeOfText) - (0.75\textwidth,-0.2)$)
                {\MarginParStyle[8.5cm]{%
                    ParaCount = \arabic{ParaCount}\\
                    CurrentParHeight = \printlength{\CurrentParHeight}\\
                    CurrentMargiparHeight = \printlength{\CurrentMargiparHeight}\\
                    CurrentPointToStartOfPara = \printlength{\CurrentPointToStartOfPara}\\
                    CurrentPointToEndOfPara = \printlength{\CurrentPointToEndOfPara}\\
                    ParaContinuesToNextPage = \ParaContinuesToNextPage\\
                    VerticalDistanceToMarginParSouth = \printlength{\VerticalDistanceToMarginParSouth}
                    }%
                };
        \fi
    \end{tikzpicture}%
}



%--------------------------------------------
% https://tex.stackexchange.com/questions/50015/tikzmark-to-have-different-behaviour-if-first-run-and-mark-locations-not-yet-av
\makeatletter
\tikzset{%
  remember picture with id/.style={%
    remember picture,
    overlay,
    save picture id=#1,
  },
  save picture id/.code={%
    \edef\pgf@temp{#1}%
    \immediate\write\pgfutil@auxout{%
      \noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
  },
  if picture id/.code args={#1#2#3}{%
    \@ifundefined{save@pt@#1}{%
      \pgfkeysalso{#3}%
    }{
      \pgfkeysalso{#2}%
    }
  }
}

\def\savepointas#1#2{%
  \expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
  \def\tmk@label{#1}%
  \def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
  \pgfutil@in@,{#1}%
  \ifpgfutil@in@%
    \tmk@labeldef#1\@nil
  \else
    \tmk@labeldef#1,(0pt,0pt)\@nil
  \fi
  \@ifundefined{save@pt@\tmk@label}{%
    \tikz@scan@one@point\pgfutil@firstofone\tmk@def
  }{%
  \pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
  \pgfsys@getposition{\pgfpictureid}\save@this@pic%
  \pgf@process{\pgfpointorigin\save@this@pic}%
  \pgf@xa=\pgf@x
  \pgf@ya=\pgf@y
  \pgf@process{\pgfpointorigin\save@orig@pic}%
  \advance\pgf@x by -\pgf@xa
  \advance\pgf@y by -\pgf@ya
  }%
}
\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}
\makeatother
%--------------------------------------------

\newcounter{ParaCount}
\newtoggle{InMarginNote}

\newcommand*{\MarkParaWithTikzMark}{%
    \iftoggle{InMarginNote}{%
        % Don't want to count the margin note paragraphs.
    }{%
        \stepcounter{ParaCount}%
        \tikzmark{Para\arabic{ParaCount}}%
    }%
}%
\AtBeginDocument{%
    \setcounter{ParaCount}{0}%
    \global\togglefalse{InMarginNote}% 
    % https://tex.stackexchange.com/questions/33849/what-does-the-the-everypar-do
    \everypar{\MarkParaWithTikzMark}%
}%

% Need this to handle the case where there is no aditional text following 
% the last para.
\AtEndDocument{\MarkParaWithTikzMark}%


% Add highlighting to words before and after so that we know
% we are pointing to the correct place.  These are really for
% debugging, but useful to leave them so we know that the
% arrows points to the correct place.
\newcommand*{\Before}[1]{\textcolor{red}{#1}}%
\newcommand*{\After}[1]{\textcolor{blue}{#1}}%


%
\begin{document}\ifdefined\DebugMarginPar\layout\fi
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum
gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulpu-
tate a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi
tristique senectus et netus et malesuada fames ac turpis egestas. Mauris
ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibu- lum urna
fringilla \Before{ultrices}.\MarginPar{\textbf{This note is centered because
there is enough space below and it is in the middle of a paragraph.} Erat
ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et nisl
hendrerit mollis.} 
\After{Phasellus} eu tellus sit amet tortor gravida placerat.
Integer sapien est, iaculis in, pretium quis, viverra ac, nunc. Nam arcu
libero, nonummy eget, consectetuer id, vulpu- tate a, magna. Donec
vehicula augue eu neque. Pellentesque habitant morbi tristique senectus et
netus et malesuada fames ac turpis egestas.

Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi.
Morbi auctor lorem non justo. Nam lacus libero, pretium at, lobortis
vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et
nisl hendrerit mollis.Suspendisse ut massa. Cras nec ante. Pellen- tesque
a nulla. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Aliquam tincidunt urna. Nulla ullam- corper
vestibulum turpis. Pellentesque cursus luctus
\Before{mauris}.\MarginPar{\textbf{This note is pushed upwards because it is at
the end of a paragraph}}

\After{Nulla} malesuada porttitor diam. Donec felis erat, congue non, volutpat at,
tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec
nonummy pellentesque ante. Phasellus adipiscing semper elit. Proin
fermentum massa ac quam. Sed diam turpis, molestie vitae, placerat a,
molestie nec, leo. Maecenas lacinia. Nam ipsum ligula, eleifend at,
accumsan nec, suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc
eleifend consequat lorem. Sed lacinia nulla vitae enim. Pellentesque
tincidunt purus vel magna. Integer non enim. Praesent euismod nunc eu
purus. Donec bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec
et mi. Nam vulputate metus eu enim. Vestibulum pellentesque felis eu
massa.

Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vi- tae
lacus tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. In hac habitasse platea dictumst. Integer tempus con-
vallis augue. Etiam facilisis. Nunc elementum fermentum wisi. Aenean
placerat. Ut imperdiet, enim sed gravida sollicitudin, felis odio placerat
quam, ac pulvinar elit purus eget enim. Nunc vitae tortor. Proin tempus
nibh sit amet nisl. Vivamus quis tortor vitae risus porta
\Before{vehicula}.\MarginPar{\textbf{This note used to be automatically adjusted by
`marginfix'.} Phasellus adipiscing semper elit. Proin fermentum massa ac
quam. Sed diam turpis, molestie vitae, placerat a, molestie nec, leo.
Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec, suscipit a,
ipsum.} \After{Fusce} mauris. 
Vestibulum luctus nibh at lectus. Sed bibendum,
nulla a vel justo vi- tae lacus tinci dunt ultrices. Lorem ipsum dolor sit
amet. Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec,
suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc eleifend
consequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt
purus vel magna. Integer non enim. Praesent euismod nunc eu purus. Donec
bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec et mi. Nam
vulputate metus eu enim. Vestibulum pellentesque felis eu massa.

Vestibulum luctus nibh at lectus. Sed bibendum,
nulla a vel justo vi- tae lacus tinci dunt ultrices. Lorem ipsum dolor sit
amet. Maecenas lacinia. Nam ipsum ligula, eleifend at, accumsan nec,
suscipit a, ipsum. Morbi blandit ligula feugiat magna. Nunc eleifend
consequat lorem. Sed lacinia nulla vitae enim. Pellentesque tincidunt
purus vel magna. Integer non enim. Praesent euismod nunc eu purus. Donec
bibendum quam in tellus. Nullam cursus pulvinar lectus. Donec et mi. Nam
vulputate metus eu enim. Vestibulum pellentesque felis eu massa.

Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vi- tae
lacus tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer
adipiscing elit. In hac habitasse platea dictumst. Integer tempus con-
vallis augue. Etiam \Before{facilisis}. 
\MarginPar[draw=brown, fill=yellow!20, inner sep=2pt, yshift=2cm][green]
    {Here is an demo of a few of the tikz options and an illustration
    of the auto arrow adjustments.%
    }
\After{Nunc} elementum fermentum wisi. Aenean
placerat. Ut imperdiet, enim sed gravida sollicitudin, felis odio placerat
quam, ac pulvinar elit purus eget enim. Nunc vitae tortor. Proin tempus
nibh sit amet nisl. Vivamus quis tortor vitae risus porta
\end{document}

相关内容