drawFocusRing(element, x, y, [ canDrawCustom ])メソッドは、canvasのどの部分がフォーカスされているかを示す際に使用します。
canvasがユーザー操作が可能な内容になっている場合には、
制作者は<canvas>~</canvas>内に含める代替要素の中に、
canvasの各フォーカス可能部分に対応するフォーカス可能要素を含めるべきとされています。
この際、drawFocusRing()メソッドを使用すると、要素がフォーカスされている場合、
または、その子孫要素である場合に true の値が返り、その部分がフォーカスされているかどうかを確認することができます。
drawFocusRing()メソッドの返り値が true の場合、
ブラウザが自動で現在のパスの周りにフォーカス・リングを描画するかもしれませんが、
制作者が手動でリング(輪)を描く必要がある場合もあるかもしれません。
※メモ:現在のところ、drawFocusRing()メソッドをサポートしているブラウザは無い(?)ようです。
実際の動作が確認できませんので、このページでは簡単な解説のみをしています。
以下は、W3Cのウェブサイトに掲載されているcanvas要素内に一組のチェックボックスを持つ場合のデモで、
canvas内でチェックボックス要素を扱うための必要最低限のプログラムとして作成されています。
ただし、この使用例は、非準拠の実装との互換性を保つためのコードを削除して修正されるべきとのことです。
<canvas tabindex="-1" id="example" height="400" width="750" role="application">
<!-- Canvas Subtree acts as Shadow DOM that the browser maps to the platform accessibility API -->
<label id="labelA" for="showA"><input id="showA" role="checkbox" aria-labelledby="labelA" type="checkbox" /> Show "A"</label>
<label id="labelB" for="showB"><input id="showB" role="checkbox" aria-labelledby="labelB" type="checkbox" /> Show "B"</label>
<!-- ... -->
</canvas>
<script>
/*/
Canvas is a low level API and requires manual management of all interactivity.
The following example is quite verbose, and demonstrates the minimum of programming
necessary to enable a simple checkbox element within canvas.
Canvasは低レベルのAPIであり、ユーザー操作機能をすべて手動で管理する必要があります。
このサンプルはとても長くなっていますが、
canvas内で、チェックボックス要素を扱うために必要な最低限のプログラムとなっています。
/*/
function drawCheckbox(context, element, x, y, pathOnly) {
context.save();
context.font = '10px sans-serif';
context.textAlign = 'left';
context.textBaseline = 'middle';
var label = document.getElementById(element.getAttribute('aria-labelledby'));
var metrics = context.measureText(label.textContent);
if(pathOnly) {
var areaWidth = 15 + metrics.width;
var areaHeight = 10;
context.beginPath();
context.rect(x-5, y-5, areaWidth, areaHeight);
return;
}
context.beginPath();
context.strokeStyle = 'black';
context.rect(x-5, y-5, 10, 10);
context.stroke();
if (element.checked) {
context.fillStyle = 'black';
context.fill();
}
context.fillText(label.textContent, x+5, y);
// Draw the Focus Ring
var drawFocusManually = false;
if (document.activeElement == element || document.activeElementFocus == element && document.activeElement == context.canvas) {
try {
drawFocusManually = !context.drawFocusRing(element);
} catch(e) {
drawFocusManually = true;
}
}
if(drawFocusManually) {
context.beginPath();
context.rect(x-7, y-7, 12 + metrics.width+2, 14);
context.strokeStyle = 'silver';
context.stroke();
}
context.restore();
}
function drawBase() { /* ... */ }
function drawAs() { /* ... */ }
function drawBs() { /* ... */ }
function redraw() {
var canvas = document.getElementsByTagName('canvas')[0];
var context = canvas.getContext('2d');
var showA = document.getElementById('showA');
var showB = document.getElementById('showB');
context.clearRect(0, 0, canvas.width, canvas.height);
drawCheckbox(context, showA, 20, 40);
drawCheckbox(context, showB, 20, 60);
drawBase();
if (showA.checked) {
drawAs();
}
if (showB.checked) {
drawBs();
}
}
function processMouseCoords(event,element) {
var offsetLeft = 0, offsetTop = 0;
while(element) {
offsetLeft += element.offsetLeft >> 0;
offsetTop += element.offsetTop >> 0;
element = element.parentNode;
}
offsetLeft -= document.documentElement.scrollLeft;
offsetTop -= document.documentElement.scrollTop;
return { x: event.clientX - offsetLeft, y: event.clientY - offsetTop }
}
function processClick(event){
var canvas = document.getElementById('example');
var context = canvas.getContext('2d');
var coords = processMouseCoords(event,canvas);
var showA = document.getElementById('showA');
var showB = document.getElementById('showB');
var useRedraw = false;
if(event.target.type == 'checkbox') {
redraw();
return;
}
drawCheckbox(context, showA, 20, 40, true);
if (context.isPointInPath(coords.x, coords.y)) {
showA.checked = !(showA.checked);
showA.focus();
document.activeElementFocus = showA;
useRedraw = true;
}
drawCheckbox(context, showB, 20, 60, true);
if (context.isPointInPath(coords.x, coords.y)) {
showB.checked = !(showB.checked);
document.activeElementFocus = showB;
showB.focus();
useRedraw = true;
}
if(!useRedraw &&
(document.activeElementFocus != document.activeElement)) {
document.activeElementFocus = document.activeElement;
redraw();
}
if(useRedraw) redraw();
}
// Add the event listeners
document.getElementById('showA').addEventListener('focus', redraw, true);
document.getElementById('showB').addEventListener('focus', redraw, true);
document.getElementById('showA').addEventListener('blur', redraw, true);
document.getElementById('showB').addEventListener('blur', redraw, true);
document.getElementById('example').addEventListener('change', redraw, true);
document.getElementById('example').addEventListener('click', processClick, false);
redraw();
</script>