「CodeMirror」でリアルタイムに同時に、エディタ編集中の他の人(他クライアント)のカーソル(キャレット)の位置を表示する方法を説明します。
本記事の内容を応用すれば、下図のような感じで、他のクライアントのカーソルの位置を様々な色で表示することも可能です。
この機能は、富士通研究所のOSSであるMarkdownベースのコラボレーションツール**「Cattaz」**に実装しています。
前置き
カーソルを表示する部分に焦点を当て説明するため、以下の説明については省略します。
- CodeMirrorエディタの入力イベントの取得
- CodeMirrorエディタ間の通信
方法
CodeMirrorの以下のAPIを利用します。
このAPIを利用することで、自ら生成したDOMノード(マーカー/表示したいデザイン)をエディタ上の指定した位置に挿入できます。
つまり、他クライアントから送られてきたカーソルの位置情報の場所に、何かしらスタイルを装飾したDOMノードを追加できます。
それにより、他クライアントのカーソル位置を表示することができます。
以下に、DOMノードを生成して、そのDOMノードを指定したエディタ上の位置に「setBookmark」でセットするコードの例を示します。
(ES2015(ES6)でのコードの書き方で説明)
// cm:CodeMirrorのインスタンス
// cursorPos:他クライアントから送られてきたカーソルの位置(CodeMirrorにおける {line, ch} のこと)
// DOMノード(マーカー/表示したいデザイン)を生成
const cursorCoords = cm.cursorCoords(cursorPos);
const cursorElement = document.createElement('span');
cursorElement.style.borderLeftStyle = 'solid';
cursorElement.style.borderLeftWidth = '2px';
cursorElement.style.borderLeftColor = '#ff0000';
cursorElement.style.height = `${(cursorCoords.bottom - cursorCoords.top)}px`;
cursorElement.style.padding = 0;
cursorElement.style.zIndex = 0;
// 上記で生成したDOMノードを他クライアントから送られてきたカーソルの位置にセット
// setBookmarkの第1引数:他クライアントから送られてきたカーソルの位置
// 第2引数内のwidget:生成したDOMノード
marker = cm.setBookmark(cursorPos, { widget: cursorElement });
DOMノード生成の部分は、自分の好きなようなスタイルにすると、かっこよくできます。
上記の例は、普通のカーソルのような縦線のデザインです。
setBookmarkで付加したDOMノードは、そのままですとエディタ上の挿入した位置に残り続けるため、他のクライアントからカーソル位置が送られてくる度に、一度以下のようにsetBookmarkのclear()メソッドで挿入したDOMノードを削除し、それから新規にDOMノードを再度挿入すると良いです。
// 挿入したDOMノードのクリア
// marker:setBookmarkのインスタンス
marker.clear();
処理の一連の流れ
処理の大まかな一連の流れの例は以下です。
- CodeMirrorエディタの入力イベントからカーソルの位置を取得する
- 取得したカーソルの位置を Websocket通信などを用いて他クライアントへ送信する
- 他クライアントから送られてきたカーソルの位置を受信したクライアントは、前にsetBookmarkで挿入したDOMノードが存在していたら削除する
- 受信したカーソルの位置に、マーカーとなるDOMノードをsetBookmarkで挿入する
また、各クライアントから受信したカーソル位置を各クライアントごとに管理すれば、複数のクライアントのカーソルを同時に表示できるようになります。
まとめ
以上のようにして、CodeMirrorのAPIの**「setBookmark」**を利用すれば、他クライアントのカーソルの位置を表示できます。
この機能は「Cattaz」にも実装していますので(2018年1月9日現在)、そちらのソースコードも見ると参考になるかもしれません。