如何在 TikZ 或 PGF 中禁用阴影(以及类似的预操作/后操作效果)?

如何在 TikZ 或 PGF 中禁用阴影(以及类似的预操作/后操作效果)?

是否有一种通用方法可以禁用 Ti 中的预操作/后操作Z 阴影等效果依赖于什么?

如果没有,是否有一种简单的方法可以让用户向现有样式添加选项,以便他们可以中和其效果,例如通过将阴影的不透明度设置为 0,如https://tex.stackexchange.com/a/354728/

首先是一些可以按我想要的方式运行的代码(我认为):

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{shadows,positioning}
\newif\ifshowplaceholders
\showplaceholdersfalse
\tikzset{%
  my node/.style={fill=gray,draw=black},
  placeholders/.is choice,
  placeholders/off/.code={%
    \showplaceholdersfalse\let\myphantom\phantom
    \pgfqkeys{/tikz}{placeholder/.style={my node,fill=none, draw=none}}%
  },
  placeholders/on/.code={%
    \showplaceholderstrue\def\myphantom##1{##1}%
    \pgfqkeys{/tikz}{placeholder/.style={my node,opacity=.25,text opacity=.5}}%
  },
  placeholders/.default=on,
  placeholders=off,  
}
\begin{document} 
\begin{tikzpicture}
  \node (n) [my node] {My Node};
  \node (p) [above=10pt of n,placeholder] {\myphantom{Placeholder}};
\end{tikzpicture} 
\end{document}

基本思想是可以创建占位符节点来帮助放置“真实”节点。在正常情况下,这些节点是不可见的,但仍可用于放置。

上方有不可见占位符的真实节点

如果需要,它们可以被呈现为可见的,以便进行调试。

  placeholders=on,

上方有可见占位符的真实节点

现在假设有人想给“真实节点”添加阴影

  my node/.style={fill=gray,drop shadow,draw=black},
%   placeholders=on,

现在占位符是不可见的,正如它应该的那样,但它的影子却不可见。

真实节点上方带有不可见占位符的阴影

理想情况下,我想禁用占位符节点的预操作和后操作,但由于不知道该怎么做,我尝试至少让用户添加中和代码,但我无法让它工作。我怀疑这与扩展有关,但我还没有找到一种既不产生错误也不产生可见性的方法。

