情境:這個問題是後續問題使用嵌套元素創建 TikZ 圖片的最佳實踐。符號1假如一個答案對於這個問題,\scopenode
定義在哪裡。
\scopenode
name=foo
範圍是否轉變為節點,即可以: 透過;命名範圍通過 定位範圍at=(somewhere)
;並透過 調整位置anchor=something
。它們基本上很棒,因為它們可以嵌套。
然後,在如何讓 tikzexternalize 和 saveboxes 的使用相容?,CFR假如一個答案透過啟用背景和內容\scopenode
的顯示來改進這些\scopenode
\scopenode
功能。 (Scopenode背景確實會被繪製多於否則內容。
問題:我試圖包括\scopenode
在 Ti 中kZ。matrix
但是,我有一些問題:
問題:怎麼做\scopenode
與Ti相容kmatrix
?
微量元素
(此範例建立一個矩陣一行和兩列。在兩個單元格(A1 和 B1)中,示波器都是填充繪製的。 A(紅橙色)為南錨定,B(黃綠色)為北錨定。在每個範圍節點中,繪製一條從(0,0)到(1,1)的路徑。
_______
| A | |
|---|---| <-- baseline
|___|_B_|
使用符號 1 的解:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{backgrounds}
% \usetikzlibrary{external}
% \tikzexternalize
% \tikzset{external/prefix=build/}
\makeatletter
\newbox\tikz@sand@box
\newcount\tikz@scope@depth
\tikz@scope@depth111\relax
\def\scopenode[#1]#2{%
\begin{pgfinterruptboundingbox}%
\advance\tikz@scope@depth111\relax%
% process the user option
\begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]%
% try to extract positioning information: name, at, anchor
\global\let\tikz@fig@name\tikz@fig@name%
\global\let\tikz@node@at\tikz@node@at%
\global\let\tikz@anchor\tikz@anchor%
\end{scope}%
\let\tikz@scopenode@name\tikz@fig@name%
\let\tikz@scopenode@at\tikz@node@at%
\let\tikz@scopenode@anchor\tikz@anchor%
% try to typeset this scope
% we only need bounding box information
% the box itself will be discard
\setbox\tikz@sand@box=\hbox{%
\begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]%
#2%
\end{scope}%
}%
% goodbye. haha
\setbox\tikz@sand@box=\hbox{}%
% now typeset again
\begin{scope}[local bounding box=\tikz@scopenode@name]%
% use the bounding box information to reposition the scope
\pgftransformshift{\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}%
\pgf@x-\pgf@x\pgf@y-\pgf@y}%
\pgftransformshift{\tikz@scopenode@at}%
\begin{scope}[#1]%
#2
\end{scope}%
\end{scope}%
\pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}%
\global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name%
\end{pgfinterruptboundingbox}%
% make up the bounding box
\path(\tikz@scopenode@[email protected] west)(\tikz@scopenode@[email protected] east);%
% draw something, not necessary
\draw[#1](\tikz@scopenode@[email protected] west)rectangle(\tikz@scopenode@[email protected] east);%
}
\makeatother
\begin{document}
\begin{tikzpicture}[
remember picture,
inner sep=0pt,
outer sep=0pt,
]
\draw [help lines](-2,-2) grid (2,2);
\matrix[
column sep=2em,
row sep = 1em,
nodes in empty cells,
anchor=center,
nodes={anchor=center},
]
{
\scopenode[draw = red, fill = orange, anchor=south] {
\draw [blue] (0,0) -- (1,1);
};
&
\scopenode[draw = yellow, fill = green, anchor=north] {
\draw [black] (0,1) -- (1,0);
};
\\
};
\end{tikzpicture}
\end{document}
使用cfr的解決方案:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{backgrounds}
% \usetikzlibrary{external}
% \tikzexternalize
% \tikzset{external/prefix=build/}
\makeatletter
\pgfdeclarelayer{scopenode}
\pgfsetlayers{background,scopenode,main}
\tikzset{%
% adapted from tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex
on scopenode layer/.style={%
execute at begin scope={%
\pgfonlayer{scopenode}%
\let\tikz@options=\pgfutil@empty%
\tikzset{every on scopenode layer/.try,#1}%
\tikz@options%
},
execute at end scope={\endpgfonlayer}
},
}
% ateb Symbol 1: tex.stackexchange.com/a/…
\newbox\tikz@sand@box
\newcount\tikz@scope@depth
\tikz@scope@depth111\relax
\def\scopenode[#1]#2{% name=<enw>, at=<man>, anchor=<angor>
\begin{pgfinterruptboundingbox}%
\advance\tikz@scope@depth111\relax%
% process the user option
\begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]%
% try to extract positioning information: name, at, anchor
\global\let\tikz@fig@name\tikz@fig@name%
\global\let\tikz@node@at\tikz@node@at%
\global\let\tikz@anchor\tikz@anchor%
\end{scope}%
\let\tikz@scopenode@name\tikz@fig@name%
\let\tikz@scopenode@at\tikz@node@at%
\let\tikz@scopenode@anchor\tikz@anchor%
% try to typeset this scope
% we only need bounding box information
% the box itself will be discard
\setbox\tikz@sand@box=\hbox{%
\begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]%
#2%
\end{scope}%
}%
% goodbye. haha
\setbox\tikz@sand@box=\hbox{}%
% now typeset again
\begin{scope}[local bounding box=\tikz@scopenode@name]%
% use the bounding box information to reposition the scope
\pgftransformshift{\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}%
\pgf@x-\pgf@x\pgf@y-\pgf@y}%
\pgftransformshift{\tikz@scopenode@at}%
\begin{scope}[#1]%
#2
\end{scope}%
\end{scope}%
\pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}%
\global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name%
\end{pgfinterruptboundingbox}%
% make up the bounding box
\path(\tikz@scopenode@[email protected] west)(\tikz@scopenode@[email protected] east);%
% draw something, not necessary
\begin{scope}[on scopenode layer]%
\draw[#1](\tikz@scopenode@[email protected] west)rectangle(\tikz@scopenode@[email protected] east);%
\end{scope}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[
remember picture,
inner sep=0pt,
outer sep=0pt,
]
\draw [help lines](-2,-2) grid (2,2);
\matrix[
column sep=2em,
row sep = 1em,
nodes in empty cells,
anchor=center,
nodes={anchor=center},
]
{
\scopenode[draw = red, fill = orange, anchor=south] {
\draw [blue] (0,0) -- (1,1);
};
&
\scopenode[draw = yellow, fill = green, anchor=north] {
\draw [black] (0,1) -- (1,0);
};
\\
};
\end{tikzpicture}
\end{document}
答案1
這是迄今為止我能得到的最好的:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{backgrounds}
% \usetikzlibrary{external}
% \tikzexternalize
% \tikzset{external/prefix=build/}
\makeatletter
\newbox\tikz@sand@box
\newcount\tikz@scope@depth
\newdimen\tikz@scope@shiftx
\newdimen\tikz@scope@shifty
\newdimen\tikz@scope@swx
\newdimen\tikz@scope@swy
\newdimen\tikz@scope@nex
\newdimen\tikz@scope@ney
\tikz@scope@depth111\relax
\def\scopenode[#1]#2{%
\begin{pgfinterruptboundingbox}%
\advance\tikz@scope@depth111\relax%
% process the user option
\begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]%
% try to extract positioning information: name, at, anchor
\global\let\tikz@fig@name@\tikz@fig@name%
\global\let\tikz@node@at@\tikz@node@at%
\global\let\tikz@anchor@\tikz@anchor%
\end{scope}%
\let\tikz@scopenode@name\tikz@fig@name@%
\let\tikz@scopenode@at\tikz@node@at@%
\let\tikz@scopenode@anchor\tikz@anchor@%
% try to typeset this scope
% we only need bounding box information
% the box itself will be discard
\setbox\tikz@sand@box=\hbox{%
\begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]%
#2%
\end{scope}%
}%
% goodbye. haha
\setbox\tikz@sand@box=\hbox{}%
% now typeset again
\begin{scope}[local bounding box=\tikz@scopenode@name]%
% use the bounding box information to reposition the scope
\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}%
\tikz@scope@shiftx-\pgf@x%
\tikz@scope@shifty-\pgf@y%
\tikz@scopenode@at%
\advance\tikz@scope@shiftx\pgf@x%
\advance\tikz@scope@shifty\pgf@y%
\pgftransformshift{\pgfpoint{\tikz@scope@shiftx}{\tikz@scope@shifty}}
% the background path
% lengthy, tedious calculation
% someone please improve this
\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{south west}
\tikz@scope@swx\pgf@x\advance\tikz@scope@swx\tikz@scope@shiftx
\tikz@scope@swy\pgf@y\advance\tikz@scope@swy\tikz@scope@shifty
\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{north east}
\tikz@scope@nex\pgf@x\advance\tikz@scope@nex\tikz@scope@shiftx
\tikz@scope@ney\pgf@y\advance\tikz@scope@ney\tikz@scope@shifty
\path(\tikz@scope@swx,\tikz@scope@swy)coordinate(tempsw)
(\tikz@scope@nex,\tikz@scope@ney)coordinate(tempne);
\path[#1](tempsw)rectangle(tempne);
% typeset the content for real
\begin{scope}[#1]%
#2%
\end{scope}%
\end{scope}%
\pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}%
\global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name%
\end{pgfinterruptboundingbox}%
% make up the bounding box
\path(\tikz@scopenode@[email protected] west)(\tikz@scopenode@[email protected] east);%
% compatible code for matrix
\expandafter\pgf@nodecallback\expandafter{\tikz@scopenode@name@smuggle}%
}
\makeatother
\begin{document}
\begin{tikzpicture}[remember picture,inner sep=0pt,outer sep=0pt]
\draw[help lines](-2,-2)grid(2,2);
\matrix()
[
column sep=2em,
row sep=1em,
nodes in empty cells,
anchor=center,
nodes={anchor=center},
]
{
\scopenode[draw=red,fill=orange,name=aaa,anchor=south] {
\draw[blue](0,0)--(1,1)circle(.2);
};
&
\scopenode[draw=yellow,fill=green,name=bbb,anchor=north] {
\draw[black](0,1)--(1,0)circle(.1);
};
&
\scopenode[fill=cyan,name=ccc,anchor=east,scale=.8] {
\draw(0,0)--(1,1)circle(.3)--(2,0);
};
\\
\node(aaaa){};
&
\node(bbbb){};
&
\node(cccc){};
\\
};
\draw[->](2,2)node[above]{this is the orange scopenode}to[bend left](aaa.east);
\draw[->](-2,-2)node[below]{this is the green scopenode}to[bend left](bbb.west);
\draw[->](3,-1)node[right]{this is the cyan scopenode}to[bend left](ccc.south);
\end{tikzpicture}
\end{document}
進口資訊
親愛的未來的我:
供您參考,矩陣的內容僅在 hbox 中排版一次。然後將它們移動到相應的單元格中。然後將整個矩陣移動到所需的位置。第一個動作由 完成\pgf@matrix@shift@nodes@initial
,第二個動作由完成\pgf@matrix@shift@nodes@secondary
。它們只是應用於\pgf@shift@node
節點列表。若要註冊範圍節點,您新增了以下行
\expandafter\pgf@nodecallback\expandafter{\tikz@scopenode@name@smuggle}%
所以範圍節點也被移動了。
目前,scopenode 中的所有內容都會被排版兩次。對於巢狀的範圍節點,事物的排版深度為 2倍。這真是令人沮喪。也許有人可以透過 Ti 的方式來改進這個kZ 處理矩陣。
(但是矩陣不能嵌套。你贏了!)
還有,你也變了
\global\let\tikz@fig@name\tikz@fig@name
到
\global\let\tikz@fig@name@\tikz@fig@name
以便在其他地方無法存取範圍節點的名稱。
特別是,鈦kZ 將應用於\pgf@shift@node
矩陣本身。如果矩陣未命名,則最後一個範圍節點將被移動,這是不需要的。你花了兩個小時才發現這個愚蠢的錯誤。吸取教訓。
此外,您還對範圍節點的背景路徑進行了硬編碼,以便現在在範圍內容之前填入/繪製它。 (由此得名背景路徑)但計算冗長且看似多餘。我希望有人可以改進它。
儘管如此,您還是避免使用pgfonlayer
.太棒了。