我正在尝试制作漫画格式的海报。除了tikZ
使用 beamerposter 效果不佳之外,我的想法是制作一种带有相互连接的气球的漫画。
请注意,我不想要通常可以轻松重现的单线连接节点tikZ
。这里的连接是双线。从根本上讲,我可以绘制这样的形状,但我真的无法在单个方块中书写。有什么帮助或提示吗?
我使用的代码非常简单
\documentclass[final,hyperref={pdfpagelabels=false}]{beamer}
\usepackage[english]{babel}
\usepackage[orientation=portrait,size=a0,scale=1.4,debug]{beamerposter}
\usepackage{tikz}
\newlength{\columnheight}
\setlength{\columnheight}{105cm}
\begin{document}
\begin{tikzpicture}
\draw[line width=0.5ex,rounded corners = 1ex, fill=white, font={peppe}] (0,0) --(0,14)--(20,14)--(20,6.9)--(30,6.9)--(30,14)--(50,14)--(50,0)--(30,0)--(30,6.3)--(20,6.3)--(20,0)--(0,0);
\end{tikzpicture}
\end{document}
答案1
实现此目的的一些技巧和想法:
- 节点的形状是“超椭圆”,而不是矩形,看起来更像“漫画”(见问题如何在 tikz 中制作超椭圆节点形状?)
- 气球之间的连接不是双线,而是非常粗的黑线,顶部有一条非常粗(但较细)的白线。如果背景也是白色,这种方法就很管用。
- 最后的标注也很棘手。一个辅助矩形小白色节点用于“擦除”最后一个气球的底部,并用作命名坐标来绘制曲线标注。
代码:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\newcommand*{\superellipse}[3][draw]{% #1 = styles
% #2 = node
% #3 = superness
\coordinate (ne) at ($(#2.center)!#3!(#2.north east)$);
\coordinate (nw) at ($(#2.center)!#3!(#2.north west)$);
\coordinate (sw) at ($(#2.center)!#3!(#2.south west)$);
\coordinate (se) at ($(#2.center)!#3!(#2.south east)$);
\pgfmathparse{-9.6*#3*#3 + 14.4*#3 - 4.8} % <--------- Magic numbers!
\xdef\tension{\pgfmathresult}
\path[#1]
plot[smooth cycle, tension=\tension] coordinates{
(#2.east) (ne) (#2.north) (nw) (#2.west) (sw) (#2.south) (se)};
% \node {\tension};
}
\tikzset{
connection/.style = {line width=2mm, white, shorten >=-3pt, shorten <=-3pt,
preaction={draw, black, line width=3mm, shorten >=0pt, shorten <=0pt},
}
}
\begin{document}
\begin{tikzpicture}
\node[text width=7em, inner sep=1.5em]
(balloon1) {Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor};
\node[text width=12em, inner sep=1.5em, right=of balloon1.north east]
(balloon2) {incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,};
\node[text width=11em, inner sep=1.5em, below=of balloon2]
(balloon3) {quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat};
\foreach \n in {1,2,3}
\superellipse[draw, very thick]{balloon\n}{0.85};
\draw[connection] ($(balloon1.north east)+(-2ex,-2ex)$) to [out=30, in=180] (balloon2.west);
\draw[connection] (balloon2.south) -- (balloon3.north);
\node[fill=white, minimum width=3mm, minimum height=1mm, inner sep=0] at (balloon3.south) (callout) {};
\draw[very thick] (callout.west) to[bend left] +(-5mm,-1cm) to[bend right] (callout.east);
\end{tikzpicture}
\end{document}
更新。
一些改进:
- 我现在不再
\superellipse
使用宏,而是使用Jake 的回答针对这个问题如何在 tikz 中制作超椭圆节点形状?。这样做的好处是可以非常精确地计算气球形状中的锚点,从而简化后续的连接。 - 我没有将 Jake 的所有代码(太长了!)都放在主文件中,而是将其分离到一个
tikz-superellipse.sty
文件中(代码如下)。这定义了一个名为 的新节点形状superellipse
。 - 创建了一种
balloon
样式,它接受气球的宽度作为参数。 - 文本默认居中
- 使用了漂亮的漫画字体(下载自bancomicsans 页面,即“Mighty Zeo”,大写版本)。需要
xelatex
使用此字体进行编译。
这是新代码:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{fontspec}
\usepackage{tikz-superellipse}
\setmainfont{MIGHZC__.TTF}
\usetikzlibrary{calc,positioning}
\tikzset{
connection/.style = {line width=2mm, white, shorten >=-6pt, shorten <=-6pt,
preaction={draw, black, line width=3mm, shorten >=-3pt, shorten <=-3pt}
},
balloon/.style = {text width=#1, inner sep=.5em, align=center, superellipse,
superellipse parameter=3.5, very thick},
balloon/.default = {11em}
}
\begin{document}
\begin{tikzpicture}
\node[balloon=7em]
(balloon1) {Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor};
\node[balloon, right=of balloon1.north east]
(balloon2) {incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,};
\node[balloon=12em, below=of balloon2]
(balloon3) {quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat};
\draw[connection] (balloon1.north east) to [out=20, in=180] (balloon2.west);
\draw[connection] (balloon2.south) -- (balloon3.north);
\node[fill=white, minimum width=3mm, minimum height=1mm, inner sep=0] at (balloon3.south) (callout) {};
\draw[very thick] (callout.north west) to[bend left] +(-5mm,-1cm) to[bend right] (callout.north east);
\end{tikzpicture}
\end{document}
结果如下:
这是tikz-superellipse.sty
文件:
\let\pgfmath@function@exp\relax % undefine old exp function
\pgfmathdeclarefunction{exp}{1}{%
\begingroup
\pgfmath@xc=#1pt\relax
\pgfmath@yc=#1pt\relax
\ifdim\pgfmath@xc<-9pt
\pgfmath@x=1sp\relax
\else
\ifdim\pgfmath@xc<0pt
\pgfmath@xc=-\pgfmath@xc
\fi
\pgfmath@x=1pt\relax
\pgfmath@xa=1pt\relax
\pgfmath@xb=\pgfmath@x
\pgfmathloop%
\divide\pgfmath@xa by\pgfmathcounter
\pgfmath@xa=\pgfmath@tonumber\pgfmath@xc\pgfmath@xa%
\advance\pgfmath@x by\pgfmath@xa
\ifdim\pgfmath@x=\pgfmath@xb
\else
\pgfmath@xb=\pgfmath@x
\repeatpgfmathloop%
\ifdim\pgfmath@yc<0pt
\pgfmathreciprocal@{\pgfmath@tonumber\pgfmath@x}%
\pgfmath@x=\pgfmathresult pt\relax
\fi
\fi
\pgfmath@returnone\pgfmath@x%
\endgroup
}
\let\pgfmath@function@pow\relax % undefine old exp function
\pgfmathdeclarefunction{pow}{2}{%
\begingroup%
\pgfmath@xa=#1pt%
\pgfmath@xb=#2pt%
\ifdim\pgfmath@xa=0pt
\pgfmath@x=0pt\relax
\else
\afterassignment\pgfmath@x%
\expandafter\c@pgfmath@counta\the\pgfmath@xb\relax%
\ifnum\c@pgfmath@counta<0\relax%
\c@pgfmath@counta=-\c@pgfmath@counta%
\pgfmathreciprocal@{#1}%
\pgfmath@xa=\pgfmathresult pt\relax%
\fi
\ifdim\pgfmath@x=0pt\relax%
\pgfmath@x=1pt\relax%
\pgfmathloop%
\ifnum\c@pgfmath@counta>0\relax%
\ifodd\c@pgfmath@counta%
\pgfmath@x=\pgfmath@tonumber{\pgfmath@x}\pgfmath@xa%
\fi
\ifnum\c@pgfmath@counta>1\relax%
\pgfmath@xa=\pgfmath@tonumber{\pgfmath@xa}\pgfmath@xa%
\fi%
\divide\c@pgfmath@counta by2\relax%
\repeatpgfmathloop%
\else%
\pgfmathln@{#1}%
\pgfmath@x=\pgfmathresult pt\relax%
\pgfmath@x=\pgfmath@tonumber{\pgfmath@xb}\pgfmath@x%
\pgfmathexp@{\pgfmath@tonumber{\pgfmath@x}}%
\pgfmath@x=\pgfmathresult pt\relax%
\fi%
\fi
\pgfmath@returnone\pgf@x%
\endgroup%
}
\pgfkeys{
/pgf/superellipse parameter/.store in=\pgf@superellipse@param,
/pgf/superellipse parameter/.default=2,
/pgf/superellipse parameter
}
\newcommand{\pointonsuperellipse}[3]{ % cornerpoint, parameter, directionpoint
\pgf@process{#1}
\edef\size@x{\the\pgf@x}%
\edef\size@y{\the\pgf@y}%
\pgfintersectionofpaths
{
\pgfpathmoveto{\centerpoint}
\pgfpathlineto{
\pgfpointborderrectangle{#3}{#1}
}
\pgfpathclose
}
{
\pgfplothandlercurveto
\pgfplotfunction{\x}{-180,-170,...,170}{
\pgfpoint{
abs(1 * cos(\x))^(2/#2)*( (cos(\x)>0)*2-1 ) * \size@x
}{
abs(1 * sin(\x))^(2/#2)*( (sin(\x)>0)*2-1 ) * \size@y
}
}
\pgfpathclose
}
\pgfpointintersectionsolution{1}
}
\makeatletter
\pgfdeclareshape{superellipse}
%
% Draws a circle around the text
%
{
\savedmacro\superellipseparameter{\edef\superellipseparameter{\pgf@superellipse@param}}
\savedanchor\centerpoint{%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by-.5\dp\pgfnodeparttextbox%
}
\savedanchor\radius{%
%
% Caculate ``height radius''
%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by.5\dp\pgfnodeparttextbox%
\pgfmathsetlength\pgf@yb{\pgfkeysvalueof{/pgf/inner ysep}}%
\advance\pgf@y by\pgf@yb%
%
% Caculate ``width radius''
%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgfmathsetlength\pgf@xb{\pgfkeysvalueof{/pgf/inner xsep}}%
\advance\pgf@x by\pgf@xb%
%
% Adjust
%
\pgf@x=1.4142136\pgf@x%
\pgf@y=1.4142136\pgf@y%
%
% Adjust hieght, if necessary
%
\pgfmathsetlength\pgf@yc{\pgfkeysvalueof{/pgf/minimum height}}%
\ifdim\pgf@y<.5\pgf@yc%
\pgf@y=.5\pgf@yc%
\fi%
%
% Adjust width, if necessary
%
\pgfmathsetlength\pgf@xc{\pgfkeysvalueof{/pgf/minimum width}}%
\ifdim\pgf@x<.5\pgf@xc%
\pgf@x=.5\pgf@xc%
\fi%
%
% Add outer sep
%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\advance\pgf@x by\pgf@xb%
\advance\pgf@y by\pgf@yb%
}
\savedmacro\test{\def\test{2}}
%
% Anchors
%
\anchor{center}{\centerpoint}
\anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}}
\anchor{base}{\centerpoint\pgf@y=0pt}
\anchor{north}
{
\pgf@process{\radius}
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@y by\pgf@ya
}
\anchor{south}
{
\pgf@process{\radius}
\pgf@ya=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@y by-\pgf@ya
}
\anchor{west}
{
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by-\pgf@xa
}
\anchor{mid west}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by-\pgf@xa%
\pgfmathsetlength\pgf@y{.5ex}
}
\anchor{base west}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by-\pgf@xa%
\pgf@y=0pt
}
\anchor{north west}
{
\pgf@process{\radius}
\def\angle{135}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgfpoint{
abs(cos(\angle))^(2/\superellipseparameter)*( (cos(\angle)>0)*2-1 ) * \pgf@xa
}{
abs(sin(\angle))^(2/\superellipseparameter)*( (sin(\angle)>0)*2-1 ) * \pgf@ya
}}
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by \pgf@xb
\advance\pgf@y by \pgf@yb
}
\anchor{south west}
{
\pgf@process{\radius}
\def\angle{-135}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgfpoint{
abs(cos(\angle))^(2/\superellipseparameter)*( (cos(\angle)>0)*2-1 ) * \pgf@xa
}{
abs(sin(\angle))^(2/\superellipseparameter)*( (sin(\angle)>0)*2-1 ) * \pgf@ya
}}
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by \pgf@xb
\advance\pgf@y by \pgf@yb
}
\anchor{east}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by\pgf@xa
}
\anchor{mid east}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by\pgf@xa%
\pgfmathsetlength\pgf@y{.5ex}
}
\anchor{base east}
{%
\pgf@process{\radius}
\pgf@xa=\pgf@x%
\pgf@process{\centerpoint}
\advance\pgf@x by\pgf@xa%
\pgf@y=0pt
}
\anchor{north east}
{
\pgf@process{\radius}
\def\angle{45}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgfpoint{
abs(cos(\angle))^(2/\superellipseparameter)*( (cos(\angle)>0)*2-1 ) * \pgf@xa
}{
abs(sin(\angle))^(2/\superellipseparameter)*( (sin(\angle)>0)*2-1 ) * \pgf@ya
}}
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by \pgf@xb
\advance\pgf@y by \pgf@yb
}
\anchor{south east}
{
\pgf@process{\radius}
\def\angle{-45}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pgf@process{\pgfpoint{
abs(cos(\angle))^(2/\superellipseparameter)*( (cos(\angle)>0)*2-1 ) * \pgf@xa
}{
abs(sin(\angle))^(2/\superellipseparameter)*( (sin(\angle)>0)*2-1 ) * \pgf@ya
}}
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\pgf@process{\centerpoint}
\advance\pgf@x by \pgf@xb
\advance\pgf@y by \pgf@yb
}
\anchorborder{
\edef\externalx{\the\pgf@x}%
\edef\externaly{\the\pgf@y}%
\pgf@process{\radius}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\pointonsuperellipse{\pgfpoint{\pgf@xa}{\pgf@ya}}{\superellipseparameter}{\pgfpoint{\externalx}{\externaly}}
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\centerpoint%
\advance\pgf@x by\pgf@xa%
\advance\pgf@y by\pgf@ya%
}
\backgroundpath
{
\pgf@process{\radius}%
\pgfutil@tempdima=\pgf@x%
\pgfutil@tempdimb=\pgf@y%
\pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
\advance\pgfutil@tempdima by-\pgf@xb%
\advance\pgfutil@tempdimb by-\pgf@yb%
{
\pgftransformshift{\centerpoint}
\pgfplothandlercurveto
\pgfplotfunction{\x}{-180,-170,...,170}{
\pgfpoint{
abs(1 * cos(\x))^(2/\pgf@superellipse@param)*( (cos(\x)>0)*2-1 ) * \pgfutil@tempdima
}{
abs(1 * sin(\x))^(2/\pgf@superellipse@param)*( (sin(\x)>0)*2-1 ) * \pgfutil@tempdimb
}
}
\pgfpathclose
\pgfgetpath\test
\pgfusepath{stroke}
}
}
}
答案2
你始终可以手动完成:
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
\node[fill=green!30,minimum width=2cm,minimum height=3cm] (a) {A};
\node[fill=blue!30,minimum width=3cm,minimum height=3cm,right=1cm of a] (b) {B};
\node[fill=orange!30,minimum width=6cm,minimum height=3cm, below=of b.south east, anchor=north east] (c) {C};
\node[fill=red!30,minimum width=2cm,minimum height=3cm, below=of c.south east, anchor=north east] (d) {D};
\draw[thick] (a.-15)|-(a.south west) |-(a.north east)--(a.3)--(a.3-|b.west)|-(b.north east)|-(b.273)--(b.273|-c.north)-|(c.south east)--(c.-32)--(c.-32|-d.north) -|(d.south east)-|(d.north west)--(d.96)--(d.96|-c.south)-|(c.north west)--(c.55)--(c.55|-b.south)-|(a.-15-|b.west)--(a.-15)--cycle;
\end{tikzpicture}
\end{document}
更新:
根据 szantaii 的建议,下图显示了一些上一个图decoration
。
\documentclass[tikz,border=2mm]{standalone}
\usetikzlibrary{positioning,decorations.pathmorphing,backgrounds}
\begin{document}
\begin{tikzpicture}
\node[minimum width=2cm,minimum height=3cm] (a) {A};
\node[minimum width=3cm,minimum height=3cm,right=1cm of a] (b) {B};
\node[minimum width=6cm,minimum height=3cm, below=of b.south east, anchor=north east] (c) {C};
\node[minimum width=2cm,minimum height=3cm, below=of c.south east, anchor=north east] (d) {D};
\begin{scope}[on background layer]
\draw[rounded corners=1mm, thick, fill=purple!30, decoration={random steps, segment length=3pt, amplitude=0.5pt},decorate] (a.-15)|-(a.south west) |-(a.north east)--(a.3)--(a.3-|b.west)|-(b.north east)|-(b.273)--(b.273|-c.north)-|(c.south east)--(c.-32)--(c.-32|-d.north) -|(d.south east)-|(d.north west)--(d.96)--(d.96|-c.south)-|(c.north west)--(c.55)--(c.55|-b.south)-|(a.-15-|b.west)--(a.-15)--cycle;
\end{scope}
\end{tikzpicture}
\end{document}
虽然这个解决方案不如 JLDiaz 那么好,但它不需要使用white
(或任何其他颜色)线来模拟double
线条。