19

I have a piece of text that can be quite long, but I only have room for one line in the report. How can I fade it out once I reach, say, .5\linewidth?

I'd like to have a syntax similar to

\FadeAfter{.5\linewidth}{Quack, quack}

Random Requirements

  • PDF format
  • It needs to view and print correctly from Evince 2.28.2 (don't shoot the messenger) and a current version of Adobe Reader

Related

  • Does overlaying with a white gradient work? Where do you want to fade it out to (length-wise)? – Werner Oct 9 '14 at 2:32
  • @Werner In TikZ terms, I want it to start fading at #1 and stop fading at .east, at which point it will be completely transparent. Pure-white works, too, but I'll always wonder if there's a way to do it with just transparency :) – Sean Allred Oct 9 '14 at 2:35
  • Does it need to print correctly? Does it need to display correctly in all (reasonably sane) PDF viewers? (I'm assuming we are talking PDF though you don't actually say.) – cfr Oct 9 '14 at 3:07
  • I do mean PDF, and it must print correctly. I'd very much like to view it—Adobe Reader and Evince are probably the only two viewers I'm technically targeting – Sean Allred Oct 9 '14 at 3:09
  • 1
    have you considered texample.net/tikz/examples/text-fading ? – Nico Vecchio Oct 9 '14 at 6:06
17

Here is a possibility which draws white color over the text:

\documentclass{article}
\usepackage{tikz,lipsum}
\usetikzlibrary{fadings}

\makeatletter
\tikzfading[name=fade left,
  left color=transparent!100,
  right color=transparent!0]

\newcommand{\FadeAfter}[2]{%
  \par\noindent\begin{tikzpicture}
  \node[inner sep=0pt,inner ysep=2pt,outer sep=0pt,clip] (A) {\makebox[\linewidth][l]{#2}};
  \fill[white,path fading=fade left] ([xshift={#1}]A.south west) rectangle ([xshift={1pt}]A.north east);
  \end{tikzpicture}\par%
}

\makeatother

\begin{document}

\FadeAfter{0pt}{\lipsum[1]}
\FadeAfter{.25\linewidth}{\lipsum[1]}
\FadeAfter{.5\linewidth}{\lipsum[1]}
\FadeAfter{.75\linewidth}{\lipsum[1]}

\medskip
\lipsum[1]

\end{document}

enter image description here

I have removed the indent, but the macro could be adapted, if you want to indent the text.

  • Doesn't seem to work with Evince :( Works in Preview, though. If I can get it to print correctly, this will get the tick :) – Sean Allred Oct 9 '14 at 12:37
  • Works in Evince 3.10.3, Acrobat 9.4.1, xpdf 3.04, gv 3.7.4 (all Linux) – alfC Oct 9 '14 at 17:46
  • @alfC Good to hear. I can only test under Windows. Thank you :-) – Thomas F. Sturm Oct 9 '14 at 18:40
10

The strategy here is to add a character with each loop, stuff the current string into a box and measure it. Then, use the fractional measure of current length to fade-length to subtract intensity from the color of that character. The routine \prefahelper I use to determine whether I am at the end of a word and need to remember a space. The routine \fahelper is the workhorse, called upon recursively by \fahelp.

Thanks to percusse at Dividing dimensions to get a count for showing how to divide lengths using counters (a trick he learned from egreg, if I recall).

EDITED to multiply denominator by 0.01, rather than multiply numerator by 100, in order to avoid counter overflows. Multiline example shown. EDITED to correct bug with one-letter words.

\documentclass{article}
\usepackage{xcolor,ifthen}
\newcounter{tmpcounter}
\newlength\cumlength
\newlength\critlength
\newlength\tmplength
\newcount\mynum
\newcount\myden
\makeatletter
\newcommand\FadeAfter[2]{\critlength=#1\relax\cumlength=0pt\relax%
  \def\cumstring{}\fahelp{#1}{#2}}
\newcommand\fahelp[2]{\prefahelper#2 \relax\fahelper#2\relax}
\def\prefahelper#1#2 #3\relax{\gdef\wordremaining{#1#2}}
\def\fahelper#1#2\relax{%
  \global\protected@edef\cumstring{\cumstring#1}%
  \ifthenelse{\equal{#1}{\wordremaining}}{%
    \global\protected@edef\cumstring{\cumstring\ }}{}%
  \setbox0=\hbox{\cumstring}%
  \tmplength=.01\critlength\relax%
  \mynum=\wd0\relax%
  \myden=\tmplength\relax%
  \divide\mynum by\myden%
  \setcounter{tmpcounter}{\numexpr100-\the\mynum}%
  \ifnum\thetmpcounter<0\setcounter{tmpcounter}{0}\fi%
  \textcolor{black!\thetmpcounter}{#1}%
  \ifthenelse{\equal{#1}{\wordremaining}}{\ }{}%
  \ifdim\wd0<\critlength%
    \ifx\relax#2\relax\else\fahelp{\critlength}{#2}\fi%
  \fi%
}
\makeatother
\begin{document}
\FadeAfter{.5in}{testing whether this fades away}%
\FadeAfter{1in}{testing whether this fades away}%
\FadeAfter{1.5in}{testing whether this fades away}%
\FadeAfter{2.5in}{testing whether this fades away}

\FadeAfter{.5in}{testing whether this fades away}\par
\FadeAfter{1in}{testing whether this fades away}\par
\FadeAfter{1.5in}{testing whether this fades away}\par
\FadeAfter{2.5in}{testing whether this fades away}\par
\FadeAfter{7in}{This is a very long multi-line test
This is a very long test This is a very long test
This is a very long test This is a very long test}
\end{document}

enter image description here

  • But it seems to introduce an issue in the actual use case: gist.github.com/vermiculus/47ceafec31b60f07efa5 Thoughts? (Introducing \def\FadeAfter#1#2{#2} resolves the issue, so it's internal to the macro I imagine.) – Sean Allred Oct 9 '14 at 20:31
  • Also, it has to fade out completely by a certain point. This unfortunately doesn't solve the base problem of 'only one line to work with'. Is there a way to construct a horizontal box and then cut it off at a certain length, then unpack the box and apply the fading? – Sean Allred Oct 9 '14 at 20:38
  • @SeanAllred I found a problem that resulted from counter overflow, because I multiplied a numerator by 100. I got around the problem by instead multiplying the denominator by 0.01. However, a multiline fade is still character by character, as shown in my last example of the MWE. Is this not what you are hoping to get? – Steven B. Segletes Oct 9 '14 at 23:17
  • I went for the fade idea so that I might not have multiple lines, but solution is still more portable than the TikZ one (however intuitive the TikZ one may be), so I'm going to try and get this working in conjunction with the truncate package, but it seems that your solution can't handle it: gist.github.com/ed425d3319f5a3912353 – Sean Allred Oct 9 '14 at 23:34
  • @SeanAllred I'm not sure the reason for truncate... My algorithm actually truncates the input [approximately] at the dimension given by the first argument. If truncate was a necessity for some reason, could you truncate the \FadeAfter, rather than the other way around? In other words, \truncate[]{3in}{\FadeAfter{3.5in}{Hello world, you would never believe how hard it~is to get a string that show's off the breaking}} compiles just fine. – Steven B. Segletes Oct 10 '14 at 0:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.