我想了解有关 tikz 花括号实现的详细信息,然后希望获得 d3.js 的 svg 等效版本。
例如
\documentclass{article}
\usepackage{tikz, pgfplots}
\begin{document}
\begin{tikzpicture}[
>=stealth,]
\draw [decorate,decoration={brace,amplitude=4pt,aspect=0.67}]
(0,2)--(0,0) node[pos=0.67, right, font=\footnotesize, xshift=2pt] {Compromise loss};
\end{tikzpicture}
\end{document}
如果有任何这样的代码片段(svg 或 d3.js)或文档可用!那就太好了!
使用 pdf2svg 工具,我可以将 pdf 转换为 svg,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="4.384pt" height="57.091pt" viewBox="0 0 4.384 57.091" version="1.1">
<defs>
<clipPath id="clip1">
<path d="M 0 0 L 4.382812 0 L 4.382812 57.089844 L 0 57.089844 Z M 0 0 "/>
</clipPath>
</defs>
<g id="surface1">
<g clip-path="url(#clip1)" clip-rule="nonzero">
<path style="fill:none;stroke-width:0.3985;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 0.00021875 56.692781 C 1.195531 56.095125 1.992406 54.700594 1.992406 52.708406 L 1.992406 22.692781 C 1.992406 20.700594 2.789281 19.306063 3.984594 18.708406 C 2.789281 18.11075 1.992406 16.716219 1.992406 14.724031 L 1.992406 3.98575 C 1.992406 1.993563 1.195531 0.599031 0.00021875 0.001375 " transform="matrix(1,0,0,-1,0.199,56.892)"/>
</g>
</g>
</svg>
该路径如下所示:
M 0.00021875 56.692781
C 1.195531 56.095125 1.992406 54.700594 1.992406 52.708406
L 1.992406 22.692781
C 1.992406 20.700594 2.789281 19.306063 3.984594 18.708406
C 2.789281 18.11075 1.992406 16.716219 1.992406 14.724031
L 1.992406 3.98575
C 1.992406 1.993563 1.195531 0.599031 0.00021875 0.001375
它使用 4 条三次贝塞尔曲线来绘制花括号。我仍然不知道如何计算每条三次贝塞尔曲线的控制点!
答案1
笔记: 显然我误解了这个问题......看起来,答案与问题相关,就像问题与 LaTeX 相关一样 :-(
对于这种情况,在tikz
库中decorations
定义了选项aspect
:
\documentclass[border=3.14159]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}
\begin{document}
\begin{tikzpicture}[
B/.style= {decorate,
decoration={brace, amplitude=5pt,
raise=2pt,
aspect=#1}, % <---
thick},
]
\draw[B=0.6] (0,4)-- node[pos=0.6, right=7pt] {Compromise loss} (0,0);
\end{tikzpicture}
\end{document}
或者使用库来增加一些趣味calligraphy
:
\documentclass[border=3.14159]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing,%
calligraphy,% had to be after decorations.pathreplacing
}
\begin{document}
BC/.style = {decorate,
decoration={calligraphic brace, amplitude=5pt,
raise=2pt,
aspect=#1},
very thick,
pen colour={red}},
]
\draw[BC=0.6]
(4,4) -- node[pos=0.6, right=7pt] {Compromise loss} (4,0);
\end{tikzpicture}
\end{document}
答案2
在我的计算机上,可以在这里找到实现:
/usr/local/texlive/2021/texmf-dist/tex/generic/pgf/libraries/decorations/pgflibrarydecorations.pathreplacing.code.tex
完整的实现如下brace
:
% brace decorations
%
% Parameters: \pgfdecorationsegmentamplitude
\pgfdeclaredecoration{brace}{brace}
{%
\state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
{
\pgf@yc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance
\ifdim2\pgfdecorationsegmentamplitude>\pgf@yc
\pgf@yc=0.5\pgf@yc
\else
\pgf@yc=\pgfdecorationsegmentamplitude
\fi
\pgf@xc=\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance
\advance\pgf@xc-\pgfdecoratedremainingdistance
\ifdim-2\pgfdecorationsegmentamplitude<\pgf@xc
\pgf@xc=-0.5\pgf@xc
\else
\pgf@xc=\pgfdecorationsegmentamplitude
\fi
\pgfpathmoveto{\pgfpointorigin}
\pgfpathcurveto
{\pgfqpoint{.15\pgf@yc}{.3\pgfdecorationsegmentamplitude}}
{\pgfqpoint{.5\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
{\pgfqpoint{\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
{
\pgftransformxshift{+\pgfdecorationsegmentaspect\pgfdecoratedremainingdistance}
\pgfpathlineto{\pgfqpoint{-\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
\pgfpathcurveto
{\pgfqpoint{-.5\pgf@yc}{.5\pgfdecorationsegmentamplitude}}
{\pgfqpoint{-.15\pgf@yc}{.7\pgfdecorationsegmentamplitude}}
{\pgfqpoint{0\pgf@yc}{1\pgfdecorationsegmentamplitude}}
\pgfpathcurveto
{\pgfqpoint{.15\pgf@xc}{.7\pgfdecorationsegmentamplitude}}
{\pgfqpoint{.5\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
{\pgfqpoint{\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
}
{
\pgftransformxshift{+\pgfdecoratedremainingdistance}
\pgfpathlineto{\pgfqpoint{-\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
\pgfpathcurveto
{\pgfqpoint{-.5\pgf@xc}{.5\pgfdecorationsegmentamplitude}}
{\pgfqpoint{-.15\pgf@xc}{.3\pgfdecorationsegmentamplitude}}
{\pgfqpoint{0pt}{0pt}}
}
}%
\state{final}
{}%
}%
例如,所有命令\pgfdecorationsegmentamplitude
都再次由 PGF 代码实现,然后再次实现/解释为某个东西,最后才变成坐标。这似乎是制作 SVG 括号的完全错误的方向。
答案3
从 pdf2svg 输出的 svg 点中,我们可以用 tikz 绘制图形(上部用于演示目的),如下所示:
\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc,intersections}
\usepackage{tikz,fp}
\makeatletter
\def\calcLength(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{center}}%
{\pgfpointanchor{#2}{center}}%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\FPeval\@temp@a{\pgfmath@tonumber{\pgf@xa}}%
\FPeval\@temp@b{\pgfmath@tonumber{\pgf@ya}}%
\FPeval\@temp@sum{(\@temp@a*\@temp@a+\@temp@b*\@temp@b)}%
\FProot{\FPMathLen}{\@temp@sum}{2}%
\FPround\FPMathLen\FPMathLen5\relax
\global\expandafter\edef\csname #3\endcsname{\FPMathLen}
}
\makeatother
\tikzset{
ctrlpoint/.style={%
draw=gray,
circle,
inner sep=0,
minimum width=1ex,
}
}
\newcommand{\Bezier}[5][]{% \bezier (lowercase 'b') was already defined elsewhere
\node (p1) [ctrlpoint] at (#2) {};
\node (p2) [ctrlpoint] at (#3) {};
\node (p3) [ctrlpoint] at (#4) {};
\node (p4) [ctrlpoint] at (#5) {};
\draw [gray] (p1) -- (p2) -- (p3) -- (p4);
\draw [blue,#1] (#2) .. controls (#3) and (#4) .. (#5);
}
\begin{document}
\begin{tikzpicture}[x=1pt,y=1pt,scale=5]
\coordinate (A) at (28.347812,28.347969);
\coordinate (C1) at (27.289219,31.515938);
\coordinate (C2) at (28.347812,35.390938);
\coordinate (P2) at (31.867344,38.914375);
\coordinate (P3) at (46.070469,53.113594);
\coordinate (C3) at (49.59,56.637031);
\coordinate (C4) at (50.648594,60.512031);
\coordinate (P8) at (49.59,63.68);
\coordinate (C5) at (52.761875,62.625313);
\coordinate (C6) at (56.636875,63.68);
\coordinate (P5) at (60.156406,67.203438);
\coordinate (P6) at (74.359531,81.402656);
\coordinate (C7) at (77.879063,84.926094);
\coordinate (C8) at (81.754063,85.980781);
\coordinate (B) at (84.925938,84.926094);
\draw[line width=1] (A) .. controls (C1) and (C2) .. (P2) -- (P3) .. controls (C3) and (C4) .. (P8) .. controls (C5) and (C6) .. (P5) -- (P6) .. controls (C7) and (C8) .. (B);
%\Bezier[line width=1]{A}{C1}{C2}{P2};
%\Bezier[line width=1]{P3}{C3}{C4}{P8};
%\Bezier[line width=1]{P8}{C5}{C6}{P5};
%\Bezier[line width=1]{P6}{C7}{C8}{B};
\def\w{10}
\draw [red,line width=1]
let
\p{A}=(A),
\p{B}=(B),
\n{len}={veclen(\x{B}-\x{A},\y{B}-\y{A})},
\n{dx}={(\x{B}-\x{A})/\n{len}},
\n{dy}={(\y{B}-\y{A})/\n{len}},
\p{P2}=({\x{A}+\n{dx}*\w-\n{dy}*\w/2},{\y{A}+\n{dy}*\w+\n{dx}*\w/2}),
\p{P6}=({\x{B}-\n{dx}*\w-\n{dy}*\w/2},{\y{B}-\n{dy}*\w+\n{dx}*\w/2}),
\p{C1}=({\x{A}+\n{dx}*\w*.15-\n{dy}*\w*.3},{\y{A}+\n{dy}*\w*.15+\n{dx}*\w*.3}),
\p{C2}=({\x{P2}-\n{dx}*\w/2},{\y{P2}-\n{dy}*\w/2}),
\p{P4}=({\x{A}+\n{dx}*\n{len}/2-\n{dy}*\w/2},{\y{A}+\n{dy}*\n{len}/2+\n{dx}*\w/2}),
\p{P8}=({\x{P4}-\n{dy}*\w/2},{\y{P4}+\n{dx}*\w/2}), \p{P3}=({\x{P4}-\n{dx}*\w},{\y{P4}-\n{dy}*\w}),
\p{P5}=({\x{P4}+\n{dx}*\w},{\y{P4}+\n{dy}*\w}), \p{C3}=({\x{P3}+\n{dx}*\w/2},{\y{P3}+\n{dy}*\w/2}),
\p{C4}=({\x{P8}-\n{dx}*\w*.15 + \n{dy}*\w*.3},{\y{P8}-\n{dy}*\w*.15-\n{dx}*\w*.3}),
\p{C5}=({\x{P8}+\n{dx}*\w*.15 + \n{dy}*\w*.3},{\y{P8}+\n{dy}*\w*.15-\n{dx}*\w*.3}),
\p{C6}=({\x{P5}-\n{dx}*\w/2},{\y{P5}-\n{dy}*\w/2}),
\p{C7}=({\x{P6}+\n{dx}*\w/2},{\y{P6}+\n{dy}*\w/2}),
\p{C8}=({\x{B}-\n{dx}*\w*.15-\n{dy}*\w*.3},{\y{B}-\n{dy}*\w*.15+\n{dx}*\w*.3}),
in
%(A) -- (\p{C1}) -- (\p{C2}) -- (\p{P2}) -- (\p{P3}) -- (\p{C3}) -- (\p{C4}) -- (\p{P8}) -- (\p{C5}) -- (\p{C6}) -- (\p{P5}) -- (\p{P6}) -- (\p{C7}) -- (\p{C8}) -- (B)
(A) .. controls (\p{C1}) and (\p{C2}) .. (P2) -- (P3) .. controls (\p{C3}) and (\p{C4}) .. (\p{P8}) .. controls (\p{C5}) and (\p{C6}) .. (\p{P5}) -- (\p{P6}) .. controls (\p{C7}) and (\p{C8}) .. (B);
%\draw[gray] (A) -- (B);
\coordinate (P2P) at ($(A)!(P2)!(B)$);
\coordinate (C1P) at ($(A)!(C1)!(B)$);
\coordinate (C2P) at ($(A)!(C2)!(B)$);
%\calcLength(A,C1P){mylenc};
%\calcLength(A,C2P){mylend};
%\calcLength(A,P2P){mylenp};
\end{tikzpicture}
% \mylenc , \mylend , \mylenp
\end{document}
输出:
从该图中我们可以看到:
- C1 位置在 y 轴偏移 1/8 单位,x 轴偏移 1/2 单位。
- C2 位置在 y 轴偏移 1/2 个单位处,在 x 轴偏移 1 个单位处。
x 单位是 P2 到 P2P 的距离。y 单位是 A 到 P2P 的距离。
这同样适用于其他曲线。
使用 tikz 命令模拟花括号的完整 tikz 代码:
\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{calc,intersections}
\tikzset{
ctrlpoint/.style={%
draw=gray,
circle,
inner sep=0,
minimum width=1ex,
}
}
\newcommand{\Bezier}[5][]{% \bezier (lowercase 'b') was already defined elsewhere
\node (p1) [ctrlpoint,label=90:$#2$] at (#2) {};
\node (p2) [ctrlpoint,label=90:$#3$] at (#3) {};
\node (p3) [ctrlpoint,label=90:$#4$] at (#4) {};
\node (p4) [ctrlpoint,label=90:$#5$] at (#5) {};
\draw [gray] (p1) -- (p2) -- (p3) -- (p4);
\draw [blue,#1] (#2) .. controls (#3) and (#4) .. (#5);
}
\begin{document}
\begin{tikzpicture}[x=1pt,y=1pt,scale=10]
\coordinate (A) at (28.347812,28.347969);
\coordinate (C1) at (27.289219,31.515938); \coordinate (C2) at (28.347812,35.390938); \coordinate (P2) at (31.867344,38.914375);
\coordinate (P3) at (46.070469,53.113594);
\coordinate (C3) at (49.59,56.637031); \coordinate (C4) at (50.648594,60.512031); \coordinate (P8) at (49.59,63.68);
\coordinate (C5) at (52.761875,62.625313); \coordinate (C6) at (56.636875,63.68); \coordinate (P5) at (60.156406,67.203438);
\coordinate (P6) at (74.359531,81.402656);
\coordinate (C7) at (77.879063,84.926094); \coordinate (C8) at (81.754063,85.980781); \coordinate (B) at (84.925938,84.926094);
\draw[line width=1] (A) .. controls (C1) and (C2) .. (P2) -- (P3) .. controls (C3) and (C4) .. (P8) .. controls (C5) and (C6) .. (P5) -- (P6) .. controls (C7) and (C8) .. (B);
\Bezier[line width=1]{A}{C1}{C2}{P2};
\Bezier[line width=1]{P3}{C3}{C4}{P8};
\Bezier[line width=1]{P8}{C5}{C6}{P5};
\Bezier[line width=1]{P6}{C7}{C8}{B};
\def\w{10}
\draw [red,line width=.5]
let
\p{A}=(A),
\p{B}=(B),
\n{len}={veclen(\x{B}-\x{A},\y{B}-\y{A})},
\n{dx}={(\x{B}-\x{A})/\n{len}},
\n{dy}={(\y{B}-\y{A})/\n{len}},
\p{P2}=({\x{A}+\n{dx}*\w-\n{dy}*\w/2},{\y{A}+\n{dy}*\w+\n{dx}*\w/2}),
\p{P6}=({\x{B}-\n{dx}*\w-\n{dy}*\w/2},{\y{B}-\n{dy}*\w+\n{dx}*\w/2}),
\p{C1}=({\x{A}+\n{dx}*\w/8-\n{dy}*\w/4},{\y{A}+\n{dy}*\w/8+\n{dx}*\w/4}),
\p{C2}=({\x{P2}-\n{dx}*\w/2},{\y{P2}-\n{dy}*\w/2}),
\p{P4}=({\x{A}+\n{dx}*\n{len}/2-\n{dy}*\w/2},{\y{A}+\n{dy}*\n{len}/2+\n{dx}*\w/2}),
\p{P8}=({\x{P4}-\n{dy}*\w/2},{\y{P4}+\n{dx}*\w/2}), \p{P3}=({\x{P4}-\n{dx}*\w},{\y{P4}-\n{dy}*\w}),
\p{P5}=({\x{P4}+\n{dx}*\w},{\y{P4}+\n{dy}*\w}), \p{C3}=({\x{P3}+\n{dx}*\w/2},{\y{P3}+\n{dy}*\w/2}),
\p{C4}=({\x{P8}-\n{dx}*\w/8 + \n{dy}*\w/4},{\y{P8}-\n{dy}*\w/8-\n{dx}*\w/4}),
\p{C5}=({\x{P8}+\n{dx}*\w/8 + \n{dy}*\w/4},{\y{P8}+\n{dy}*\w/8-\n{dx}*\w/4}),
\p{C6}=({\x{P5}-\n{dx}*\w/2},{\y{P5}-\n{dy}*\w/2}),
\p{C7}=({\x{P6}+\n{dx}*\w/2},{\y{P6}+\n{dy}*\w/2}),
\p{C8}=({\x{B}-\n{dx}*\w/8-\n{dy}*\w/4},{\y{B}-\n{dy}*\w/8+\n{dx}*\w/4}),
in
%(A) -- (\p{C1}) -- (\p{C2}) -- (\p{P2}) -- (\p{P3}) -- (\p{C3}) -- (\p{C4}) -- (\p{P8}) -- (\p{C5}) -- (\p{C6}) -- (\p{P5}) -- (\p{P6}) -- (\p{C7}) -- (\p{C8}) -- (B)
(A) .. controls (\p{C1}) and (\p{C2}) .. (P2) -- (P3) .. controls (\p{C3}) and (\p{C4}) .. (\p{P8}) .. controls (\p{C5}) and (\p{C6}) .. (\p{P5}) -- (\p{P6}) .. controls (\p{C7}) and (\p{C8}) .. (B);
\draw[gray] (A) -- (B);
\end{tikzpicture}
\end{document}