TikZ 中有一个用于创建思维导图(或概念导图)的库(https://pgf-tikz.github.io/pgf/pgfmanual.pdf#section.60)。
但是,使用起来似乎不太直观。我希望节点能够自动调整到其内容(部分可以通过以下方法实现https://tex.stackexchange.com/a/285655/194783)。
此外,我希望思维导图能够(至少是半)自动排列。
为了避免发生类似 MWE 的事情:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{mindmap}
\begin{document}
\pagestyle{empty}
{\centering
\makebox[0pt]{
\begin{tikzpicture}
[mindmap,
grow cyclic,
every node/.style={concept, text width=},
concept color=teal!40,
]
\node {node}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
};
\end{tikzpicture}
}
\par
}
\end{document}
我假设,在 CSS 中,人们将边距定义为具有不重叠的元素。
解决方案的一部分可能包括设置动态兄弟角度(例如https://tex.stackexchange.com/a/118746/194783)并定义自定义增长函数(如中所述https://tex.stackexchange.com/a/232914/194783)。
sibling angle
编辑:为了缓解这个问题,我添加了一些代码来根据节点的子节点数量自动设置。但这仍然不能总是避免重叠。
我看过几篇关于编写自定义增长函数来实现特殊形状的帖子。这通常也能解决重叠问题,但我并不需要那里使用的形状。
对于相关问题,建议使用以下软件包forest
,但对我的情况没有太大帮助:使用TikZ在树中重叠节点
答案1
所有功劳都归功于@Marmottopanswers.xyz/tex?q=1808
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{mindmap,shadows}
% growCycle
\makeatletter
\newif\ifmmap@debug
\mmap@debugfalse
\newcommand{\mmap@debug@message}[1]{\ifmmap@debug
\typeout{#1}%
\fi}
\def\tikz@mmap@store@aux#1#2{%
\immediate\write\@mainaux{\string\expandafter\xdef\noexpand\csname pgfk@/tikz/mmap/\pgfkeysvalueof{/tikz/mmap/name}/#1\string\endcsname{#2}}}%
\def\tikz@mmap@get@from@aux#1#2{%
\ifcsname pgfk@/tikz/mmap/\pgfkeysvalueof{/tikz/mmap/name}/#1\endcsname
\edef#2{\csname pgfk@/tikz/mmap/\pgfkeysvalueof{/tikz/mmap/name}/#1\endcsname}%
\else
\edef#2{0}%
\fi
}
\pgfmathdeclarefunction{MMapNodesAtLevel}{1}{%
\tikz@mmap@get@from@aux{n-\@roman{#1}}{\pgfmathresult}}
\newcount\tikzcountchildi
\newcount\tikzcountchildii
\newcount\tikzcountchildiii
\newcount\tikzcountchildiv
\newcount\tikzcountchildv
\newcount\tikzcountchildvi
\tikzcountchildi=0
\tikzcountchildii=0
\tikzcountchildiii=0
\tikzcountchildiv=0
\tikzcountchildv=0
\tikzcountchildvi=0
\tikzset{Julien growth/.style={growth function=\tikz@grow@Julien,
mmap/initialize counts,
/tikz/execute at end scope={%
\tikz@mmap@store@aux{n-i}{\the\tikzcountchildi}%
\tikz@mmap@store@aux{n-ii}{\the\tikzcountchildii}%
\tikz@mmap@store@aux{n-iii}{\the\tikzcountchildiii}%
\tikz@mmap@store@aux{n-iv}{\the\tikzcountchildiv}%
\tikz@mmap@store@aux{n-v}{\the\tikzcountchildv}%
\tikz@mmap@store@aux{n-vi}{\the\tikzcountchildvi}%
}},
mmap/.cd,initialize counts/.code={\global\tikzcountchildi=0%
\global\tikzcountchildii=0%
\global\tikzcountchildiii=0%
\global\tikzcountchildiv=0%
\global\tikzcountchildv=0%
\global\tikzcountchildvi=0%
}
}
\def\tikz@grow@Julien{%
\pgftransformreset%
\pgftransformshift{\pgfpoint{\pgfkeysvalueof{/tikz/mmap/overall xshift}}%
{\pgfkeysvalueof{/tikz/mmap/overall yshift}}}%
\ifcase\tikztreelevel
\or
\pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildi}%
\global\advance\tikzcountchildi by1\relax%
\or
\pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildii}%
\global\advance\tikzcountchildii by1\relax%
\or
\pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildiii}%
\global\advance\tikzcountchildiii by1\relax%
\or
\pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildiv}%
\global\advance\tikzcountchildiv by1\relax%
\or
\pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
+\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildv}%
\global\advance\tikzcountchildv by1\relax%
\fi
\mmap@debug@message{level=\the\tikztreelevel,%
\the\tikzcountchildi,\the\tikzcountchildii,\the\tikzcountchildiii,
rotation=\pgfutil@tempb,sibling angle=\pgfkeysvalueof{/tikz/sibling angle}}%
\pgftransformrotate{\pgfutil@tempb}%
\pgftransformxshift{\the\tikzleveldistance}%
}
\makeatother
\tikzset{%
mmap/.cd,
name/.initial=undef,
overall rotation/.initial=0,
overall xshift/.initial=0pt,
overall yshift/.initial=0pt,
sign/.initial=1,
child weight/.initial=0.5,
/tikz/.cd,
offset angle/.initial=0, %%% Not exist anymore
Xshift/.style={xshift=#1,mmap/overall xshift=#1},
Yshift/.style={yshift=#1,mmap/overall yshift=#1},
branch color/.style={
concept color=#1!80,ball color=#1!50,
every child/.append style={concept color=#1!50},
}
}
\begin{document}
% you may want to use pgf keys for those (did not change them)
\def\ShapeAngle{360} % half circle
\def\Rotation{0}
\def\DistOne{5cm}
\def\DistTwo{8cm}
\def\DistThree{11cm}
\def\OffsetLevelThree{0}
% Part to automate
\begin{tikzpicture}%[node font=\sffamily]
\begin{scope}
[ text width=1.5cm,
align=flush center,
mindmap,Julien growth,
mmap/overall rotation=\Rotation,mmap/sign=1,
mmap/name=semicirc,%<- you need unique names if you want to use several mindmaps
every node/.style={concept,circular drop shadow,execute at begin node=\hskip0pt,text=white},
node font=\sffamily,
nodes={concept},
concept color=teal!40,
root concept/.append style={ball color=teal!40, line width=1.5ex,text=white,font=\huge\bfseries\scshape,minimum size=4.5cm,text width=4.5cm,},
level 1/.style={level distance=\DistOne,font=\large,minimum size=2.5cm,text width=2.0cm,
sibling angle/.evaluated={\ShapeAngle/max((MMapNodesAtLevel(1)-1),1)}},
level 2/.style={level distance=\DistTwo,font=\normalsize,minimum size=1.5cm,text width=1.5cm,
sibling angle/.evaluated={\ShapeAngle/max((MMapNodesAtLevel(2)-1),1)}},
level 3/.style={level distance=\DistThree,font=\normalsize,minimum size=1.5cm,text width=1.5cm,
sibling angle/.evaluated={\ShapeAngle/max((MMapNodesAtLevel(3)-1),1)},
offset angle=\OffsetLevelThree},
]
\node[root concept] {node}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
}
child{
node {subnode}
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
child { node {subnode} }
};
\end{scope}
\end{tikzpicture}
\end{document}