9

My question is essentially: is this possible?

In my document, I have some example tasks. Those are highlighted by having a slightly grey background. Inside those examples, there are some complicated TikZ drawings. (This question of course applies to every case where a TikZ drawing is positioned over another object.)

Let's suppose the following MWE:

\documentclass{article}
\usepackage{mdframed}   % for framing
\usepackage{tikz}
\begin{document}

\begin{mdframed}[backgroundcolor=black!10] 
\centering
\begin{tikzpicture}
\foreach \x in {0,...,5}
\draw (0,0) to[bend right] node [fill=white, pos=0.8] {\x} (60*\x+30:3) ;
\draw[fill=white] (20:1) -- (140:1) -- (260:1) -- cycle;
\draw (0,0) node[align=center] {Center};
\end{tikzpicture}
\end{mdframed}

\end{document}

This produces the following output:

output

This is obviously bad. I'd like to have this output:

good result

Possible solutions and their threads:

  • I know I could possibly find some complicated way for calculating the six arcs so that they start directly at the border of the center triangle, and possibly also some way to stop the arc before the node and restart it afterwards. But that is not a solution I'd like. (The option of re-drawing the image is basically the answer to this question)
  • Another way would be filling the nodes not white, but with the background color: fill=black!10. This would be a workaround in my case, but for others it won't work, just suppose you have a gradient below the image or even worse, some text / other drawing.
  • Yet another option would be to use [transparency group=knockout] (as this question supposes), but this doesn't seem to work in my case (probably because of the mdframe) and is highly viewer dependent, most browers don't support this.

So the preferred solution would be something along a command that does the following:

Fill an area, and then set the entire area to transparent.

I thought about clipping everything but the object in question and then draw the object, but that would mean I have to know where the image will end or results in having a pretty large bounding box.

Edit: Re-worded part of the question.

Edit 2: For the sake of a MWE that is immune to the workaround:

\documentclass[a5paper]{article}
\usepackage{background}
\backgroundsetup{
scale=1,
angle=0,
opacity=1,
contents={\begin{tikzpicture}[remember picture,overlay]
 \path [left color = black, right color = white] (current page.south west)rectangle (current page.north east);   % Adjust the position of the logo.
\end{tikzpicture}}}
\begin{document}

\centering
\begin{tikzpicture}
\foreach \x in {0,...,5}
\draw (0,0) to[bend right] node [pos=0.8,fill=white] {\x} (60*\x+30:3) ;
\draw[fill=white] (20:1) -- (140:1) -- (260:1) -- cycle;
\draw (0,0) node[align=center] {Center};
\end{tikzpicture}
\end{document}

produces the following output:mwe 2

  • Welcome to TeX.SX! Sorry, for being slow, but what are you actually trying to do? You say that your drawing "is obviously not bad" and then talk about various possible solutions but as far as I can see you do not say what the problem is!? Could it be that removing fill=white solves your problem? – Andrew Sep 18 '17 at 17:24
  • *typo. edited it – jaytar Sep 18 '17 at 17:25
  • Also removing fill=white does not resolve the issue, because then the lines would continue in the center triangle and below the nodes. – jaytar Sep 18 '17 at 17:28
  • you need to use decorations if you don't want to place dummy fills. – percusse Sep 18 '17 at 19:13
7

You could do the whole picture as a fading 🙃

\documentclass[border=5]{standalone}
\usepackage{tikz}
\usetikzlibrary{fadings}
\begin{tikzfadingfrompicture}[name=figure]
\foreach \x in {0,...,5}
  \draw [pgftransparent!0] (0,0) to [bend right] 
    node [fill=pgftransparent, pos=0.8, text=pgftransparent!0] {\x} (60*\x+30:3);
\draw [draw=pgftransparent!0, fill=pgftransparent] 
  (20:1) -- (140:1) -- (260:1) -- cycle;
\draw [draw=pgftransparent!0]
  (0,0) node[align=center, text=pgftransparent!0] {Center};
