我知道,这个问题是在一年多前提出的(看这里),但给出的答案仅限于callouts
无边框。有没有办法改进给出的答案,使其具有callout
均匀填充的形状,或者shadings
可以使用透明度和线边框?就像漫画中看到的呼唤一样……
如果可以设计一种新的callout
,例如具有以下由选项定义的特征:
shape= <rectangle multipointer callout> or <ellipse multipointer callout> number of pointers= <number> pointer one= <absolute coordinate> or <relative coordinate> pointer two= <absolute coordinate> or <relative coordinate> ... pointer origin offset= <x-offset,y-offset> % not necessary but usefull other existed options of callout shapes
我认为这对我很有用。我使用多指针的一个例子callouts
是:
\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta,calc,chains,positioning,shadows,shapes.callouts}
%---------------------------------------------------------------%
\begin{document}
%%%% SA-multipointer-callout
\begin{tikzpicture}[
node distance=5mm and 44mm,
start chain = going right,
C/.style = {callout absolute pointer={#1},
rectangle callout,
callout pointer width=1.8 mm, callout pointer shorten=-1mm,
rounded corners, draw, fill=yellow!30,
semitransparent, text opacity=1,
font=\footnotesize, text=teal!40!black, align=center},
L/.style = {line width=1mm, gray,
arrows={-Stealth[inset=0pt,length=0pt 2,angle'=90]},
text=black},
N/.style 2 args = {name=n#1,
text width=#2,
draw, fill=white, minimum height=9mm, align=center, on chain, drop shadow}
]\sffamily
\node[N={1}{21mm}] {oddajnik};
\node[name=n2,circle,inner sep=2pt,
fill=white,draw,on chain] {$+$};
\node[N={3}{21mm}] {sprejemnik};
\draw[L] (n1) edge node[above,pin=above left:signal] {$y(t)$}
node[below,black,pin=below left:sporo\v{c}ilo] {$y[n]$} (n2)
(n2) edge node[above] {$r(t)=y(t)+ n(t)$}
node[below] {$r[n]=y[n]+ z[n]$}
(n3);
\draw[->] ($(n2.north)+(0,1.1)$)
node[right,align=left,black] {motnje: $n(t)$ ali $z[n]$} -- (n2);
\node[C={([xshift=-7mm] n2.west)},below = of n2]
{komunikacijski\\ kanal};
\node[C={([xshift=+7mm] n2.east)},below = of n2]
{komunikacijski\\ kanal};
\end{tikzpicture}
\end{document}
到目前为止,我堆叠了两种callout
形状,但结果却很丑陋:
附录:
经过两年半符号 1提供的答案部分满足了我的期望。然而,我仍然有一个梦想,有一天 TikZ 库shapes.callouts
将丰富multi-pointer-callout
形状...借助我的问题的答案 :),可以用于我的示例:
\node[ellipse multipointer callout, absolute pointer one=n2.wet, absolute pointer two=n2.east, callout pointer width=1.8 mm, callout pointer shorten=-1mm, % other, not specific but important options draw, fill=yellow!30, semitransparent, text opacity=1, % <-- key features font=\footnotesize, text=teal!40!black, align=center] {komunikacijski\\ kanal};
答案1
新答案
我们从构建一种在同一位置排版多个节点的简单方法开始:
\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{shapes.callouts}
\begin{document}
% The goal is to translate
% \overlaynode<red,blue>{hallo};
% into
% \node[red]{hallo};
% \node[blue]{hallo};
\makeatletter
\def\overlaynode<#1>#2;{
\gdef\stacknodecommonpart{#2}
\pgfkeys{/typeset node/.list={#1}}
% we are lazy
% pgfkeys will translate
% \pgfkeys{/typeset node/.list={red,blue}}
% into
% \pgfkeys{/typeset node=red}
% \pgfkeys{/typeset node=blue}
}
\pgfkeys{
/typeset node/.code={
\edef\pgf@marshal{\noexpand\node[#1]\stacknodecommonpart;}
\pgf@marshal
}
}
\tikz{
\overlaynode<red,{blue,xshift=1}>{{Hello}}; % notice the nested {{}}
% \overlaynode<red,{blue,xshift=1}>[]{Hello}; % workaround
\overlaynode<red,{blue,rotate=5}>at(1,0)[draw]{from};
\overlaynode<red,{blue,scale=1.1}>[circle]at(2,0)[draw]{the};
\overlaynode<red,{blue,opacity=.5}>[fill=yellow!50]at(3,0){other};
\overlaynode<{red,rectangle callout,fill},{blue,ellipse callout,draw}>at(4,0){side};
}
- 中的每个项目都
< >
将指向一个单独的节点。在上面的示例中,red
会给出一个红色节点,{blue,rotate=5}
会给出一个蓝色的旋转节点。 - 您可以设置全球的中的属性
[ ]
。在上面的例子中,[draw]
将绘制所有节点的边框。因此,您可以看到红色矩形和蓝色旋转矩形。
absolute
因此,人们可以轻松地进行多次调用:由于每个调用本身就是一个节点,因此将和relative
和组合起来不会有问题shorten
。
\tikz{
\overlaynode<
{fill=red,callout absolute pointer=(45:2)},
{fill=yellow,callout absolute pointer=(135:2),callout pointer shorten=1cm},
{fill=green,callout relative pointer=(-135:2),callout pointer width=.5cm},
{fill=blue,callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout,text=white]
at(0,0){can you}
;
}
现在我们来到了激动人心的部分。
为了描绘所有节点的轮廓,我们需要调用\overlaynode
两次:一次使用draw
,一次使用fill
。
\def\overlaynodedrawfill{\pgfutil@ifnextchar[{\overlaynodedrawfill@opt}{\overlaynodedrawfill@opt[]}}
\def\overlaynodedrawfill@opt[#1]<#2>#3;{
\begin{scope}[transparency group,draw=black,fill=white,line cap=round,line join=round,#1]
\pgfmathsetmacro\pgflinewidthdouble{2\pgflinewidth}
\overlaynode<#2>[draw=pgfstrokecolor,line width=\pgflinewidthdouble]#3;
\overlaynode<#2>[fill=pgffillcolor]#3;
\end{scope}
}
\tikz{
\overlaynodedrawfill[draw=cyan,fill=magenta,opacity=.5]<
{callout absolute pointer=(45:2)},
{callout absolute pointer=(135:2),callout pointer shorten=1cm},
{callout relative pointer=(-135:2),callout pointer width=.5cm},
{callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout]
at(0,0){hear me}
;
}
请注意,虽然有opacity=.5
,但是看起来只有一个节点!
还请注意,我们将其放在draw=cyan,fill=magenta,opacity=.5
开头和rectangle callout
结尾。
如果放在draw=cyan
最后,则所有节点都将为draw
n,结果将不是轮廓。(但是,如果您知道自己在做什么,仍然可以这样做。)
更多技巧
\tikz{
\overlaynodedrawfill<
{cloud callout,callout absolute pointer=(90:2),inner sep=-20},
{rectangle callout,callout absolute pointer=(210:2),minimum height=30},
{ellipse callout,callout absolute pointer=(-30:2)}
>
at(0,0){nice to meet you}
;
}
\tikz{
\overlaynodedrawfill<
{starburst},
{cloud,inner sep=-10}
>
at(0,0){where you been}
;
}
\usetikzlibrary{shapes.arrows}
\tikz{
\overlaynodedrawfill[arrow box,text opacity=0,minimum height=50,,minimum width=50,inner xsep=-10]<
{rotate=22.5},
{rotate=45},
{rotate=67.5},
{text opacity=1}
>
at(0,0){I can}
;
}
完整代码
\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{shapes.callouts}
\begin{document}
% The goal is to translate
% \overlaynode<red,blue>{hallo};
% into
% \node[red]{hallo};
% \node[blue]{hallo};
\makeatletter
\def\overlaynode<#1>#2;{
\gdef\stacknodecommonpart{#2}
\pgfkeys{/typeset node/.list={#1}}
% we are lazy
% pgfkeys will translate
% \pgfkeys{/typeset node/.list={red,blue}}
% into
% \pgfkeys{/typeset node=red}
% \pgfkeys{/typeset node=blue}
}
\pgfkeys{
/typeset node/.code={
\edef\pgf@marshal{\noexpand\node[#1]\stacknodecommonpart;}
\pgf@marshal
}
}
\tikz{
\overlaynode<red,{blue,xshift=1}>{{Hello}}; % notice the nested {{}}
% \overlaynode<red,{blue,xshift=1}>[]{Hello}; % workaround
\overlaynode<red,{blue,rotate=5}>at(1,0)[draw]{from};
\overlaynode<red,{blue,scale=1.1}>[circle]at(2,0)[draw]{the};
\overlaynode<red,{blue,opacity=.5}>[fill=yellow!50]at(3,0){other};
\overlaynode<{red,rectangle callout,fill},{blue,ellipse callout,draw}>at(4,0){side};
}
\tikz{
\overlaynode<
{fill=red,callout absolute pointer=(45:2)},
{fill=yellow,callout absolute pointer=(135:2),callout pointer shorten=1cm},
{fill=green,callout relative pointer=(-135:2),callout pointer width=.5cm},
{fill=blue,callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout,text=white]
at(0,0){can you}
;
}
\def\overlaynodedrawfill{\pgfutil@ifnextchar[{\overlaynodedrawfill@opt}{\overlaynodedrawfill@opt[]}}
\def\overlaynodedrawfill@opt[#1]<#2>#3;{
\begin{scope}[transparency group,draw=black,fill=white,line cap=round,line join=round,#1]
\pgfmathsetmacro\pgflinewidthdouble{2\pgflinewidth}
\overlaynode<#2>[draw=pgfstrokecolor,line width=\pgflinewidthdouble]#3;
\overlaynode<#2>[fill=pgffillcolor]#3;
\end{scope}
}
\tikz{
\overlaynodedrawfill[draw=magenta,fill=cyan,opacity=.5]<
{callout absolute pointer=(45:2)},
{callout absolute pointer=(135:2),callout pointer shorten=1cm},
{callout relative pointer=(-135:2),callout pointer width=.5cm},
{callout relative pointer=(-45:2),callout pointer shorten=1cm,callout pointer width=.5cm}
>
[rectangle callout]
at(0,0){hear me}
;
}
\tikz{
\overlaynodedrawfill<
{cloud callout,callout absolute pointer=(90:2),inner sep=-20},
{rectangle callout,callout absolute pointer=(210:2),minimum height=30},
{ellipse callout,callout absolute pointer=(-30:2)}
>
at(0,0){nice to meet you}
;
}
\tikz{
\overlaynodedrawfill<
{starburst},
{cloud,inner sep=-10}
>
at(0,0){where you been}
;
}
\usetikzlibrary{shapes.arrows}
\tikz{
\overlaynodedrawfill[arrow box,text opacity=0,minimum height=50,minimum width=50,inner xsep=-10]<
{rotate=22.5},
{rotate=45},
{rotate=67.5},
{text opacity=1}
>
at(0,0){I can}
;
}
\end{document}
旧答案
这个想法是[draw,black,line width=.8pt,postaction={fill,white}]
。
\documentclass[border=9,tikz]{standalone}
\usetikzlibrary{automata,shapes,arrows}
\makeatletter
\tikzset{
expand me/.style={#1},
multiple absolute pointers/.style args={#1[#2]#3#4}{
insert path={
\foreach \qrr@tikz@calloutabsolutepointer in {#3} {
\pgfextra
\expandafter\pgfutil@ifnextchar\expandafter[%
\expandafter\qrr@tikz@parse@calloutabsolutepointer\expandafter{%
\expandafter\qrr@tikz@parse@calloutabsolutepointer\expandafter[\expandafter]\expandafter}\qrr@tikz@calloutabsolutepointer\@qrr@tikz@parse@calloutabsolutepointer
\endpgfextra
node[#2, shape/.expanded=\tikz@shape\space callout, expand me/.expanded=\qrr@tikz@calloutabsolutepointer@options, callout absolute pointer={(\qrr@tikz@calloutabsolutepointer@)}] {#4}
}
\pgfextra
\def\pgf@tempa{#1}
\pgfutil@in@*{#1}
\ifpgfutil@in@\else
\pgfkeysalso{insert path={node[#2] {#4}}}
\fi
\endpgfextra}}}
\def\qrr@tikz@parse@calloutabsolutepointer[#1]#2\@qrr@tikz@parse@calloutabsolutepointer{%
\gdef\qrr@tikz@calloutabsolutepointer@options{#1}%
\gdef\qrr@tikz@calloutabsolutepointer@{#2}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[node distance=2cm, auto]
\node[state,initial] (s0) {$s_0$};
\node[state] (s1) [right of=s0] {$s_1$};
\node[state,accepting] (s2) [right of=s1] {$s_2$};
\path[->]
(s0) edge node {a} (s1)
(s1) edge node {c} (s2)
edge [loop above] node {b} ();
\path[multiple absolute pointers={
[fill=green!20, text width=2.1cm, below of=s0]
{
{[draw,line width=.8pt]s1.south},%
{[draw,line width=.8pt]s2.south},%
{[draw,line width=.8pt]s0.south},%
[fill=magenta]s1.south,%
[fill=yellow]s2.south,%
[fill=cyan]s0.south%
}
{Each circle is a \emph{state} of the automaton}
}];
\end{tikzpicture}
\end{document}