tableタグを2次元で表現するプログラムを作成する。
rowspanやcolspanも加味して考える。
##目次
・セルを1で表現するプログラム
・列番号で表現するプログラム
##1. セルを1で表現するプログラム 実際のブラウザ上の表示に合わせて、セルがある場所を1で埋めて表を表現する。
###完成イメージ
例えば3行3列の表なら以下のように出力する。
arr = [
[1, 1, 1]
[1, 1, 1]
[1, 1, 1]
]
**▼結合がある場合1**
結合がある場合セルの数(tdタグ)は減るが、colspanやrowspanに合わせて1を埋める。
arr = [
[1, 1, 1]
[1, 1, 1]
[1, 1, 1]
]
**▼結合がある場合の例2**
arr = [
[1, 1, 1]
[1, 1, 1, 1]
[1, 1, 1, 1, 1]
]
##コード
処理には、HTMLTableElementを利用する。
HTMLTableElementはtableタグをオブジェクトに変換しjsで処理できるAPI。
function scanTable(table)
{
var arr = [];
for(var y=0; y<table.rows.length; y++)
{
var row = table.rows[y];
for(var x=0;x<row.cells.length;x++)
{
var cell = row.cells[x], xx = x, tx, ty;
for(; arr[y] && arr[y][xx]; ++xx);
for(tx = xx; tx < xx + cell.colSpan; ++tx)
{
for(ty = y; ty < y + cell.rowSpan; ++ty)
{
if( !arr[ty] ) arr[ty] = [];
arr[ty][tx] = 1;
}
}
}
}
return arr
};
###コードの中身
▼変数
・arr
1が入る2次元配列。最終的なアウトプット。
・ty
1を入力する行番号
・tx
1を入力する列番号
・y
行番号
・x
列番号
・xx
1を入力するセルの列開始番号。
**▼主な処理**
for(var y=0; y<table.rows.length; y++)
{
var row = table.rows[y];
for(var x=0;x<row.cells.length;x++)
1行毎、1セル毎に処理を繰り返す。
x, yは結合を加味せず、1づつ増えていく。
・`for(; arr[y] && arr[y][xx]; ++xx);` 1を挿入しようとしているセルに、結合などにより既に1が挿入されていないか判断。
既に1が挿入してある場合は、隣のセルに移動(xxを1増やす)
・for(tx = xx; tx < xx + cell.colSpan; ++tx)
列方向の結合状況を加味する処理。cospanの分だけ、列方向に1を入力するセルを増やす。
・for(ty = y; ty < y + cell.rowSpan; ++ty)
行方向の結合状況を加味する処理。rowspanの分だけ、行方向に1を入力するセルを増やす。
・if( !arr[ty] ) arr[ty] = [];
行方向の結合(rowspan > 1)があった場合に、まだその行が定義されていない場合は、空のオブジェクトを生成する。
これがないと、rowspan > 1 の時にエラーが発生する。
Cannot set property '0' of undefined
//undefinedのプロパティ0には値をセットできない
##2. 列番号で表現するプログラム 結合によりセルの列番号がズレるが、**ズレが発生した場合に各セルの見た目の列番号を取得する**プログラム。
先ほどは見た目を1で表現したが、今回はセルを基準にして表示する。
###完成イメージ
arr = [
[0, 1, 2]
[0, 1, 2]
[0, 1, 2]
]
**▼結合がある場合1** ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/e945db5a-ed52-dc50-0445-0f190e1286bc.png)
arr = [
[0, 1, 2]
[1, 2]
[0, 1, 2]
]
2行目のセルが2つになっている状態。実際のセルの行列番号は (1, 0) だが、見た目の列番号は1から始まる。
**▼結合がある場合2** ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/173973d9-dd16-9b66-ab89-e27f264af1a1.png)
arr = [
[0, 1, 2]
[1, 2, 3]
[0, 3, 4]
]
##コード
function scanTable2(table)
{
var arr = [];
const colIndices = [];
for(var y=0; y<table.rows.length; y++)
{
var row = table.rows[y];
for(var x=0;x<row.cells.length;x++)
{
var cell = row.cells[x], xx = x, tx, ty;
for(; arr[y] && arr[y][xx]; ++xx); // skip already occupied cells in current row
for(tx = xx; tx < xx + cell.colSpan; ++tx) // arrark arratrix elearrents occupied by current cell with true
{
for(ty = y; ty < y + cell.rowSpan; ++ty)
{
if( !arr[ty] ) arr[ty] = []; // fill arrissing rows
arr[ty][tx] = 1;
if ( !colIndices[y] ) colIndices[y] = [];
colIndices[y][x] = xx;
}
}
}
}
return colIndices;
};
9割は前述の表を1で表現するプログラムと同じ。追加した処理は以下3行のみ。
const colIndices = [];
if ( !colIndices[y] ) colIndices[y] = [];
colIndices[y][x] = xx;
列番号を格納する変数colIndicesを作成し、セル番号に合わせて、変数xxを格納している。
x = row.cells.length
であり、何番目のセルかを表している。
xx
は配列arrで1を格納するセルの開始番号を表してる。つまり結合によりセルがズレていれば、ズレも加味した列数を指す値となっている。