BaseSVGLine
专为 SVG 的线类元素打造。继承自 sd.BaseSVG。在线类元素上可以存在一个价值物(value)。这是一个抽象类,不应该被实例化。
API 列表
class BaseSVGLine extends BaseSVG {
constructor(target: SDNode | RenderNode, tag: string);
markerStart(): string;
markerStart(marker: string): this;
markerMid(): string;
markerMid(marker: string): this;
markerEnd(): string;
markerEnd(marker: string): this;
arrow(arrow?: boolean | undefined | null): this;
revArrow(arrow?: boolean | undefined | null): this;
doubleArrow(arrow?: boolean | undefined | null): this;
pointStoT(): this;
pointTtoS(): this;
fadeStoT(): this;
fadeTtoS(): this;
at(k: number): [number, number];
getPointAtLength(length: number): [number, number];
totalLength(): number;
text(): string;
text(text: string): this;
intValue(): number;
value(): SDNode | undefined;
value(value: any, rule?: SDRule): this;
valueFromExist(value: SDNode, rule?: SDRule): this;
drop(): SDNode;
}
markerStart & markerMid & markerEnd
class BaseSVGLine {
markerStart(): string;
markerStart(marker: string): this;
markerMid(): string;
markerMid(marker: string): this;
markerEnd(): string;
markerEnd(marker: string): this;
}
在 SVG 中,可以为线类元素上的起点位置、路径的所有中间顶点、终点位置添加标记(marker),标记的样式是自定义的。目前画布中自带了两种样式:arrow,adaptiveArrow。
const svg = sd.svg();
const styles = ["arrow", "adaptiveArrow"];
const lines = [];
styles.forEach((style, i) => {
const line = new sd.Line(svg);
line.source(0, i * 40);
line.target(200, i * 40);
line.markerStart(style).markerEnd(style);
// 对于 sd.Line 而言,markerMid 是无效的,因为路径没有中间顶点
lines.push(line);
});
sd.main(async () => {
await sd.pause();
lines.forEach(line => {
line.startAnimate().strokeWidth(3).endAnimate();
});
});
试一试,adaptive 表示这个标记的大小会随着线段的粗细而变化。
arrow & revArrow & doubleArrow
class BaseSVGLine {
arrow(arrow?: boolean | undefined | null): this;
revArrow(arrow?: boolean | undefined | null): this;
doubleArrow(arrow?: boolean | undefined | null): this;
}
管理箭头的设置,分别表示正向箭头,反向箭头,双向箭头。其内部是通过设置 marker 来实现的。
const svg = sd.svg();
const l1 = new sd.Line(svg).x(100).y(100);
const l2 = new sd.Line(svg).x(200).y(100);
const l3 = new sd.Line(svg).x(300).y(100);
sd.main(async () => {
await sd.pause();
l1.arrow();
l2.revArrow();
l3.doubleArrow();
});
pointStoT & pointTtoS & fadeStoT & fadeTtoS
class BaseSVGLine {
pointStoT(): this; // 从起点到终点浮现
pointTtoS(): this; // 从终点到起点浮现
fadeStoT(): this; // 从起点到终点消失
fadeTtoS(): this; // 从终点到起点消失
}
用于让线类元素的出现和消失更加丝滑。内部是通过 strokeDashArray 和 strokeDashOffset 实现的。
const svg = sd.svg();
const l1 = new sd.Line(svg).opacity(0).source(0, 0).target(100, 0);
const l2 = new sd.Line(svg).opacity(0).source(0, 40).target(100, 40);
const l3 = new sd.Line(svg).source(0, 80).target(100, 80);
const l4 = new sd.Line(svg).source(0, 120).target(100, 120);
sd.main(async () => {
await sd.pause();
l1.opacity(1).startAnimate().pointStoT().endAnimate();
l2.opacity(1).startAnimate().pointTtoS().endAnimate();
l3.startAnimate().fadeStoT().endAnimate();
l4.startAnimate().fadeTtoS().endAnimate();
});
at & getPointAtLength & totalLength
class BaseSVGLine {
at(k: number): [number, number]; // 获取路径上占总长比值为 k 的点的位置,0<=k<=1
getPointAtLength(length: number): [number, number]; // 获取路径上,距离起点 length 的点
totalLength(): number; // 获取路径总长度
}
用于获取线类元素上的轨迹信息。
text
class BaseSVGLine {
text(): string;
text(text: string): this;
}
管理 value 的文本。当且仅当 value 是文本元素时才有效。
const svg = sd.svg();
const line1 = new sd.Line(svg, "A");
const line2 = new sd.Line(svg, new sd.Rect(svg).width(12).height(12)).x(100);
console.log(line1.text()); // "A"
// console.log(line2.text()); // this is invalid invoke
sd.main(async () => {
await sd.pause();
line1.text("B");
});
intValue
class BaseSVGLine {
intValue(): number;
}
将 value 对应的文本解析为整数类型,并返回。如果 value 不存在,或者对应的文本是空串,则会解析为整数 0。在解析其他非数值文本的情况下会抛出错误。
const svg = sd.svg();
const line1 = new sd.Line(svg, "1");
const line2 = new sd.Line(svg, "1.8").x(100);
const line3 = new sd.Line(svg).x(200);
const line4 = new sd.Line(svg, "A").x(300);
console.log(line1.intValue()); // 1
console.log(line2.intValue()); // 1
console.log(line3.intValue()); // 0
// console.log(line4.intValue()); // this is invalid invoke
value & valueFromExist
class BaseElement {
value(): SDNode | undefined;
value(value: any, rule?: SDRule): this;
valueFromExist(value: SDNode, rule?: SDRule): this;
}
管理 value 节点。可以在添加 value 节点时使用自定义布局规则,若不提供则使用默认规则(即把 value 放在路径中点位置)。
const svg = sd.svg();
const EN = sd.enter();
const svg = sd.svg();
const EN = sd.enter();
const line1 = new sd.Line(svg);
const line2 = new sd.Line(svg).x(100);
const line3 = new sd.Line(svg).x(200);
const line4 = new sd.Line(svg).x(300);
const value2 = new sd.Text(svg, "B").cy(100).cx(line2.cx());
const value3 = new sd.Circle(svg).r(5).cy(100).cx(line3.cx());
const value4 = new sd.Text(svg, "C").cy(100).cx(line4.cx());
sd.main(async () => {
await sd.pause();
line1.startAnimate().value("A").endAnimate();
line2.startAnimate().value(value2).endAnimate();
line3.startAnimate().value(value3.onEnter(EN.moveTo())).endAnimate();
line4.startAnimate().valueFromExist(value4).endAnimate();
});
试一试,前两个 line 中,value 是浮现在 box 的正中心的;而后两个 line 中,value 是从自己原本的位置平移过去的。这就是 value 和 valueFromExist 的区别。valueFromExist 会指定 value 进入元素的方式是从当前位置平移过去。
如果一个线类元素已存在 value 的情况下设置其 value,则原来那个 value 会被删掉,这里的删除将会导致原始 value 永远地离开场景。
const svg = sd.svg();
const line = new sd.Line(svg, "A");
sd.main(async () => {
await sd.pause();
line.startAnimate().value("B").endAnimate(); // "A" 被删除
await sd.pause();
line.startAnimate().value(null).endAnimate(); // "B" 被删除
});
drop
class BaseElement {
drop(): SDNode;
}
前文提到,如果 value 方法去删除已存在的 value,会导致 value 永远地离开场景,但部分情况下,我们可能希望被删除的 value 只是被元素丢弃了,它仍然存在于场景之中。有两种达成这个目的的解决方案,最直接的便是 drop 方法。
const svg = sd.svg();
const EX = sd.exit();
const line11 = new sd.Line(svg, "A");
const line12 = new sd.Line(svg).x(100);
const line21 = new sd.Line(svg, "B").y(50);
const line22 = new sd.Line(svg).x(100).y(50);
sd.main(async () => {
await sd.pause();
line12.startAnimate().valueFromExist(line11.drop()).endAnimate(); // 直接使用 drop 方法丢弃 box11 中的 value
const b = line21.value().onExit(EX.drop()); // 设置 box21 的 value 以 drop 的形式从 box21 中删除
line21.value(null); // 删除 box21 中的 value
line22.startAnimate().valueFromExist(b).endAnimate();
});
试一试,在上例中,当 line11 或者 line21 中的 value 被删除时,它们并不会被移除到场景之外,而仅仅是被元素所丢弃了。所以我们能在之后的代码中,将这两个 value 分别转交给 line12 和 line22。