背景
使用 MetaPost 在覆盖层上绘制一条线,该覆盖层用作框架层的背景。该层嵌入在设置这样每次都会重新计算时间线上的点的位置。计算基于当前部分的标题文本的值。
问题
时间线两端的水平条略有移动。比较:
当重叠显示时,差异很明显,尽管很微妙:
代码
这个最小工作示例相当简单。大部分代码都是通过解析节标题中的数字来完成的\startuseMPgraphic
。
\definepapersize[BookPaperSize][
width=8in,
height=6in,
]
\setuppapersize[BookPaperSize]
% Specify the width and height here because the inline figures need to
% maintain aspect ratio while setting a pleasing width.
\startsetups[BookIllustrationSetups]
\setlayerframed[BookIllustrationLayer][
frame=off,
x=\zeropoint,
y=1.25in,
width=\makeupwidth,
background=BookTimelineOverlay,
]{}
\stopsetups
\setupbackgrounds[page][
background=BookIllustrationLayer,
setups=BookIllustrationSetups
]
\definelayer[BookIllustrationLayer][
width=\paperwidth,
height=\paperheight,
]
\defineoverlay[BookTimelineOverlay][\useMPgraphic{BookTimelineGraphic}]
\startuseMPgraphic{BookTimelineGraphic}
% Define constants
numeric EVENT_BEGAN, TIME_OFFSET, PATH_THICKNESS;
EVENT_BEGAN := 13799;
TIME_OFFSET := 1.25in;
PATH_THICKNESS := 2pt;
% The book timeline title macro contains a number representing when the
% event transpired and additional information.
string sectionTitle, sectionTitleDigits;
sectionTitle := "\getspecificstructuretitle{3}";
sectionTitleDigits := "";
% Extract only digits and decimals from the book timeline title macro.
for i = 0 upto length( sectionTitle ):
string sectionChar;
sectionChar := substring( i, i + 1 ) of sectionTitle;
% A space indicates that the number has no more digits.
if sectionChar = " ":
break;
fi;
% Concatentate all the digits together.
if ((sectionChar >= "0") and (sectionChar <= "9")) or (sectionChar = "."):
sectionTitleDigits := sectionTitleDigits & sectionChar;
fi;
endfor;
% Convert the digits from a string to a numeric value.
numeric eventTime;
eventTime := 0;
for i = scantokens( sectionTitleDigits ):
eventTime := i;
endfor;
numeric eventX;
eventX := 1 - (eventTime / EVENT_BEGAN);
% Draw the line.
draw (TIME_OFFSET, .5*\overlayheight) -- (\overlaywidth, .5*\overlayheight) \
withpen pencircle scaled PATH_THICKNESS;
% Draw starting |.
draw (TIME_OFFSET, 0) -- (TIME_OFFSET, \overlayheight) \
withpen pencircle scaled PATH_THICKNESS;
% Draw ending |.
draw (\overlaywidth, 0) -- (\overlaywidth, \overlayheight) \
withpen pencircle scaled PATH_THICKNESS;
% Draw the timeline's dot relative to the event on the timeline.
filldraw fullcircle scaled 9 \
shifted( \
TIME_OFFSET + eventX * (\overlaywidth - TIME_OFFSET), .5*\overlayheight \
);
\stopuseMPgraphic
\starttext
\chapter[title={Inflation Theory},reference={inflation-theory}]
\section[title={13,799 ± 0.021},reference={section}]
\input ward
\chapter[title={First Stars},reference={first-stars}]
\section[title={13,689 ± 70},reference={section-1}]
\input ward
\stoptext
问题
我在想:
- 时间轴栏为何略微发生偏移?
- 如何消除这种移位,使得时间轴条能够精确重叠,而不管时间线点的位置如何?
附加问题:
- 如何简化代码,特别是解析标题?
示例输出
以下示例展示了如何使用时间线图形:
解决
经过一些上下文调整,Henri 的解决方案完美地发挥了作用:
numeric wb, hb;
wb := \overlaywidth - 1in;
hb := .5in;
draw image(
draw image(
% Draw the line.
draw (0, .5*hb) -- (wb, .5*hb);
% Draw starting |.
draw (0, 0) -- (0, hb);
% Draw ending |.
draw (wb, 0) -- (wb, hb);
)
withpen pencircle scaled 2pt withcolor \MPcolor{\overlaylinecolor};
draw image(
% Draw the timeline's dot relative to the event on the timeline.
filldraw fullcircle scaled 11 shifted( eventX * wb, .5*hb );
)
withcolor \MPcolor{BookTimelineColour};
)
shifted( .55in, OverlayHeight - .25 * hb );
答案1
点的位置会修改边界框。此问题最临时的解决方案是
- 在绘制点之前保存边界框
- 画点
- 恢复没有点的边界框
然后,该点将会泄漏出边界框,但那只是一点点。
\definepapersize[BookPaperSize][
width=8in,
height=6in,
]
\setuppapersize[BookPaperSize]
% Specify the width and height here because the inline figures need to
% maintain aspect ratio while setting a pleasing width.
\startsetups[BookIllustrationSetups]
\setlayerframed[BookIllustrationLayer][
frame=off,
x=\zeropoint,
y=1.25in,
width=\makeupwidth,
background=BookTimelineOverlay,
]{}
\stopsetups
\setupbackgrounds[page][
background=BookIllustrationLayer,
setups=BookIllustrationSetups
]
\definelayer[BookIllustrationLayer][
width=\paperwidth,
height=\paperheight,
]
\defineoverlay[BookTimelineOverlay][\useMPgraphic{BookTimelineGraphic}]
\startuseMPgraphic{BookTimelineGraphic}
% Define constants
numeric EVENT_BEGAN, TIME_OFFSET, PATH_THICKNESS;
EVENT_BEGAN := 13799;
TIME_OFFSET := 1.25in;
PATH_THICKNESS := 2pt;
% The book timeline title macro contains a number representing when the
% event transpired and additional information.
string sectionTitle, sectionTitleDigits;
sectionTitle := "\getspecificstructuretitle{3}";
sectionTitleDigits := "";
% Extract only digits and decimals from the book timeline title macro.
for i = 0 upto length( sectionTitle ):
string sectionChar;
sectionChar := substring( i, i + 1 ) of sectionTitle;
% A space indicates that the number has no more digits.
if sectionChar = " ":
break;
fi;
% Concatentate all the digits together.
if ((sectionChar >= "0") and (sectionChar <= "9")) or (sectionChar = "."):
sectionTitleDigits := sectionTitleDigits & sectionChar;
fi;
endfor;
% Convert the digits from a string to a numeric value.
numeric eventTime;
eventTime := 0;
for i = scantokens( sectionTitleDigits ):
eventTime := i;
endfor;
numeric eventX;
eventX := 1 - (eventTime / EVENT_BEGAN);
% Draw the line.
draw (TIME_OFFSET, .5*\overlayheight) -- (\overlaywidth, .5*\overlayheight)
withpen pencircle scaled PATH_THICKNESS;
% Draw starting |.
draw (TIME_OFFSET, 0) -- (TIME_OFFSET, \overlayheight)
withpen pencircle scaled PATH_THICKNESS;
% Draw ending |.
draw (\overlaywidth, 0) -- (\overlaywidth, \overlayheight)
withpen pencircle scaled PATH_THICKNESS;
% The dot will change the size of bounding box, so we will just save the
% bounding box without the dot for later
path p ; p := bbox currentpicture ;
% Draw the timeline's dot relative to the event on the timeline.
filldraw fullcircle scaled 9
shifted(
TIME_OFFSET + eventX * (\overlaywidth - TIME_OFFSET), .5*\overlayheight
);
% Restore the bounding box without dot
setbounds currentpicture to p ;
\stopuseMPgraphic
\starttext
\chapter[title={Inflation Theory},reference={inflation-theory}]
\section[title={13,799 ± 0.021},reference={section}]
\input ward
\chapter[title={First Stars},reference={first-stars}]
\section[title={13,689 ± 70},reference={section-1}]
\input ward
\stoptext
这是您的代码的稍短版本,使用 Lua 解析章节标题并使用 MetaPost 绘图直接作为页面文本层的背景。
\definepapersize
[BookPaperSize]
[width=8in,
height=6in]
\setuppapersize[BookPaperSize]
\defineoverlay
[BookTimelineOverlay]
[\useMPgraphic{BookTimelineGraphic}]
\setupbackgrounds
[text]
[background=BookTimelineOverlay]
\startluacode
function userdata.parsetitle(title)
local a, b = string.match(title, "(%d+),(%d+)")
return table.concat({ a, b }, "")
end
\stopluacode
\startuseMPgraphic{BookTimelineGraphic}
% Define constants
numeric EVENT_BEGAN;
EVENT_BEGAN := 13799;
% Convert the digits from a string to a numeric value.
numeric eventX;
eventX := lua("mp.print(userdata.parsetitle('\getspecificstructuretitle{3}'))") ;
eventX := 1 - (eventX / EVENT_BEGAN);
numeric wb, hb ; wb := 3.33in ; hb := .33in ;
pickup pencircle scaled 2pt;
picture p ; p := image(
% Draw the line.
draw (0, .5*hb) -- (wb, .5*hb) ;
% Draw starting |.
draw (0, 0) -- (0, hb) ;
% Draw ending |.
draw (wb, 0) -- (wb, hb) ;
% Draw the timeline's dot relative to the event on the timeline.
filldraw fullcircle scaled 9 shifted (eventX * wb, .5*hb);
);
numeric h ; h := OverlayHeight ;
draw p shifted (-.33in, h - hb - .33in);
setbounds currentpicture to OverlayBox ;
\stopuseMPgraphic
\starttext
\chapter[title={Inflation Theory},reference={inflation-theory}]
\section[title={13,799 ± 0.021},reference={section}]
\input ward
\chapter[title={First Stars},reference={first-stars}]
\section[title={13,689 ± 70},reference={section-1}]
\input ward
\stoptext
答案2
Henri 已经回答了如何修复移位。我将回答您的附加问题,即如何简化代码。为此,我将使用视觉计数器模块。
首先,我定义一个新的 visualcounter 名为progressmarker
:
\usemodule[visualcounter]
\definevisualcounter
[progressmarker]
[
mp=visualcounter::progressmarker,
width=\the\dimexpr\textwidth/2\relax,
height=4ExHeight,
rulethickness=2bp,
mpsetups=visualcounter::markers:circle,
]
\startuseMPgraphic {visualcounter::progressmarker}
begingroup;
\includeMPgraphic{visualcounter::initialization}
\includeMPgraphic{\visualcounterparameter{mpsetups}}
shift := (current_counter-1)/(last_counter-1);
newpath boundary;
boundary := (0,-height/2) -- (width,-height/2) -- (width,height/2) -- (0, height/2) -- cycle;
newpath pastline;
pastline := (0, 0) -- (shift*width, 0);
newpath futureline;
futureline := (shift*width, 0) -- (width, 0);
drawoptions(withpen pencircle scaled rulethickness);
linecap := butt;
draw leftboundary boundary withcolor past_color;
draw rightboundary boundary withcolor future_color;
draw pastline withcolor past_color;
draw futureline withcolor future_color;
drawoptions();
show_marker(height/2, shift*width, active_color);
setbounds currentpicture to boundary ;
endgroup;
\stopuseMPgraphic
可以按如下方式使用:
\starttext
\startTEXpage[offset=2mm]
\usevisualcounter[n=4, last=10]{progressmarker}
\stopTEXpage
\stoptext
这使:
颜色有点不对,因为它使用的是 visualcounter 的默认调色板。为了获得单一的纯色,我们更改了调色板:
\definepalet[blue][past=blue, active=blue, future=blue]
\setupvisualcounter[progressmarker][palette=blue]
这使:
因此,只需将其插入部分计数器即可。可以使用以下方法完成此操作:
\definevisualcounter
[visualsection]
[progressmarker]
[
n={\somenamedheadnumber{section}{current}},
last={\somenamedheadnumber{section}{last}},
]
\setuphead[section]
[after={\usevisualcounter{visualsection}}]
\starttext
\startTEXpage[offset=2mm]
\startsection[title=Inflation Theory]
\input ward
\stopsection
\startsection[title=First Starts]
\input ward
\stopsection
\startsection[title=Second Starts]
\input ward
\stopsection
\stopTEXpage
\stoptext