3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jspreadsheet 使い方メモ1(基本)

Last updated at Posted at 2024-12-08

はじめに

これは、Jspreadsheet Advent Calendar 2024の8日目の記事となります。

Handsontable 使い方メモ1(基本)」と比較しながら書いていきます。

Hello World

導入と設定

実装

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Jspreadsheet</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jspreadsheet-ce/dist/jspreadsheet.min.css" media="screen">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jsuites/dist/jsuites.min.css" type="text/css" />
</head>
<body>
  <div id="grid"></div>
  <script src="https://cdn.jsdelivr.net/npm/jspreadsheet-ce/dist/index.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/jsuites/dist/jsuites.min.js"></script>
  <script type="text/javascript">
    // 以降の記載をここを埋める -->
  </script>
</script>
</body>
</html>
var data = [
  [ '佐藤', 28 ],
  [ '鈴木', 19 ],
  [ '田中', 25 ]
];

var grid = document.getElementById('grid');

new jspreadsheet(grid, {data: data});

実行結果

image.png

説明

  • 以下の4つのファイルを読み込む
    • jspreadsheet-ce/dist/index.min.js
    • jsuites/dist/jsuites.min.js
    • jspreadsheet-ce/dist/jspreadsheet.min.css
    • jsuites/dist/jsuites.min.css
  • グリッドを表示する場所として <div> タグを用意して、その Element オブジェクトを取得する
  • jspreadsheetnew してテーブルを作成する
    • コンストラクタ引数の第一引数に先ほど取得した Element オブジェクトを渡す
    • 第二引数にオプションを渡す
      • data オプションに、グリッドに表示するデータを渡す

Handsontableとの違い

  • Jspreadsheet は Jsuites に依存しているため、読み込みが必要となります
  • 行ヘッダーと列ヘッダーがデフォルト表示になっています

データソース

jspreadsheet では、配列やオブジェクトなど幾つかのデータを取り込むことができる。

配列

let data = [
  [ '佐藤', 28 ],
  [ '鈴木', 19 ],
  [ '田中', 25 ]
];

let grid = document.getElementById('grid');

new jspreadsheet(grid, {data: data});

image.png

  • 二次元配列を使用した最も基本的な方法

オブジェクト

let data = [
  { name: '佐藤', age: 25, a: 'A' },
  { name: '鈴木', age: 11, b: 'B' },
  { name: '田中', age: 21 }
];

let grid = document.getElementById('grid');

new jspreadsheet(grid, {data: data});

image.png

  • オブジェクトの配列も渡すことができる
  • 各プロパティから値が取得され、グリッドに表示される
  • どのプロパティが使用されるかは、先頭のオブジェクトで決まる模様

ネストされたオブジェクト

let data = [
  { name: {first: '佐藤', last: '一郎'}, age: 25 },
  { name: {first: '鈴木', last: '二郎'}, age: 11 },
  { name: {first: '田中', last: '三郎'}, age: 21 }
];

let grid = document.getElementById('grid');

new jspreadsheet(grid, {
  data: data,
  columns: [ // ★列のマッピングを定義できる
    { name: 'age' },
    { name: 'name.last' },
    { name: 'name.first' }
  ]
})

image.png

  • column オプションで、列ごとの細かい定義を宣言できる
  • columndata オプションで、その列に表示する値をオブジェクトのどのプロパティから取得するかを指定できる
  • ネストされたオブジェクトの場合は name.first のようにドット区切りでプロパティはCE版では指定できません

ネストされたオブジェクトは、Pro版では指定可能です。
https://jspreadsheet.com/docs/data

Handsontableとの違い

MIT(6.2.2)版でも、ネストされたオブジェクトの場合は name.first のようにドット区切りでプロパティを指定できる。

任意のオブジェクトを使う

JspreadsheetにはdataSchema属性はない。

CE版では非対応
Handsontable - 任意のオブジェクトを使う

空のグリッドを作る

let grid = document.getElementById('grid');