\end{tikzfadingfrompicture}
\begin{document}
\tikz\path[bottom color=red!20, top color=blue!20, middle color=green!20,
  postaction={fill=black, path fading=figure, fit fading=false}] 
  (-3.5, -3.5) rectangle (3.5,3.5);
\end{document}

enter image description here

Placing the image over text is simple enough, just remember to set the fading transform as well:

\documentclass{article}
\usepackage{tikz,lipsum}
\usetikzlibrary{fadings}
\begin{tikzfadingfrompicture}[name=figure]
\foreach \x in {0,...,5}
  \draw [pgftransparent!0] (0,0) to [bend right] 
    node [fill=pgftransparent, pos=0.8, text=pgftransparent!0] {\x} (60*\x+30:3);
\draw [draw=pgftransparent!0, fill=pgftransparent] 
  (20:1) -- (140:1) -- (260:1) -- cycle;
\draw [draw=pgftransparent!0]
  (0,0) node[align=center, text=pgftransparent!0] {Center};
\end{tikzfadingfrompicture}
\begin{document}
\lipsum[1]\lipsum[2]\lipsum[3]\lipsum[4]
\tikz[remember picture, overlay, 
  shift=(current page.center), fading transform={shift=(current page.center)}]
\path[fill=red, path fading=figure, fit fading=false] 
  (-3.5, -3.5) rectangle (3.5,3.5);
\end{document}

Part of the output (after two compliations):

enter image description here

It is also possible to automatically get the bounding box of the fading. For this, a trick is used which means the picture that makes up the fading is specified inline.

