假设我定义一种添加一些标记的样式,例如如下:
\begin{tikzpicture}[
mymarks/.style = {
postaction = {
decorate,
decoration = {markings, mark = at position 0.5 with {\arrow[red]{>};}},
},
},
]
\draw[mymarks] (0, 0) -- (1, 0);
\end{tikzpicture}
如何参数化这种样式?即如何使颜色“红色”成为可自定义的参数?当然,一种简单直接的方法是使用键值并写入\arrow[#1]
和mymarks=red
。但是,如果键值已经用于其他用途并且颜色参数无论如何都应该是可选的,该怎么办?
一个想法是定义mymarks/color/.store in = \param
并编写\arrow[\param]
和\draw[mymarks/color=red, mymarks]
,但随后我需要自己为每个这样的参数创建一个全局宏。
另一个想法是定义一些内容mymarks/color/.initial = red
并将其用作\arrow[\pgfkeysvalueof{/tikz/mymarks/color}]
。但是,是否有某种方法可以像定义后置操作时那样创建本地快捷方式,这样如果多次使用该值,\path let
我就不必一直写入?\pgfkeysvalueof{/tikz/mymarks/color}
有没有更好的方法来实现这种参数化?
答案1
当然,您可以定义一个宏,它只是 的包装器\pgfkeysvalueof
,最短的“宏”是~
(a)活动字符,b)通常用于不间断空格)。在箭头内标记不间断空格是不需要的。因此,您可以说:
\begin{tikzpicture}[
/pgf/decoration/tilde shortcut/.code =
\def~##1{\pgfkeysvalueof{/tikz/mymarks/##1}},
mymarks/.default = ,
mymarks/.style = {
postaction = {
decorate,
decoration = {
markings, tilde shortcut,
mark = at position .5 with {\arrow[~{color}]{>}},
}
}
},
mymarks/color/.initial=red,
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[mymarks/color=green, mymarks] (0, 0) -- (1, .2) node[right]{x~y};
\end{tikzpicture}
如您所见,~
当我们回到时,它具有其正常定义node
。
但由于你只定义mymarks
一次样式,我认为你不需要使用快捷方式。(尽管,也许
\newcommand*\mymarksvo[1]{\pgfkeysvalueof{/tikz/mymarks/#1}}
够简短且独特吗?
我甚至想更进一步。在这里,我们定义一个mymarks
键,该键可选地接受键/值列表并将它们应用于/tikz/mymarks
名称空间:
\begin{tikzpicture}[
mymarks/.default = ,
mymarks/.style = {
postaction = {
decorate,
decoration = {
markings,
/utils/exec=\pgfqkeys{/tikz/mymarks}{#1},
my mark/.style = {
mark = at position ########1 with {%
\arrow[style/.expand twice/.expand once =
\pgfkeysvalueof{/tikz/mymarks/style}
]{>}
}
},
my mark/.list/.expand twice/.expand once=
\pgfkeysvalueof{/tikz/mymarks/pos}
},
},
},
mymarks/pos/.initial=.5,
mymarks/style/.initial=red,
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[
mymarks={
pos={.2, .4, ..., .8},
style={scale=2, rotate=-90}
}
] (0, 0) -- (1, .2);
\end{tikzpicture}
这样你就不需要(但仍然可以)做mymarks/pos = …
或mymarks/style = …
除了它本身之外mymarks
,你只需说
mymarks = {pos = …, style = …}
(/tikz/style
中使用的键\arrow
仅定义为style/.style = {#1}
,即它与使用完全相同,#1
但是我们现在可以在#1
使用它之前对其进行一些操作,否则我们无法做到这一点。在这种情况下:扩展。)
我们自己的/tikz/mymarks/style
密钥(不是样式但值键)的使用有些不寻常。(我们可以使用style/.append = …
将键附加到此值,因此我们几乎可以以与使用实际样式相同的方式使用它。)
适当的风格可能更好。我们定义一个/tikz/mymarks/every arrow
风格,现在需要覆盖它
mymarks = {every arrow/.style = …}
或者如果我们不想丢失以前的设置,请附加到:
mymarks = {every arrow/.append style = …}
PGF/TikZ 及其基础上构建的包/库通常还定义一个arrows
附加到的键every arrow
:
\begin{tikzpicture}[
/pgf/decoration/mymarks/.style = {
mark = at position #1 with {\arrow[mymarks/every arrow]{>}}},
mymarks/.default = ,
mymarks/.style = {
postaction = {
decorate,
decoration = {
markings,
/utils/exec=\pgfqkeys{/tikz/mymarks}{#1},
mymarks/.list/.expand twice/.expand once=
\pgfkeysvalueof{/tikz/mymarks/pos}
},
},
},
mymarks/pos/.initial=.5,
mymarks/every arrow/.style=red,
mymarks/arrows/.style={every arrow/.append style={#1}}
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[
mymarks={
pos={.2, .4, ..., .8},
arrows={scale=2, rotate=-90}% still red
}
] (0, 0) -- (1, .2);
\end{tikzpicture}
现在.expand twice/.expand once
有点笨重,我们可以定义自己的.expand thrice
处理程序...或者使用给定键的值的处理程序...或者甚至更短的处理程序:
\makeatletter
\pgfqkeys{/handlers}{
.expand thrice/.code=%
\pgfkeysalso{\pgfkeyscurrentpath/.expand twice/.expand once={#1}},
.value/.code=%
\pgfkeysgetvalue{#1}\pgfkeys@temp
\expandafter\pgfkeys@exp@call\expandafter{\pgfkeys@temp},%
.tikz value/.code=\pgfkeysalso{\pgfkeyscurrentpath/.value=/tikz/#1},
.../.code=\pgfkeysalso{\pgfkeyscurrentpath/.value=/tikz/mymarks/#1},
}
\makeatother
现在你可以做以下任何一件事:
my mark/.list/.expand thrice = \pgfkeysvalueof{/tikz/mymarks/pos}
my mark/.list/.value = /tikz/mymarks/pos
my mark/.list/.tikz value = mymarks/pos
my mark/.list/... = pos
不过,类似于~
我只定义...
本地。
但我们可以进一步推动这一进程……
代码
\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.markings,arrows.meta}
\makeatletter
\pgfqkeys{/handlers}{
.value/.code=%
\pgfkeysgetvalue{#1}\pgfkeys@temp
\expandafter\pgfkeys@exp@call\expandafter{\pgfkeys@temp}%
% this is equivalent to:
% \pgfkeysalso{\pgfkeyscurrentpath/.expand once=\pgfkeys@temp}
}
\makeatother
\begin{document}
\begin{tikzpicture}[
/pgf/decoration/my mark/.style = {
/utils/exec=\edef\mymarkscounter{\the\numexpr\mymarkscounter+1\relax},
mark/.expanded = at position #1 with {\noexpand\arrow[
mymarks/every arrow,
mymarks/arrow \mymarkscounter/.try
]{>}
}% expanded is needed since "mark" only collects
},
mymarks/.default = ,
mymarks/.style = {
postaction = {
decorate,
decoration = {
markings,
/utils/exec=\pgfqkeys{/tikz/mymarks}{#1}\def\mymarkscounter{0},
my mark/.list/.value=/tikz/mymarks/pos
}
}
},
mymarks/pos/.initial=.5, mymarks/every arrow/.style=red,
% to be on the safe site we use the full path so that we can do
% \tikzset{mymarks/arrows=…}
% where we don't want to reder to /tikz/every arrow
mymarks/arrows/.style={/tikz/mymarks/every arrow/.append style={#1}}
]
\draw[mymarks] (0, .3) -- (1, .5);
\draw[
mymarks={
pos={.2, .4, ..., .8},
arrows = {scale = 2, rotate = -90},
arrow 3/.style = blue,
arrow 2/.style = {green, > = {Stealth[round]}}
}
] (0, 0) -- (1, .2);
\end{tikzpicture}
\end{document}