BaseGrid
这类节点拥有二维数组的结构,意味着可以用两个索引去获取其内部的每个元素。我们把二维数组称为网格。
网格内的每个元素被抽象为一个个 element。
这是一个抽象类,不应该被实例化。
API 列表
class BaseGrid extends SD2DNode {
// 索引管理
startN(): number;
startN(start: number): this;
startM(): number;
startM(start: number): this;
endN(): number;
endM(): number;
endM(i: number): number;
idxN(i: number): number;
idxM(j: number): number;
n(n: number): this;
m(m: number): this;
// 元素访问管理
element(i: number, j: number): SDNode;
forEachElement(callback: (element: SDNode, rowId: number, colId: number) => void): this;
// 元素属性管理
opacity(i: number, j: number): number;
opacity(i: number, j: number, opacity: number): this;
color(color: SDColor): this;
color(i: number, j: number): SDColor;
color(i: number, j: number, color: SDColor): this;
text(i: number, j: number): string;
text(i: number, j: number, text: string): this;
intValue(i: number, j: number): number;
value(i: number, j: number): SDNode;
value(i: number, j: number, value: any): this;
// 插入管理
insert(i: number, j: number, value?: any): this;
insertFromExistValue(i: number, j: number, value: SDNode): this;
insertFromExistElement(i: number, j: number, element: SDNode): this;
pushCol(): this;
pushCol(count: number): this;
pushRow(): this;
pushRow(count: number): this;
// 删除管理
erase(i: number, j: number): this;
dropElement(i: number, j: number): SDNode | undefined;
dropValue(i: number, j: number): SDNode | undefined;
popCol(): this;
popRow(): this;
}
索引管理
class BaseGrid {
startN(): number; // 获取第一维度起始索引
startN(start: number): this; // 设置第一维度起始索引
startM(): number; // 获取第二维度起始索引
startM(start: number): this; // 设置第二维度起始索引
endN(): number; // 获取第一维度结束索引
endM(): number; // 获取第二维度结束索引
endM(i: number): number; // 获取第一维度指定的第二维度的结束索引
idxN(i: number): number; // 将第一维度的逻辑索引转化为物理索引,对用户而言用不到
idxM(j: number): number; // 将第二维度的逻辑索引转化为物理索引,对用户而言用不到
n(): number; // 获取第一维度的长度
n(n: number): this; // 设置第一维度的长度
m(): number; // 获取第二维度的长度
m(m: number): this; // 设置第二维度的长度
}
上文提到的二维数组并不一定是规整的,例如,二维数组可能是这样的:
[
[1, 2, 3],
[4, 5],
[],
[6, 7, 8, 9]
];
我们用第一维度指外层数组,用第二维度指内层数组。对于第一维度而言,它一定只有一个长度,对于第二维度而言,它可能就有不同的长度了,所以 endM 相比于 endN 多了一种重载。
默认情况下,当我们说第二维度的长度,而没有指定具体第一维度时,我们在说第二维度最长的那个长度。例如上述二维数组的例子中,其第二维度的长度就是 4。
通过 n 和 m 这两个方法,我们可以很方便地初始化一个规整的二维数组出来。
const svg = sd.svg();
const grid = new sd.Grid(svg).n(3).m(6);
元素访问管理
class BaseGrid {
element(i: number, j: number): SDNode;
forEachElement(callback: (element: SDNode, rowId: number, colId: number) => void): this;
}
元素属性管理
各种各样的管理元素属性的方法。
opacity
class BaseGrid {
opacity(i: number, j: number): number; // 获取目标元素的透明度
opacity(i: number, j: number, opacity: number): this; // 设置目标元素的透明度
}
管理 element 的透明度。
color
class BaseGrid {
color(color: SDColor): this; // 设置每一个元素的颜色
color(i: number, j: number): SDColor; // 获取目标元素的颜色
color(i: number, j: number, color: SDColor): this; // 设置目标元素的颜色
}
管理 element 的颜色。
text
class BaseGrid {
text(i: number, j: number): string;
text(i: number, j: number, text: string): this;
}
管理 element 的文本。当 element 本身就是文本元素,或者 element 的 value 是文本元素时有效。
intValue
class BaseGrid {
intValue(i: number, j: number): number;
}
将 element 对应的文本解析为整数类型,并返回。如果 value 不存在,或者对应文本是空串,则会解析为整数 0。在解析其他非数值文本的情况下会抛出错误。
const svg = new sd.svg();
const grid = new sd.Grid(svg).insert(0, 0, "1").insert(0, 1, "2.8").insert(0, 2).insert(1, 0, "A");
console.log(grid.intValue(0, 0)); // 1
console.log(grid.intValue(0, 1)); // 2
console.log(grid.intValue(0, 2)); // 0
// console.log(grid.intValue(1, 0)); // this is an invalid invoke
value
class BaseGrid {
value(i: number, j: number): SDNode; // 获取目标元素的价值物
value(i: number, j: number, value: any): this; // 设置目标元素的价值物
}
管理 element 的 value。
插入管理
class BaseGrid {
insert(i: number, j: number, value?: any): this;
insertFromExistValue(i: number, j: number, value: SDNode): this;
insertFromExistElement(i: number, j: number, element: SDNode): this;
pushCol(): this;
pushCol(count: number): this;
pushRow(): this;
pushRow(count: number): this;
}
insert
insert 类型的插入需要指定插入的位置。有三种不同类型的 insert,下面演示它们的区别:
const svg = sd.svg();
const grid = new sd.Grid(svg).n(1).m(3);
const value1 = new sd.Circle(svg).cx(grid.element(0, 0).cx()).cy(120);
const value2 = new sd.Text(svg, "A").cx(grid.element(0, 1).cx()).cy(120);
const value3 = new sd.Box(svg, "B").cx(grid.element(0, 2).cx()).cy(120);
sd.main(async () => {
await sd.pause();
grid.startAnimate().insert(1, 0, value1).endAnimate();
await sd.pause();
grid.startAnimate().insertFromExistValue(1, 1, value2).endAnimate();
await sd.pause();
grid.startAnimate().insertFromExistElement(1, 2, value3).endAnimate();
});
pushCol & pushRow
我们把二维数组的第一维度中每个元素看作是一行(第一维度上每个元素是一个数组),第二维度中每个元素看作位于某列上(第二维度上每个元素是一个 element)。这两个 push 方法提供了快速添加一行一列的方案。
const svg = sd.svg();
const grid = new sd.Grid(svg).pushRow(3).pushRow(2).pushRow(1);
/*
[
[e, e, e],
[e, e],
[e]
]
*/
const svg = sd.svg();
const grid = new sd.Grid(svg).pushCol(3).pushCol(2).pushCol(1);
// pushCol(1).pushCol(2).pushCol(3) 的效果与 pushCol(3).pushCol(2).push(1) 是一样的
// 对 pushCol 而言,如果其作用于第一维度上的某个数组,则新元素会被附加到该数组的末尾
/*
[
[e, e, e],
[e, e],
[e],
]
*/
删除管理
用来删掉网格中的元素。
erase
class BaesGrid {
erase(i: number, j: number): this; // 删除目标元素
}
顾名意思,把某个 element 从网格中删除。默认情况下删除 element 会导致其永远地离开场景。
const svg = sd.svg();
const grid = new sd.Grid(svg).n(3).m(6);
sd.main(async () => {
await sd.pause();
grid.startAnimate().erase(1, 2).endAnimate();
});
drop
class BaseGrid {
dropElement(i: number, j: number): SDNode | undefined; // 丢弃目标元素
dropValue(i: number, j: number): SDNode | undefined; // 丢弃目标元素的价值物
}
前文提到,使用 erase 一类的方法去删除某个 element,会导致 element(及其内部的 value,如果有)永远地离开场景。但部分情况下,我们可能希望被删除的 element 或者 value 只是被网格丢弃了,它仍然存在于场景之中。有两种达成这个目的的解决方案,最直接的便是 drop 方法。下面的代码以交换两个网格中的元素为例进行演示:
const svg = sd.svg();
const EN = sd.enter();
const grid1 = new sd.Grid(svg).insert(0, 0, 1).insert(0, 1, 2).insert(0, 2, 3);
const grid2 = new sd.Grid(svg).y(100).insert(0, 0, "A").insert(0, 1, "B").insert(0, 2, "C");
function swapByValue(x) {
grid1.startAnimate();
grid2.startAnimate();
const v1 = grid1.dropValue(0, x);
const v2 = grid2.dropValue(0, x);
grid1.element(x).valueFromExist(v2);
grid2.element(x).valueFromExist(v1);
grid1.endAnimate();
grid2.endAnimate();
}
function swapByElement(x) {
grid1.startAnimate();
grid2.startAnimate();
const e1 = grid1.dropElement(0, x);
const e2 = grid2.dropElement(0, x);
grid1.insertFromExistElement(0, x, e2);
grid2.insertFromExistElement(0, x, e1);
grid1.endAnimate();
grid2.endAnimate();
}
sd.main(async () => {
await sd.pause();
swapByValue(2);
await sd.pause();
swapByElement(1);
});
试一试,dropValue 和 dropElement 的区别。
popRow & popCol
class BaseGrid {
popCol(): this; // 删掉最后一列
popRow(): this; // 删掉最后一行
}