論理
カスタム ロジックを提供しない限り、キャンバス上で個別の文字を処理することはできません。キャンバスに描画されたものはすべて、ピクセルのスープにマージされます。
残念ながら、テキストを純粋なパスとして追加することはできないため、ピクセル値を確認する必要があります。それ以外の場合は、テキストを新しいパスに追加し、isPointInPath
各文字に対してメソッドを使用するだけです。
1 つのアプローチ
SO で完全なソリューションを提供することはできませんが、キャンバス上の単一の文字をクリックするための基本的なロジックを提供するために構築できる基盤を次に示します。
- 各文字はオブジェクトを含めて保存されます。その位置、サイズ、フォント、および文字だけでなく、長方形のヒット領域もあります (以下を参照)
- これらのオブジェクトを使用して配列を定義し、レンダリング関数に渡します
- クリックを登録すると、配列を反復処理し、長方形のヒット領域に対してテストし、内部にある場合はピクセルをチェックします (*)
*) 重なっている文字を区別するには、優先度でチェックする必要があります。この char を別のキャンバスにレンダリングして、この char のみのピクセルを取得することもできます。デモではこれを示していませんが、アイデアは得られます。
デモ
var ltrs = []; /// stores the letter objects
/// Create some random objects
for(;i < 20; i++) {
/// build the object
var o = {char: alpha[((alpha.length - 1) * Math.random())|0],
x: ((w - 20) * Math.random())|0,
y: ((h - 20) * Math.random())|0,
size: (50 * Math.random() + 16)|0,
font: fonts[((fonts.length - 1) * Math.random())|0]};
/// store other things such as color etc.
/// store it in array
ltrs.push(o);
}
次に、これらの文字をレンダリングする関数があります (デモを参照)。
次に、クリックを処理するときに、オブジェクト配列を反復処理し、最初に境界をチェックして、現在の文字を確認します (ここでピクセルを選択しても、文字を識別できません)。
demo.onclick = function(e) {
/// adjust mouse position to be relative to canvas
var rect = demo.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top,
i = 0, o;
/// iterate
for(;o = ltrs[i]; i++) {
/// is in rectangle? "Older" letters has higher priority here...
if (x > o.x && x < (o.x + o.rect[2]) &&
y > o.y && y < (o.y + o.rect[3])) {
/// it is, check if we actually clicked a letter
/// This is what you would adopt to be on a separate canvas...
if (checkPixel(x, y) === true) {
setLetterObject(o, '#f00')
return;
}
}
}
}
ピクセル チェックは簡単です。x/y 位置で単一のピクセルを選択し、そのアルファ値 (または無地の背景を使用する場合は色)をチェックします。
function checkPixel(x, y) {
var data = ctx.getImageData(x, y, 1, 1).data;
return (data[3] !== 0);
}
オンラインデモはこちら
更新されたチェック ピクセル機能:
この更新されたチェックでは、同じ領域で文字が重なっている場合でもチェックできます。
文字を描画するための別のキャンバスを作成します。これにより、文字が分離され、ピクセルを選択すると、その特定の文字からのみピクセルを取得できます。また、オフスクリーン キャンバスは、チェック中に背景ではなく文字のピクセルのみを設定するため、背景色が何であるかは問題ではありません。オーバーヘッドは最小限です。
function checkPixel(o, x, y) {
/// create off-screen canvas
var oc = document.createElement('canvas'),
octx = oc.getContext('2d'),
data,
oldX = o.x,
oldY = o.y;
/// default canvas is 300x150, adjust if letter size is larger *)
//oc.width = oc.height = 200;
/// this can be refactored to something better but for demo...
o.x = 0;
o.y = 0;
setLetterObject(octx, o, '#000');
o.x = oldX;
o.y = oldY;
data = octx.getImageData(x - oldX, y - oldY, 1, 1).data;
return (data[3] !== 0);
}
*) キャンバスを作成するときのデフォルトのサイズは 300x150 です。新しいビットマップの再割り当てを避けるために、メモリは既に割り当てられているためそのままにしておき、そこから 1 つのピクセルを選択するだけで済みます。文字のピクセル サイズがデフォルト サイズよりも大きい場合は、もちろん、文字が収まるように再割り当てする必要があります。
このデモでは、x と y の位置を一時的にオーバーライドします。プロダクションでは、setLetterObject
メソッドがこれを何らかの方法でオーバーライドできるようにする必要があります。ただし、最も重要なことは原理を理解することなので、デモではそのままにしておきます。