new jspreadsheet(grid, {
  data: [{}],
  columns: [
    { name: 'name' },
    { name: 'age' }
  ],
  minSpareRows: 1
})

image.png

  • columns で、列の順序を指定する
  • data に空のデータ配列を渡す
  • minSpareRows に最低限表示する行数を設定する

指定数の空のグリッドを作る

minDimensions に指定した行列数分の空グリッドを設定できる

let grid = document.getElementById('grid');

new jspreadsheet(grid, {
  minDimensions: [4,3]
})

image.png

Handsontableとの違い

JspreadsheetにはdataSchema属性はないため、data: []data: [{}] に変更

データとグリッドを切り離す

グリッドを再描画してもデータの変更が反映されないようにしたい場合は、コンストラクタ引数で渡す data をディープコピーにする方法がある。

ディープコピーを作る手段の1つとして、 JSON に一旦エンコードして、 JavaScript オブジェクトにデコードし直す方法がある。

let data = [
  [ '佐藤', 28 ],
  [ '鈴木', 19 ],
  [ '田中', 25 ]
];

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  // JSON 文字列にしてから JavaScript オブジェクトに戻す
  data: JSON.parse(JSON.stringify(data))
});

data.push([ '山田', 22 ]);

table.updateTable();

image.png

Handsontableとの違い

  • table.render() から table.updateTable() に変更
  • table.updateTable()は描画のみで、table.setData(data)としないとデータは更新されない

プラグイン

調査中

Handsontableとの違い

コメントはプラグインなしで標準機能として使用できる。

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5],
  allowComments: true
});

table.setComments([1, 1], 'This is a comment');

image.png

Hook(イベントハンドリング)

イベントハンドラを追加する

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5]
});

table.options.onselection = function(el, startRow, startCol, endRow, endCol) {
  console.log(`${startRow}, ${startCol}, ${endRow}, ${endCol}`);
};

onselection.gif

  • options.(指定イベント)でイベントハンドラを登録できる

Handsontableとの違い

  • hooksが無いため、optionsを使用する
  • 複数の jspreadsheet インスタンスによる全てのグリッドのイベントは監視できない、特定のグリッドのみ
  • afterSelection イベントはないため、onselection イベントに変更

イベントの種類

公式ドキュメント を参照

  • onafterchanges(records):変更後
  • onbeforechange(el, cell, x, y, value):変更前
  • oneditionend(el, cell, x, y, value, save):編集終了時
  • oneditionstart(el, cell, x, y):編集開始時
  • onbeforesave(el, obj, data):保存前
  • onsave(el, obj, data):保存時
  • onchange(el, cell, x, y, value, oldValue):変更時
  • onselection(el, borderLeft, borderTop, borderRight, borderBottom, origin):選択時
  • onsort(el, column, order):ソート時
  • onbeforeinsertcolumn(el, columnNumber, numOfColumns, insertBefore):カラム挿入前
  • oninsertcolumn(el, columnNumber, numOfColumns, historyRecords, insertBefore):カラム挿入時
  • onbeforedeletecolumn(el, columnNumber, numOfColumns):カラム削除前
  • ondeletecolumn(el, columnNumber, numOfColumns, historyRecords):カラム削除時
  • onmovecolumn(el, o, d):カラム移動時
  • onresizecolumn(el, column, width, oldWidth):カラムサイズ変更時
  • onbeforeinsertrow(el, rowNumber, numOfRows, insertBefore):行挿入前
  • oninsertrow(el, rowNumber, numOfRows, rowRecords, insertBefore):行挿入時
  • onbeforedeleterow(el, rowNumber, numOfRows):行削除前
  • ondeleterow(el, rowNumber, numOfRows, rowRecords):行削除時
  • onmoverow(el, o, d):行移動時
  • onresizerow(el, row, height, oldHeight):行サイズ変更時
  • onchangeheader(el, column, oldValue, newValue):ヘッダ変更時
  • onchangemeta(el, o, k, v):メタ情報変更時
  • onchangepage(el, pageNumber, oldPage):ページ変更時
  • onchangestyle(el, o, k, v):スタイル変更時
  • oncomments(el, comments, title, cell, cell[0], cell[1]):コメント変更時
  • oncreateeditor(el, cell, x, y, editor):エディタ作成時
  • onblur(el):フォーカスを失う時
  • onfocus(el):フォーカスがあたる時
  • onload(el, obj):ロード時
  • onmerge(el, cellName, colspan, rowspan):マージ時
  • oncopy(el, row, hashString):コピー時
  • onbeforepaste(el, data, x, y):ペースト前
  • onpaste(el, data):ペースト時
  • onundo(el, historyRecord):アンドゥ時
  • onredo(el, historyRecord):リドゥ時

