generated at
scrapboxのcursorの位置を計算する
タイトル通り

用途
ScrapVimでcursorの座標計算を行う
先頭から何文字目なのかとか
あとはどの文字が何番目にあるのかも取得したい
実装するmethodは他の機能を実装しながら考える
必要になったものを順次実装する

参考にするcode
今まで作ってきたやつ
一旦文字列に変換してから比較しているが、それを変更して、直接DOMの座標を比較するようにした
文字列→DOM→文字列の二度手間を避ける
Referene


実装
classではなく関数で実装する
classにする意義を感じられなかった
cursor には .cursor の縦棒を送る
#text-input だと選択範囲があるときにうまく認識できない
完成したので別なページに載せる
getCursorInfo.js
export function getCursorInfo({lines, cursor}) { // cursorのいる行を取得する const cursorLine = lines.getElementsByClassName('cursor-line')?.[0]; if (!cursorLine) return {error: 'The cursor doesn\'t has a focus.'}; // 行内の文字を<span>のまま取得する const chars = [...cursorLine.querySelectorAll('span[class^="c-"]')];
developper toolで確認したところ、 left の値が同一だった
等号比較で行けるか?
find で簡単に検索したい
js
const targetChar = chars.find(char => cursor.getBoundingClientRect().left === char.getBoundingClientRect().left);
21:13:31 同一でない文字もあるみたい。
全部確認して、一番近いcharを取得するしかなさそう
21:20:20 cursor.getBoundingClientRect().left char.getBoundingClientRect() left right の中に収まっているものを探すのならどうだ?
done21:24:27 やった!
21:30:31 行先頭の文字番号がおかしい?
0, 0, 1, ... になる
調べる
どうやら cursor.getBoundingClientRect().left よりも該当文字の getBoundingClientRect().left が左にずれている場合があるみたい
どれも小数点以下でずれている
整数値に丸めたらどうなんだろう?
21:46:52 うまくいった
判定は半開区間にした
[..., ...[
閉区間にすると、後ろの <span> とかぶってしまう
21:58:59 これでもだめなやつがあった
おそらく発生条件
indentあり
先頭が全角文字
半開区間に直すのを忘れてただけだった
22:06:57 最後にcursorが来たら、 \n にcursorがあると解釈しよう
最後の .c-{number} に1足したものを返す
getCursorInfo.js
// cursorのいる<span>を検索する const cursorLeft = Math.round(cursor.getBoundingClientRect().left); const targetChar = chars.find(char => { const {left, right} = char.getBoundingClientRect(); return Math.round(left) <= cursorLeft && cursorLeft < Math.round(right);}); return { id: cursorLine.id, column: targetChar? parseInt(targetChar.className.replace(/c-(\d+)/,'$1')) : chars.length, // 改行文字として、最後の文字より一つ後ろの番号を返す }; }

テストコード
js
function getCursorInfo({lines, cursor}) { // cursorのいる行を取得する const cursorLine = lines.getElementsByClassName('cursor-line')?.[0]; if (!cursorLine) return {error: 'The cursor doesn\'t has a focus.'}; // 行内の文字を<span>のまま取得する const chars = [...cursorLine.querySelectorAll('span[class^="c-"]')]; // cursorのいる<span>を検索する console.log('char pos.: %o', chars .map(char => char.getBoundingClientRect()) .map(rect => {return {left: Math.round(rect.left), right: Math.round(rect.right)}})); const cursorLeft = Math.round(cursor.getBoundingClientRect().left); console.log('cursor left: %o', cursorLeft); const targetChar = chars.find(char => { const {left, right} = char.getBoundingClientRect(); return Math.round(left) <= cursorLeft && cursorLeft < Math.round(right);}); return { id: cursorLine.id, column: targetChar? parseInt(targetChar.className.replace(/c-(\d+)/,'$1')) : chars.length, // 改行文字として、最後の文字より一つ後ろの番号を返す }; } addEventListener('keydown',e=>{ console.log(`char info: %o`,getCursorInfo({lines:document.getElementsByClassName('lines')[0],cursor:document.getElementsByClassName('cursor')[0]})) })
hr
classの名前でいい感じのが見つかったら、別のページに移す
computeCursor.js_disabled
export class cursorLocator { constructor() { this._editor = document.getElementById('editor'); this._lines = this._editor.getElementsByClassName('lines')[0]?.children; } // cursorがどこかにいるかどうかを返す hasFocus() { return !!this._cursorLine; } // cursorがいる行の行番号と行idを返す // タイトル行を0行目とする // @return {index:number; id:string}? get line() { const currentLine = this._cursorLine; return {index: [...this._lines].indexOf(currentLine), id: this.currentLine.id}; }
cumputeCursor.js_disabled
// cursorのいる行のDOMを取得する get _cursorLine() { return this._lines.getElementsByClassName('cursor-line')[0]; } }
行から文字の座標を取得するのは別のclassに分離するか?
computeChar.js_disabled
export class charLocator { constructor() { this._editor = document.getElementById('editor'); }
computeChar.js_disabled
// 指定した文字に一致する<span>を探し、はじめに見つかった文字の位置を返す // @return {index:number; position: {top,left,right,bottom}}? findChar(char) {} }

#2020-11-15 18:22:22