我不会指望下面的方法会起作用,所以我对它不起作用并不感到惊讶,但我将它包括在内,因为它代表了我认为如何处理这个问题的示意图。

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{shadows,positioning}
\newif\ifshowplaceholders
\showplaceholdersfalse
\tikzset{%
  my node/.style={fill=gray,draw=black},
  placeholders/.is choice,
  placeholders/off/.code={%
    \showplaceholdersfalse\let\myphantom\phantom
    \pgfqkeys{/tikz}{placeholder/.style={my node,fill=none, draw=none}}%
  },
  placeholders/on/.code={%
    \showplaceholderstrue\def\myphantom##1{##1}%
    \pgfqkeys{/tikz}{placeholder/.style={my node,opacity=.25,text opacity=.5}}%
  },
  placeholders/.default=on,
  placeholders=off,
  placeholders/when off/.code={%
%     \edef\tempa{#1}%
    \pgfqkeys{/tikz}{%
      placeholders/off/.append code={%
        \pgfqkeys{/tikz}{placeholder/.append code={\pgfqkeys{/tikz}{#1}}}%
      },
    }%
    \ifshowplaceholders
    \else
      \pgfqkeys{/tikz}{placeholder/.append code={\pgfqkeys{/tikz}{#1}}}%
    \fi
  },
  placeholders/when on/.code={%
%     \edef\tempa{#1}%
    \pgfqkeys{/tikz}{%
      placeholders/on/.append code={%
        \pgfqkeys{/tikz}{placeholder/.append code={\pgfqkeys{/tikz}{#1}}}%
      }%
    }%
    \ifshowplaceholders
      \pgfqkeys{/tikz}{placeholder/.append code={\pgfqkeys{/tikz}{#1}}}%
    \fi
  },
  my node/.style={fill=gray,drop shadow,draw=black},
  placeholders/when off={drop shadow={fill=none}},
%   placeholders=on,
}
\begin{document} 
\begin{tikzpicture}
  \node (n) [my node] {My Node};
  \node (p) [above=10pt of n,placeholder] {\myphantom{Placeholder}};
\end{tikzpicture} 
\end{document}

我实际上是先尝试使用.append style,但也没用。作为最后的手段,我可​​以使用 expl3,但我宁愿不这样做,因为这似乎是一个相对简单的问题。

我应该提到一些我没有考虑过的选项,从上面的 MWE 来看,这些选项可能看起来是不错的方法:

  • 根本不使用my node占位符样式(我不知道样式是什么,我需要占位符相对于该样式进行标准化);
  • 消除最后一次运行的占位符(然后放置与它们相关的东西将不起作用 - 它们不像用于放置的临时网格那样被使用)。

我能做的事情:

  • 当应用于这种类型的元素时,声明包与shadows类似的东西不兼容,除非占位符被禁用(很诱人,但有点核,人们无论如何都想这样做);
  • 引入(另一个)图层(或两个),用白色填充并在其后面创建占位符off(但该包已经创建了很多图层,而且这似乎有很多基础设施只是为了禁用阴影 - 如果用户使用在不同图层上绘制的预/后操作涉及的东西,它将不起作用)。

我的默认设置是仅记录不兼容性或采取某些措施expl3,但我希望有更好的解决方案。

答案1

我想禁用占位节点的预操作和后操作

前置操作和后置操作仅存储在类似列表的宏中:

  • \tikz@preactions
  • \tikz@postactions

将这些设置为空将删除所有先前添加的操作。

当然,用户只需在您清空它们后添加另一个操作即可。但您始终可以删除这些键本身:postaction/.code=, preaction/.code=。(但这也适用于drawfill等。)

说到drawfill,我已经draw=none, fill=nonepath only禁用替换了你的全部动作:绘制、填充、阴影、淡入淡出、图案、剪辑、用作边界框、路径图片、双重……

我还介绍了phantom node钥匙这会禁用 PGF 针对相关节点发送 TeX 框的功能。形状的定义仍会考虑这些框的测量值,但不会将其放入页面上。

\pgf@sh@boxes@<shape name>是另一个包含列表的宏。在大多数情况下,这只是text代表\pgfnodeparttextbox。请参阅手动开启\pgfmultipartnode关于这个话题我再说几句。


如果你比较代码 1 返回的两个页面,你会注意到占位符节点所在的页面不是显示的要小一些。(如果您不添加到line width=1exmy node)这是因为绘制的路径将.5\pgflinewidth在图片边界框的所有边上添加一个填充。

当未绘制路径时(即path onlydraw = none),不会发生这种情况。

我只想补充overlay一点,every placeholder node从而禁用这些节点的任何边界框考虑。这似乎与其辅助用途一致,但当然会根据情况将这些占位符节点打印在图片的边界框之外。

我已经尝试了其他路径操作,以便更好地控制它添加undrawdraw undraw其中undraw不会描边路径但会根据线宽改变边界框,并且draw undraw会描边路径但忽略边界框的线宽。

不幸的是,这需要重新定义 PGF\pgfusepath宏,我怀疑您是否想尝试这个。


说到盒子……
当 TikZ 遇到路径上的节点、边、图片或绘图标记时,它们或多或少会立即构造和排版,但放在一个盒子里,要么是前景或背景因此,路径实际上提供了三层,并且无论在路径上何时遇到节点,节点都可以位于路径之上。

虽然将一个节点放到一个单独的PGF层(看[1][2] (第 5 节)[3])让一个节点消失是相当容易的。

虽然有特殊的discard,如果你真的不想看到那个节点……而不是路径的前景或背景框,我们可以使用任何框,然后不使用它(它也会在路径之后被遗忘;)。

如果不设置path only或,draw = none边界框仍将进行调整(至少没有overlay或类似,当然),但不会仅因线宽而变化。所有操作和排版仍将执行,并将创建节点。

代码 1(禁用绘图和操作)

\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{shadows, positioning}
\newif\ifshowplaceholders
\showplaceholdersfalse
\makeatletter
\tikzset{
  no actions/.code=\let\tikz@preactions\pgfutil@empty
                   \let\tikz@postactions\pgfutil@empty,
  phantom node/.code=\tikz@addoption % no recovery!
    {\expandafter\let\csname pgf@sh@boxes@\tikz@shape\endcsname\pgfutil@empty}}
\makeatother
\tikzset{
  show placeholders/.is if=showplaceholders,
  placeholder/is on/.style={
    every placeholder node, opacity=.25, text opacity=.5},
  placeholder/is off/.style={
    every placeholder node, path only, no actions, phantom node},
  placeholder/.style={placeholder/is \ifshowplaceholders on\else off\fi},
  placeholders/when off/.style={/tikz/placeholders/is off/.append style={#1}},
  placeholders/when  on/.style={/tikz/placeholders/is  on/.append style={#1}}}

\tikzset{
  my node/.style={fill=gray, draw=black},
  every placeholder node/.style=my node}
\begin{document}
\begin{tikzpicture}[show placeholders, my node/.append style=drop shadow]
  \node (n) [my node] {My Node};
  \node (p) [above=10pt of n, placeholder] {Placeholder};
\end{tikzpicture}

\begin{tikzpicture}[show placeholders=false, my node/.append style=drop shadow]
  \node (n) [my node] {My Node};
  \node (p) [above=10pt of n, placeholder] {Placeholder};
\end{tikzpicture}
\end{document}

代码 2(将节点放入一次性盒子)

\documentclass[tikz, border=10pt]{standalone}
\usetikzlibrary{shadows, positioning}
\newif\ifshowplaceholders
\showplaceholdersfalse
\makeatletter
\tikzset{
  discard node/.code=\setbox\pgfutil@tempboxa\box\pgfutil@voidb@x % empty out box
                     \def\tikz@whichbox{\pgfutil@tempboxa}}
\makeatother
\tikzset{
  show placeholders/.is if=showplaceholders,
  placeholder/is on/.style={every placeholder node, opacity=.25, text opacity=.5},
  placeholder/is off/.style={every placeholder node, discard node},
  placeholder/.style={placeholder/is \ifshowplaceholders on\else off\fi},
  placeholders/.is choice,
  placeholders/when off/.style={/tikz/placeholders/is off/.append style={#1}},
  placeholders/when  on/.style={/tikz/placeholders/is  on/.append style={#1}}}

\tikzset{
  my node/.style={fill=gray, draw=black},
  every placeholder node/.style=my node}
\begin{document}
\begin{tikzpicture}[show placeholders, my node/.append style=drop shadow]
  \node (n) [my node] {My Node};
  \node (p) [above=10pt of n, placeholder] {Placeholder};
\end{tikzpicture}

\begin{tikzpicture}[show placeholders=false, my node/.append style=drop shadow]
  \node (n) [my node] {My Node};
  \node (p) [above=10pt of n, placeholder] {Placeholder};
\end{tikzpicture}
\end{document}

相关内容