イベントハンドラを削除する

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5]
});

table.options.onselection = function(el, startRow, startCol, endRow, endCol) {
  console.log(`${startRow}, ${startCol}, ${endRow}, ${endCol}`);
};

document.getElementById('remove').addEventListener('click', function () {
  table.options.onselection = null;
});

removehook.gif

  • options.(指定イベント) に null でイベントハンドラを削除できる

登録されているイベントハンドラを取得する

Handsontableのhooks.getBucket メソッドと同じものは存在しないため、個別にメソッドを作成する必要がある。

一度だけ実行されるイベントハンドラを登録する

Handsontableのhooks.once メソッドと同じものは存在しないため、個別にメソッドを作成する必要がある。

任意のイベントを発火させる

Handsontableのhooks.run メソッドと同じものは存在しないため、個別にメソッドを作成する必要がある。
カスタムイベントを直接作成する機能は標準で提供されていないため、JavaScript の標準機能を利用してカスタムイベントを作成する。

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5]
});

// 独自のイベントハンドラを登録
table.el.addEventListener('onButtonClick', function(e) {
  console.log('click!!');
});

document.getElementById('button').addEventListener('click', function () {
  // イベントを発火
  table.el.dispatchEvent(new CustomEvent('onButtonClick'));
});

image.png

イベントハンドラに値を渡す

detail プロパティに、渡したい任意の値を含めることで実現しています。
ここでは、foo と bar という値を含めています。

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5]
});

// 独自のイベントハンドラを登録
table.el.addEventListener('onButtonClick', function(e) {
  console.log('click!!', e.detail);
});

document.getElementById('button').addEventListener('click', function () {
  // イベントを発火
  table.el.dispatchEvent(
    new CustomEvent('onButtonClick',{ detail: { foo: 'Hello', bar: 'World' }})
  );
});
実行結果
click!! ▶︎ {foo: 'Hello', bar: 'World'}

キーコード

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5],
});

// キーダウンのイベントハンドラを登録
table.el.addEventListener('keydown', function(e) {
  if (e.keyCode === KEY_CODES.SPACE) {
    console.log('space!');
  } else if (isKey(e.keyCode, 'ARROW_LEFT|ARROW_RIGHT')) {
    console.log('left or right!!');
  }
});

const KEY_CODES = {
  ARROW_LEFT: 37,
  ARROW_RIGHT: 39,
  SPACE: 32
}

function isKey(keyCode, baseCode) {
  const keys = baseCode.split('|');
  let result = false;
  
  keys.forEach((key) => {
    if (keyCode === KEY_CODES[key]) {
      result = true;

      return false;
    }
  });
  
  return result;
}

keycode.gif

  • beforeKeyDownイベントがないため、keydownイベントを登録して使用する
  • KEY_CODES に、よく使いそうなキーコードを定義する
  • isKey() メソッドを使えば、 | 区切りで複数のキーのいずれかが入力されたことをチェックできる

Handsontableとの違い

Editor

調査中、これが分かれば Jsuites のような部品を作るようになりそうです。

最後に

思っている以上に Handsontable なら存在するメソッドが不足している気がします。
参考になりそうなコードも少ないため、解析しながら作成していく必要がありますね。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?