【JS】表 (table)のHTMLを２次元配列に変換するプログラム

tableタグを２次元で表現するプログラムを作成する。
rowspanやcolspanも加味して考える。


##目次

[・セルを１で表現するプログラム](#1-セルを１で表現するプログラム)
[・列番号で表現するプログラム](#2-列番号で表現するプログラム)


<br>
##1. セルを１で表現するプログラム
実際のブラウザ上の表示に合わせて、セルがある場所を1で埋めて表を表現する。

###完成イメージ
例えば3行3列の表なら以下のように出力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/72ee623e-d980-28c9-5c8c-a89abadb648b.png)

```js:
arr = [
  [1, 1, 1]
  [1, 1, 1]
  [1, 1, 1]
]
```


<br>
**▼結合がある場合１**

結合がある場合セルの数（tdタグ）は減るが、colspanやrowspanに合わせて1を埋める。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/8b1d5c48-bb33-c7a2-4e51-5ad4224a7494.png)

```js:
arr = [
  [1, 1, 1]
  [1, 1, 1]
  [1, 1, 1]
]
```

<br>
**▼結合がある場合の例２**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/86568fff-94ee-2da5-34b4-cbef1184a738.png)


```js:
arr = [
  [1, 1, 1]
  [1, 1, 1, 1]
  [1, 1, 1, 1, 1]
]
```



##コード
処理には、HTMLTableElementを利用する。

HTMLTableElementはtableタグをオブジェクトに変換しjsで処理できるAPI。

>＞ [HTMLTableElementの使い方](https://qiita.com/yuta-38/items/a60c1542b73159051e04)

<br>

```js:
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`  １が入る２次元配列。最終的なアウトプット。

・`ty` １を入力する行番号

・`tx` 1を入力する列番号

・`y`　行番号

・`x`　列番号

・`xx` １を入力するセルの列開始番号。



<br>
**▼主な処理**

```js:
for(var y=0; y<table.rows.length; y++)
    {
        var row = table.rows[y];

        for(var x=0;x<row.cells.length;x++)
```

1行毎、１セル毎に処理を繰り返す。
x, yは結合を加味せず、１づつ増えていく。


<br>
・`for(; arr[y] && arr[y][xx]; ++xx);`
１を挿入しようとしているセルに、結合などにより既に１が挿入されていないか判断。

既に１が挿入してある場合は、隣のセルに移動（xxを1増やす）


・`for(tx = xx; tx < xx + cell.colSpan; ++tx)`
列方向の結合状況を加味する処理。cospanの分だけ、列方向に１を入力するセルを増やす。



・`for(ty = y; ty < y + cell.rowSpan; ++ty)`
行方向の結合状況を加味する処理。rowspanの分だけ、行方向に１を入力するセルを増やす。

・`if( !arr[ty] ) arr[ty] = []; `
行方向の結合（rowspan > 1）があった場合に、まだその行が定義されていない場合は、空のオブジェクトを生成する。

**これがないと、rowspan > 1　の時にエラーが発生**する。

```:エラー
Cannot set property '0' of undefined

//undefinedのプロパティ0には値をセットできない
```





<br>
##2. 列番号で表現するプログラム
結合によりセルの列番号がズレるが、**ズレが発生した場合に各セルの見た目の列番号を取得する**プログラム。

先ほどは見た目を１で表現したが、今回はセルを基準にして表示する。


###完成イメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/08c853ea-fc9c-7667-c5bd-bb60b7aadb23.png)

```js:
arr = [ 
 [0, 1, 2]
 [0, 1, 2]
 [0, 1, 2]
]
```

<br>
**▼結合がある場合１**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/e945db5a-ed52-dc50-0445-0f190e1286bc.png)

```js:
arr = [ 
 [0, 1, 2]
 [1, 2]
 [0, 1, 2]
]
```

2行目のセルが２つになっている状態。実際のセルの行列番号は (1, 0) だが、見た目の列番号は１から始まる。

<br>
**▼結合がある場合２**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/173973d9-dd16-9b66-ab89-e27f264af1a1.png)

```js:
arr = [ 
 [0, 1, 2]
 [1, 2, 3]
 [0, 3, 4]
]
```


##コード

```js:
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;
};
```

９割は前述の表を１で表現するプログラムと同じ。追加した処理は以下3行のみ。



```js:追加コード
const colIndices = [];

if ( !colIndices[y] ) colIndices[y] = [];
colIndices[y][x] = xx;
```

列番号を格納する変数colIndicesを作成し、セル番号に合わせて、変数xxを格納している。

`x = row.cells.length`であり、何番目のセルかを表している。

`xx`は配列arrで１を格納するセルの開始番号を表してる。つまり結合によりセルがズレていれば、ズレも加味した列数を指す値となっている。