新答案

新答案

我知道,这个问题是在一年多前提出的(看这里),但给出的答案仅限于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最后,则所有节点都将为drawn,结果将不是轮廓。(但是,如果您知道自己在做什么,仍然可以这样做。)

更多技巧

\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}

相关内容