رویدادهای لمسی (Touch Events)
در سالهای اخیر استفاده از دستگاههای مجهز به صفحه نمایشهای لمسی (مانند تلفن همراه و تبلت) بسیار فراگیر شده است. با توجه به این که در این دستگاهها معمولاً از ماوس استفاده نمیشود و بیشتر از لمس صفحه نمایش برای تعامل با دستگاه استفاده میشود، باید از رویدادهای دیگری به عنوان جایگزین رویدادهای ماوس استفاده کرد. البته رویدادهای click و dblclick را به خوبی میتوان با لمس صفحه نمایش تولید کرد. اما سایر رویدادهای ماوس در صفحات لمسی یا قابل تولید نیستند (مانند mousemove) و یا عملکر مناسبی ندارند (مانند mousedown).
انواع رویدادهای لمسی
در مجموع ۴ نوع رویداد لمسی در جاوا اسکریپت تعریف شده است که به شرح زیر میباشند.- touchstart : به محض لمس کردن صفحه نمایش رخ میدهد. این رویداد تقریباً معادل رویداد mousedown است.
- touchend : به محض برداشتن انگشت (یا قلم) از روی صفحه نمایش رخ میدهد. این رویداد تقریباً معادل رویداد mouseup است.
- touchmove : در زمان حرکت انگشت (یا قلم) بر روی صفحه نمایش رخ میدهد. این رویداد تقریبا معادل رویداد mousemove است.
- touchcancel : در صورتی که در زمان لمس صفحه نمایش وقفهای رخ دهد، این رویداد تولید میشود. البته رفتار این رویداد در مرورگرها و دستگاههای مختلف تا حدودی متفاوت است. مثلاً در زمان خروج انگشت از صفحه نمایش ممکن است این رویداد رخ دهد. و یا در صورت لمس همزمان با چند انگشت و یا در صورت اجرای تابع alert برای نمایش یک پیام در زمان لمس صفحه ممکن است این رویداد رخ دهد.
برای درک بهتر عملکرد هر یک از رویداهای فوق مثال زیر را اجرا کنید. در این مثال یک عنصر از نوع <div> وجود دارد که در صورت وقوع هر یک از رویدادهای لمسی در محدودهی این عنصر، تابع handler فراخوانی شده و نام رویداد رخ داده را در عنصری دیگر از نوع <p> نمایش میدهد. توجه کنید که این مثال را حتماً باید در دستگاهی که مجهز به صفحه نمایش لمسی است اجرا کنید. و یا از شبیهساز مرورگر Chrome استفاده کنید. این مثال را میتوانید اینجا در CodePen اجرا کنید.
const div = document.querySelector('div');
div.addEventListener('touchstart', handler);
div.addEventListener('touchmove', handler);
div.addEventListener('touchend', handler);
div.addEventListener('touchcancel', handler);
function handler(event) {
const p = document.querySelector('p');
p.textContent += event.type + ' ';
}
نکته : در دستگاههای مجهز به صفحه نمایش لمسی، معمولاً برای شبیهسازی دکمهی فرعی ماوس (یا کلیک راست) باید صفحه را لمس کرده و حدود ۲ ثانیه انگشت (یا قلم) را ثابت نگاه داشت. لذا انجام این کار موجب تولید رویداد contextmenu در این نوع دستگاهها میشود.
خاصیتهای شئ event
پیش از این دیدیم که در رویدادهای ماوس، شئ event دارای خاصیتهایی برای دسترسی به مختصات محل وقوع رویداد است. اما در رویدادهای لمسی امکان استفاده از این خاصیتها وجود ندارد. با توجه به این که در صفحه نمایشهای لمسی، امکان انجام چند لمس به صورت همزمان وجود دارد، در نتیجه به تعداد لمسهای انجام شده، مختصات وجود خواهد داشت. به همین دلیل خاصیتهایی که در رویدادهای ماوس برای به دست آوردن مختصات استفاده میشوند، در رویدادهای لمسی قابل استفاده نیستند. اما سایر خاصیتهای شئ event که در رویدادهای ماوس وجود دارند، در رویدادهای لمسی نیز قابل استفادهاند.
برای ادامهی بحث و معرفی روش دستیابی به مختصات نقاط لمس شده، ابتدا باید به معرفی شئ Touch بپردازیم. در جاوا اسکریپت برای مشخص کردن مختصات و سایر مشخصات یک نقطهی لمس شده از صفحه نمایش، از شئ Touch استفاده میشود. این شئ دارای تعدادی خاصیت به شرح زیر است که تقریباً در تمام دستگاههای لمسی پشتیبانی میشوند.
- clientX و clientY : مختصات محل لمس نسبت به گوشهی بالا و چپ مرورگر (فقط بخش نمایشی یا Viewport مرورگر).
- pageX و pageY : مختصات محل لمس نسبت به گوشهی بالا و چپ صفحهی وب.
- screenX و screenY : مختصات لمس رویداد نسبت به گوشهی بالا و چپ صفحه نمایش.
- identifier : شمارهی نقطهی لمس شده. (هر یک از نقاط لمس شده یک شناسهی عددی دارند)
- target : عنصری که رویداد لمس از آنجا شروع شده. (حتی با خارج شدن از عنصر شروع کننده، مقدار خاصیت target عوض نمیشود)
اما شئ Touch دارای ۴ خاصیت دیگر نیز میباشد که فعلاً به استاندارد نهایی اضافه نشدهاند و پشتیبانی از آنها در دستگاههای مختلف متفاوت است. این خاصیتها برای به دست آوردن اطلاعاتی در مورد نحوهی لمس صفحه به کار میروند. اسامی این ۴ خاصیت و کاربرد هر یک در زیر آمده است. توجه کنید که منظور از "بیضی" در توضیحات زیر، همان سطح تماس انگشت با صفحه نمایش است که معمولاً به شکل بیضی میباشد.
- radiusX : شعاع بیضی روی محور X.
- radiusY : شعاع بیضی روی محور Y.
- rotationAngle : میزان دوران بیضی بر حسب درجه. یعنی بیضی اولیه که با radiusX و radiusY تعریف میشود، باید به این میزان در جهت ساعتگرد دوران کند تا منطبق با سطح لمس شده با انگشت باشد.
- force : میزان فشار وارد شده بر محل لمس که عددی بین صفر و یک است.
البته تعاریف فوق، تعاریف استانداردی است که برای این خاصیتها ارائه شده است. اما در حال حاضر در دستگاههای مختلف رفتار این خاصیتها متفاوت است. (مثلاً در آزمایشی که بر روی تلفن همراه من با مرورگر Chrome انجام شد، به غیر از خاصیت force، بقیه موارد برابر با صفر بودند. ضمناً خاصیت force میزان فشار را نشان نمیدهد، بلکه با بیشتر شدن سطح لمس شده، بزرگتر میشود.)
اما برای استفاده از خاصیتهای شئ Touch به خاصیتهایی از شئ event نیاز خواهیم داشت. شئ event در رویدادهای لمسی دارای ۳ خاصیت به نامهای touches و changedTouches و targetTouches میباشد. هر یک از این خاصیتها حاوی لیستی از اشیاء Touch هستند. یعنی مانند یک آرایه رفتار میکنند. محتوای هر یک از این خاصیتها به شرح زیر است.
- touches : شامل لیستی از تمام نقاط لمس شده در صفحه نمایش
- targetTouches : شامل لیستی از تمام نقاط لمس شده در صفحه نمایش که نقطهی شروع آنها در شئ target بوده است. (شئ target همان عنصری است که Event Handler آن فراخوانی شده و در حال اجرا است)
- changedTouches : لیستی از نقاط لمس شده که وضعیتشان نسبت به قبل تغییر کرده است.
خاصیت touches بیشترین کاربرد را در بین موارد فوق دارد. مثال زیر را بر روی تلفن همراه یا تبلت اجرا کنید تا با رفتار این خاصیت و خاصیتهای شئ Touch بهتر آشنا شوید. در این مثال فرض شده است که فقط یک نقطه لمس شده است. این مثال را میتوانید اینجا اجرا کنید.
const div = document.querySelector('div');
div.addEventListener('touchstart', handler);
function handler(event) {
const p = document.querySelector('p');
p.innerHTML = 'clientX: ' + event.touches[0].clientX +'<br />';
p.innerHTML += 'clientY: ' + event.touches[0].clientY + '<br />';
p.innerHTML += 'screenX: ' + event.touches[0].screenX + '<br />';
p.innerHTML += 'screenY: ' + event.touches[0].screenY + '<br />';
p.innerHTML += 'pageX: ' + event.touches[0].pageX + '<br />';
p.innerHTML += 'pageY: ' + event.touches[0].pageY + '<br />';
p.innerHTML += 'identifier: ' + event.touches[0].identifier + '<br />';
p.innerHTML += 'target: ' + event.touches[0].target.tagName;
}
نکته : در دستگاههای مجهز به صفحه نمایشهای لمسی، مقدار خاصیتهای مربوط به مختصات معمولاً اعشاری هستند.
جهت مشاهدهی رفتار سایر خاصیتهای شئ Touch که پشتیبانی کمتری در دستگاههای مختلف دارند، از مثال زیر استفاده کنید. در این مثال نیز فرض شده است که فقط یک نقطه لمس میشود. این مثال را میتوانید اینجا اجرا کنید.
const div = document.querySelector('div');
div.addEventListener('touchstart', handler);
function handler(event) {
const p = document.querySelector('p');
p.innerHTML = 'RadiusX: ' + event.touches[0].radiusX + '<br />';
p.innerHTML += 'RadiusY: ' + event.touches[0].radiusY + '<br />';
p.innerHTML += 'angle: ' + event.touches[0].rotationAngle + '<br />';
p.innerHTML += 'force: ' + event.touches[0].force;
}
حال برای مشاهدهی رفتار خاصیت touches در صورت لمس شدن همزمان چند نقطه از صفحه نمایش، مثال زیر را اجرا کنید. در این مثال مختصات تمام نقاط لمس شده در صفحهی وب در یک عنصر از نوع <p> نمایش داده میشود. این مثال را میتوانید اینجا اجرا کنید.
document.addEventListener('touchstart', handler);
function handler(event) {
const p = document.querySelector('p');
const points = event.touches.length;
let message = '';
for(let i=0 ; i < points ; i++){
message += `Point ${i}: <br />
clientX: ${event.touches[i].clientX}<br />
clientY: ${event.touches[i].clientY}<br /><br />`;
}
p.innerHTML = message;
}
شکل زیر نمونهای از اجرای این برنامه را نشان میدهد. حالت نشان داده شده در این شکل با لمس همزمان ۴ نقطه از صفحه نمایش به وجود آمده است. مشاهده میکنید که اعداد مربوط به مختصات، اعشاری هستند.
در نهایت ذکر این نکته ضروری است که استفاده از رویدادهای لمسی کمی دشوار است و برای استفاده از این رویدادها باید با دقت بالا کدنویسی کرده و حتماً برنامه را در چند دستگاه محتلف آزمایش کنید.