\documentclass{article}
\usepackage{tikz,lipsum}
\usetikzlibrary{fadings}
\newbox\fadingbox
\tikzset{
  shift fading/.style={shift=#1, fading transform={shift=#1}},
  use as fading/.style={%
    /utils/exec={%
      \pgfinterruptpicture
      \global\setbox\fadingbox=\hbox{\pgfpicture#1\endpgfpicture}%
      \begin{tikzfadingfrompicture}[name=@fading]
        \pgftext{\copy\fadingbox}
      \end{tikzfadingfrompicture}%
      \endpgfinterruptpicture},
    path fading=@fading, fit fading=false,
    insert path={%
        (-\wd\fadingbox/2, -\ht\fadingbox/2-\dp\fadingbox/2)
        rectangle ++(\wd\fadingbox, \ht\fadingbox+\dp\fadingbox)
}}}
\begin{document}
\lipsum[1]\lipsum[2]\lipsum[3]\lipsum[4]
\tikz[remember picture, overlay, shift fading=(current page.center)]
\path [fill=blue, use as fading={
  \foreach \x in {0,...,5}
    \draw [transparent!0] (0,0) to [bend right] 
      node [fill=transparent, pos=0.8, text=transparent!0] {\x} (60*\x+30:3);
  \draw [draw=transparent!0, fill=transparent] 
    (20:1) -- (140:1) -- (260:1) -- cycle;
  \draw [draw=transparent!0]
    (0,0) node[align=center, text=transparent!0] {Center};
  }];
\end{document}

enter image description here

  • I hoped there was an option like fill=pgftransparent!0. Is there an option that this works for underlying text too (like in @JLDiaz ' example)? For my document I could work with this, but I'd like to see if this can be further generalized. – jaytar Sep 19 '17 at 9:10
  • @jaytar see updated answer – Mark Wibrow Sep 19 '17 at 10:00
  • +1 -- Really like this since it works for all kinds of images. – jaytar Sep 19 '17 at 10:05
  • Is there a possibility to store the bounding box of the image and use it later on so you dont have to guess the values (-3.5, -3.5) rectangle (3.5,3.5);? – jaytar Sep 19 '17 at 10:11
  • 1
    @jaytar see the updated answer – Mark Wibrow Sep 19 '17 at 10:38
8

Disclaimer:

Horrible, horrible hack. Please, forgive me, consider it only as a proof of concept...

The output:

Result

The trick:

  1. Draw (without actually drawing it) the star, including the numbered nodes which are actually drawn and named, to later get their border coordinates.
  2. Clip to a shape with holes. The contour of the shape is the current bounding box (set by step 1). The holes are the rectangular borders of the numbered nodes, and the triangular path. Those are defined in counter-clockwise direction, so that they are "substracted" from the shape.
  3. Draw again the star shaped edges. As a result of step 2 our current canvas has "holes" in which the drawn lines disappear.
  4. Reset the clipping area and draw the inner triangle.

To reset the clipping area in 4, it is enough to perform steps 2 and 3 inside a scope.

 The code:

\documentclass[a5paper]{article}
\usepackage{tikz}
\usepackage{background}
\backgroundsetup{
scale=1,
angle=0,
opacity=1,
contents={\begin{tikzpicture}[remember picture,overlay]
 \path [left color = black, right color = white] (current page.south west)rectangle (current page.north east);   % Adjust the position of the logo.
\end{tikzpicture}}}
\begin{document}

\centering
\begin{tikzpicture}
    % Draw and name the nodes
    \foreach \x in {0,...,5}
      \path (0,0) to[bend right] node [pos=0.8,fill=none,name=n\x] {\x} (60*\x+30:3) ;

    % Scope in which the curved lines are drawn
    \begin{scope}
        % Define clipping geometry with holes
        \clip (current bounding box.south west) rectangle (current bounding box.north east)
              foreach \x in {0,...,5}  { (n\x.south east) rectangle (n\x.north west) }
              (20:1) -- (140:1) -- (260:1) -- (20:1);
        % Draw curves
        \foreach \x in {0,...,5}
          \draw (0,0) to[bend right] (60*\x+30:3) ;
    \end{scope}
    % Reset clipping (when scope is exited)
    % Draw triangle
    \draw[fill=none] (20:1) -- (140:1) -- (260:1) -- cycle;
    \draw (0,0) node[align=center] {Center};
\end{tikzpicture}
\end{document}

Update

For extra fun and ugliness:

% Same preamble...
\usepackage{lipsum}
\begin{document}
\lipsum[6]\lipsum[6]\lipsum[6]
\begin{tikzpicture}[remember picture, overlay, shift=(current page.center), blue, thick]
  % Same drawing code...
\end{tikzpicture}
\end{document}

Gives:

Result

  • Cool to see that this idea actually works. Do you have any idea if you can transform this to a more generic example? – jaytar Sep 19 '17 at 8:50
3

Just fill using the same background color as in your mdframed environment. That is, fill=black!10. This produces:

enter image description here

Here is the full code:

\documentclass{article}
\usepackage{mdframed}   % for framing
\usepackage{tikz}
\begin{document}

\begin{mdframed}[backgroundcolor=black!10]
\centering
\begin{tikzpicture}
\foreach \x in {0,...,5}
\draw (0,0) to[bend right] node [pos=0.8,fill=black!10] {\x} (60*\x+30:3) ;
\draw[fill=black!10] (20:1) -- (140:1) -- (260:1) -- cycle;
\draw (0,0) node[align=center] {Center};
\end{tikzpicture}
\end{mdframed}

\end{document}
  • I already thought about that workaround. It works in my case, but not in others, like having a gradient / text / whatever below the image. – jaytar Sep 18 '17 at 17:33
  • 1
    @jaytar Then post a MWE that exhibits your actual problem. I have solved the question you posed. It's really hard to read your mind.... – Andrew Sep 18 '17 at 17:34
  • I added another MWE. – jaytar Sep 18 '17 at 18:20
  • @jaytar Maybe accept the helpful answer that is provided and ask a new question (or at least upvote...). If you provide a "moving target" then that's bad in my opinion. – Dr. Manuel Kuehner Sep 18 '17 at 18:45
  • 4
    I upvoted it, but I don't think my question is a moving target. I already stated from the beginning on that I'd like to have a different solution than just knowing the background color. – jaytar Sep 18 '17 at 18:47

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.