scrapbox-position
指定した座標にあるscrpabox editor上の諸々の情報を取得する函数群
内容物
getBorder({x,y})
指定した座標に一番近い文字境界を取得する
cursorや選択範囲の端など、ほぼ文字境界に位置する座標に対して用いる
引数
x
: ページの可視領域の左上を原点とした座標系でのx成分
y
: ページの可視領域の左上を原点とした座標系でのy成分
返り値
tstype Return = {
left?: CharObject; //境界の左側の文字
right?: CharObject; //境界の右側の文字
line: LineObject; // 文字がいる行
} |{
line: LineObject;
message: 'No char found';
} | {
message: 'No line found.' | 'No border matched.';
};
行頭や行末など、片側の文字がないときはundefinedが入る
境界が見つからなかったときはすべてundefinedになる
getLine({y})
指定した座標上にある行のDOMを取得する
引数
y
: ページの可視領域の左上を原点とした座標系でのy成分
返り値
LineObject | undefined
行がなかったらundefinedになる
dependencies
script.jsimport {char as c} from '/api/code/programming-notes/scrapbox-char-accessor/script.js';
import {line as l} from '/api/code/programming-notes/scrapbox-line-accessor/script.js';
const scrapboxDOM = {
lines: document.getElementsByClassName('lines')?.[0],
};
script.jsexport function getBorder({x, y}) {
const line = getLine({y});
if (!line) return {message: 'No line found.'};
const chars = [...line.DOM.querySelectorAll('span[class^="c-"]')];
if (chars.length === 0) return {line, message: 'No char found'};
// 文字境界のリストを作る
const borders = [...chars.map((char, i, charList) => {
return {left: i === 0 ? undefined : charList[i - 1], right: char};
}), {left: chars.pop(), right: undefined}];
//console.log({borders});
境界の判定方法
それぞれの文字の中間を判定領域の端とする
行頭や行末など、どちらかの文字がない場合は、一方の文字の width
の値を用いる
script.js const matchedBorders = borders
.flatMap(({left: lChar, right: rChar}) => {
const lRect = lChar?.getBoundingClientRect?.() ?? rChar.getBoundingClientRect();
const rRect = rChar?.getBoundingClientRect?.() ?? lChar.getBoundingClientRect();
const left = (lChar ? lRect.left : lRect.left - lRect.width) + lRect.width / 2;
const right = (rChar ? rRect.left : rRect.right) + rRect.width / 2;
//console.log({left, right});
if (left <= x && x < right) return [{left: c(lChar), right: c(rChar)}];
return [];
});
if (matchedBorders.length === 0) return {line, message: 'No border matched.'};
if (matchedBorders.length === 1) return {line, ...matchedBorders[0]};
もし複数の文字が見つかったら、 y
から絞り込みをかける
18:33:52
絞り込みに失敗しているようだ y
の値が境界ギリギリだったからみたい
script.js const lineRect = line.DOM.getBoundingClientRect();
const border = matchedBorders
.map(({left, right}, i) => {
const lTop = left?.DOM?.getBoundingClientRect?.()?.top ?? lineRect.top;
const rTop = right?.DOM?.getBoundingClientRect?.()?.top ?? lineRect.top;
const top = i === 0 ? lineRect.top : Math.max(lTop, rTop);
return {left, right, top};
})
.find(({top}, i, list) => top <= y && y < (list[i + 1]?.top ?? lineRect.bottom));
if (border) return {line, left: border.left, right: border.right};
return {line, message: 'No border matched.'};
}
script.jsexport function getLine({y}) {
return l([...scrapboxDOM.lines.children].find(line =>{
const rect = line.getBoundingClientRect();
return rect.top <= y && y < rect.bottom;
}));
}