تمرير علامة تبويب تم التقاطها وتكبيرها/تصغيرها

François Beaufort
François Beaufort

يمكن حاليًا مشاركة علامات التبويب والنوافذ والشاشات على منصة الويب باستخدام Screen Capture API. عندما يطلب تطبيق ويب getDisplayMedia()، يطلب Chrome من المستخدم مشاركة علامة تبويب أو نافذة أو شاشة مع تطبيق الويب كفيديو MediaStreamTrack.

تعرض العديد من تطبيقات الويب التي تستخدم getDisplayMedia() للمستخدم معاينة فيديو للسطح الذي تم التقاطه. على سبيل المثال، غالبًا ما تبث تطبيقات مؤتمرات الفيديو هذا الفيديو للمستخدمين البعيدين مع عرضه أيضًا على HTMLVideoElement على الجهاز، حتى يتمكن المستخدم المحلي من الاطّلاع باستمرار على معاينة لما يشاركه.

تقدّم هذه المستندات واجهة برمجة التطبيقات الجديدة Captured Surface Control API في Chrome، والتي تتيح لتطبيق الويب الانتقال إلى علامة تبويب تم التقاطها، بالإضافة إلى قراءة مستوى التكبير/التصغير لعلامة التبويب التي تم التقاطها وكتابته.

عندما ينتقل المستخدم إلى صفحة علامة تبويب تم التقاطها ويكبرها (عرض توضيحي).

لماذا يجب استخدام عنصر التحكّم في المساحة التي تمّ التقاطها؟

تواجه جميع تطبيقات مؤتمرات الفيديو العائق نفسه: إذا أراد المستخدم التفاعل مع علامة تبويب أو نافذة تم التقاطها، عليه التبديل إلى تلك المساحة، ما ينقل المستخدم بعيدًا عن تطبيق مؤتمرات الفيديو. ويؤدي ذلك إلى بعض التحديات:

  • لا يمكن للمستخدم الاطّلاع على التطبيق الذي التقطه وفيديوهات المستخدمين البعيدين في الوقت نفسه ما لم يستخدموا ميزة نافذة ضمن النافذة أو نوافذ منفصلة جنبًا إلى جنب لعلامة التبويب "مؤتمر الفيديو" وعلامة التبويب "تمت مشاركتها". وقد تكون هذه العملية صعبة على الشاشة الأصغر حجمًا.
  • يشعر المستخدم بالحاجة إلى الانتقال بين تطبيق مؤتمرات الفيديو والسطح الذي تم التقاطه.
  • يفقد المستخدم إمكانية الوصول إلى عناصر التحكّم التي يعرضها تطبيق مكالمات الفيديو عندما لا يكون متصلاً به، مثل تطبيق محادثة مضمّن وتفاعلات الرموز التعبيرية والإشعارات بشأن المستخدمين الذين يطلبون الانضمام إلى المكالمة وعناصر التحكّم في الوسائط المتعددة والتنسيقات وغيرها من ميزات مكالمات الفيديو المفيدة.
  • لا يمكن للمقدّم تفويض التحكّم للمشاركين عن بُعد. يؤدّي ذلك إلى السيناريو المعتاد الذي يطلب فيه المستخدمون عن بُعد من المُقدّم تغيير الشريحة أو الانتقال للأعلى أو للأسفل قليلاً أو ضبط مستوى التكبير/التصغير.

تعالج واجهة برمجة التطبيقات Captured Surface Control API هذه المشاكل.

كيف يمكنني استخدام عنصر التحكّم في السطح الذي تمّ التقاطه؟

يتطلّب استخدام عنصر التحكّم في المساحة التي تمّ التقاطها بنجاح اتّباع بعض الخطوات، مثل التقاط علامة تبويب في المتصفّح صراحةً والحصول على إذن من المستخدم قبل التمكّن من الانتقال إلى علامة التبويب التي تمّ التقاطها وتكبيرها أو تصغيرها.

التقاط علامة تبويب متصفّح

ابدأ بطلب من المستخدم اختيار سطح لمشاركة المحتوى عليه باستخدام getDisplayMedia()، وربط عنصر CaptureController بجلسة الالتقاط أثناء ذلك. سنستخدم هذا الكائن للتحكم في السطح الذي تم التقاطه قريبًا.

const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });

بعد ذلك، أنشئ معاينة محلية للسطح الذي تم التقاطه على شكل عنصر <video>:

const previewTile = document.querySelector('video');
previewTile.srcObject = stream;

إذا اختار المستخدم مشاركة نافذة أو شاشة، لن نتمكن من تنفيذ ذلك في الوقت الحالي، ولكن إذا اختار مشاركة علامة تبويب، يمكننا المتابعة.

const [track] = stream.getVideoTracks();

if (track.getSettings().displaySurface !== 'browser') {
  // Bail out early if the user didn't pick a tab.
  return;
}

طلب الإذن

يؤدي الاستدعاء الأول إما لـ sendWheel() أو setZoomLevel() على عنصر CaptureController محدّد إلى ظهور طلب الإذن. إذا منح المستخدم الإذن، يُسمح بمزيد من عمليات استدعاء هذه الطرق على عنصر CaptureController هذا. إذا رفض المستخدم الإذن، يتم رفض الوعد الذي تم إرجاعه.

يُرجى العِلم أنّ عناصر CaptureController مرتبطة بشكل فريد بجلسة تسجيل معيّنة، ولا يمكن ربطها بجلسة تسجيل أخرى، ولا تبقى محفوظة عند الانتقال إلى الصفحة التي تم تحديدها فيها. ومع ذلك، تبقى جلسات الالتقاط محفوظة بعد الانتقال إلى الصفحة التي تم التقاطها.

يجب أن يُجري المستخدم إيماءة لعرض طلب الحصول على الإذن. لا تتطلّب مكالمات sendWheel() وsetZoomLevel() سوى إيماءة من المستخدم، وذلك فقط إذا كان يجب عرض الطلب. إذا نقر المستخدم على زر التكبير أو التصغير في تطبيق الويب، سيتم تحديد إيماءة المستخدم هذه، ولكن إذا كان التطبيق يريد توفير عنصر التحكم في التمرير أولاً، يجب أن يضع المطوّرون في الاعتبار أن التمرير لا يشكِّل إيماءة مستخدم. من بين الحلول المقترَحة أن يعرض التطبيق أولاً زر "بدء الانتقال للأعلى أو للأسفل"، كما هو موضّح في المثال التالي:

const startScrollingButton = document.querySelector('button');

startScrollingButton.addEventListener('click', async () => {
  try {
    const noOpWheelAction = {};

    await controller.sendWheel(noOpWheelAction);
    // The user approved the permission prompt.
    // You can now scroll and zoom the captured tab as shown later in the article.
  } catch (error) {
    return; // Permission denied. Bail.
  }
});

صفحة مواضع التمرير

باستخدام sendWheel()، يمكن للتطبيق الذي يُجري عملية الالتقاط إرسال أحداث عجلة بحجم محدّد على إحداثيات من اختياره ضمن مساحة العرض في علامة التبويب. لا يمكن تمييز الحدث عن تفاعل المستخدم المباشر مع التطبيق الذي تم التقاطه.

بافتراض أنّ التطبيق الذي يُجري عملية التسجيل يستخدم عنصر <video> يُسمى "previewTile"، يوضّح الرمز التالي كيفية إعادة توجيه أحداث إرسال عجلة التمرير إلى علامة التبويب التي تم تسجيلها:

const previewTile = document.querySelector('video');

previewTile.addEventListener('wheel', async (event) => {
  // Translate the offsets into coordinates which sendWheel() can understand.
  // The implementation of this translation is explained further below.
  const [x, y] = translateCoordinates(event.offsetX, event.offsetY);
  const [wheelDeltaX, wheelDeltaY] = [-event.deltaX, -event.deltaY];

  try {
    // Relay the user's action to the captured tab.
    await controller.sendWheel({ x, y, wheelDeltaX, wheelDeltaY });
  } catch (error) {
    // Inspect the error.
    // ...
  }
});

تأخذ الطريقة sendWheel() قاموسًا يتضمّن مجموعتَين من القيم:

  • x وy: الإحداثيات التي سيتم إرسال حدث العجلة إليها
  • wheelDeltaX وwheelDeltaY: قياسات التمرير بالبكسل للتمرير الأفقي والرأسي على التوالي يُرجى العلم أنّ هذه القيم مقلوبة مقارنةً بحدث العجلة الأصلي.

في ما يلي مثال على تنفيذ translateCoordinates():

function translateCoordinates(offsetX, offsetY) {
  const previewDimensions = previewTile.getBoundingClientRect();
  const trackSettings = previewTile.srcObject.getVideoTracks()[0].getSettings();

  const x = trackSettings.width * offsetX / previewDimensions.width;
  const y = trackSettings.height * offsetY / previewDimensions.height;

  return [Math.floor(x), Math.floor(y)];
}

تجدر الإشارة إلى أنّ هناك ثلاثة مقاسات مختلفة في الرمز أعلاه:

  • حجم العنصر <video>
  • حجم اللقطات التي تم التقاطها (يتم تمثيلها هنا بالرمزَين trackSettings.width وtrackSettings.height).
  • حجم علامة التبويب

يقع حجم العنصر <video> بالكامل ضمن نطاق تطبيق الالتقاط وغير معروف للمتصفّح. حجم علامة التبويب بالكامل ضمن نطاق المتصفّح، وغير معروف لتطبيق الويب.

يستخدم تطبيق الويب اللغة translateCoordinates() لترجمة علامات الإزاحة المرتبطة بعنصر <video> إلى إحداثيات داخل مساحة الإحداثيات الخاصة بمقطع الفيديو. وبالمثل، سيترجم المتصفّح بين حجم الإطارات التي تم التقاطها وحجم علامة التبويب، وسيعرض حدث الانتقال للأعلى أو للأسفل استنادًا إلى إزاحة تتوافق مع توقّعات تطبيق الويب.

يمكن رفض الوعد الذي تم إرجاعه من قِبل "sendWheel()" في الحالات التالية:

  • إذا لم تبدأ جلسة التسجيل بعد أو سبق أن توقفت، ويشمل ذلك الإيقاف بشكل غير متزامن أثناء معالجة المتصفّح لإجراء sendWheel().
  • إذا لم يمنح المستخدم التطبيق الإذن لاستخدام sendWheel()
  • إذا حاول تطبيق الالتقاط عرض حدث تمرير في إحداثيات خارج [trackSettings.width, trackSettings.height] يُرجى العِلم أنّ هذه القيم يمكن أن تتغيّر بشكل غير متزامن، لذا من الأفضل رصد الخطأ وتجاهله. (يُرجى العِلم أنّ الرمز 0, 0 لا يكون خارج الحدود عادةً، لذا من الآمن استخدامه لطلب الإذن من المستخدم).

Zoom

يتم التفاعل مع مستوى التكبير لعلامة التبويب التي تم التقاطها من خلال مساحات العرض CaptureController التالية:

  • تعرِض getSupportedZoomLevels() قائمة بمستويات التكبير أو التصغير المتوافقة مع المتصفّح، ويتم تمثيلها كنسب مئوية من "مستوى التكبير أو التصغير التلقائي" الذي يتم تحديده على أنّه %100. هذه القائمة تزداد بشكل روتيني وتحتوي على القيمة 100.
  • تعرِض getZoomLevel() مستوى التكبير الحالي لعلامة التبويب.
  • تضبط setZoomLevel() مستوى التكبير/التصغير للعلامة على أي قيمة عددية متوفّرة في getSupportedZoomLevels()، وتُعرِض وعدًا عند نجاحها. يُرجى العِلم أنّه لا تتم إعادة ضبط مستوى التكبير أو التصغير في نهاية جلسة الالتقاط.
  • تتيح لك ميزة oncapturedzoomlevelchange الاستماع إلى التغييرات في مستوى التكبير/التصغير في علامة التبويب التي تم التقاطها، حيث يمكن للمستخدمين تغيير مستوى التكبير/التصغير إما من خلال تطبيق الالتقاط أو من خلال التفاعل المباشر مع علامة التبويب التي تم التقاطها.

تكون المكالمات إلى setZoomLevel() متاحة فقط بعد الحصول على الإذن، في حين تكون المكالمات إلى طرق التكبير/التصغير الأخرى للقراءة فقط "مجانًا"، كما هو الحال مع الاستماع إلى الأحداث.

يوضّح لك المثال التالي كيفية زيادة مستوى تكبير علامة تبويب تمّ التقاطها في جلسة تسجيل حالية:

const zoomIncreaseButton = document.getElementById('zoomInButton');

zoomIncreaseButton.addEventListener('click', async (event) => {
  const levels = CaptureController.getSupportedZoomLevels();
  const index = levels.indexOf(controller.getZoomLevel());
  const newZoomLevel = levels[Math.min(index + 1, levels.length - 1)];

  try {
    await controller.setZoomLevel(newZoomLevel);
  } catch (error) {
    // Inspect the error.
    // ...
  }
});

يوضّح المثال التالي كيفية التفاعل مع تغييرات مستوى التكبير/التصغير في علامة تبويب تم التقاطها:

controller.addEventListener('capturedzoomlevelchange', (event) => {
  const zoomLevel = controller.getZoomLevel();
  document.querySelector('#zoomLevelLabel').textContent = `${zoomLevel}%`;
});

رصد الميزات

للتحقّق مما إذا كان إرسال أحداث عجلة القيادة متاحًا، استخدِم:

if (!!window.CaptureController?.prototype.sendWheel) {
  // CaptureController sendWheel() is supported.
}

للتحقّق مما إذا كان التحكّم في التكبير/التصغير متاحًا، استخدِم:

if (!!window.CaptureController?.prototype.setZoomLevel) {
  // CaptureController setZoomLevel() is supported.
}

تفعيل عنصر التحكّم في المساحة التي تمّ التقاطها

تتوفّر واجهة برمجة التطبيقات Captured Surface Control API في Chrome على أجهزة الكمبيوتر المكتبي ضمن علامة Captured Surface Control، ويمكن تفعيلها على الإصدار chrome://flags/#captured-surface-control.

تدخل هذه الميزة أيضًا في مرحلة التجربة والتقييم بدءًا من Chrome 122 على أجهزة الكمبيوتر المكتبي، ما يسمح للمطوّرين بتفعيل الميزة لزوّار مواقعهم الإلكترونية من أجل جمع البيانات من مستخدمين حقيقيين. اطّلِع على البدء باستخدام تجارب المصدر للحصول على مزيد من المعلومات حول تجارب المصدر وطريقة عملها.

الأمان والخصوصية

تتيح لك سياسة الأذونات في "captured-surface-control" إدارة كيفية وصول تطبيق الالتقاط وإطارات iframe التابعة لجهات خارجية المضمّنة إلى عنصر التحكّم في المساحة التي تم التقاطها. لفهم المفاضلات الأمنية، اطّلِع على قسم الاعتبارات المتعلّقة بالخصوصية والأمان في الشرح التفصيلي عن ميزة "التحكّم في السطح الذي تم التقاطه".

عرض توضيحي

يمكنك تجربة ميزة "عناصر التحكّم في السطح الذي تمّ التقاطه" من خلال تشغيل الإصدار التجريبي على Glitch. تأكّد من الاطّلاع على رمز المصدر.

التغييرات في الإصدارات السابقة من Chrome

في ما يلي بعض الاختلافات السلوكية الرئيسية حول عنصر التحكّم في المساحة التي تمّ التقاطها والتي يجب أن تكون على دراية بها:

  • في الإصدار 124 من Chrome والإصدارات الأقدم:
    • في حال منح الإذن، يتم تحديد نطاق جلسة الالتقاط المرتبطة بـ CaptureController، وليس مصدر الالتقاط.
  • في الإصدار 122 من Chrome:
    • تعرض getZoomLevel() وعدًا بمستوى التكبير الحالي لعلامة التبويب.
    • يعرض sendWheel() وعدًا تم رفضه مع رسالة الخطأ "No permission." إذا لم يمنح المستخدم الإذن لاستخدام التطبيق. نوع الخطأ هو "NotAllowedError" في الإصدار 123 من Chrome والإصدارات الأحدث.
    • لا يتوفّر oncapturedzoomlevelchange. يمكنك استخدام ميزة الملء اللاحق لهذه الميزة باستخدام setInterval().

ملاحظات

يريد فريق Chrome ومجتمع معايير الويب معرفة تجاربك مع عنصر التحكّم في المساحة التي تمّ التقاطها.

أخبرنا عن التصميم

هل هناك مشكلة في ميزة "التقاط السطح المُسجَّل" لا تعمل على النحو المتوقّع؟ أو هل هناك طرق أو سمات غير متوفّرة تحتاجها لتنفيذ فكرتك؟ هل لديك سؤال أو تعليق بشأن نموذج الأمان؟ يمكنك الإبلاغ عن مشكلة في المواصفات على مستودع GitHub، أو إضافة أفكارك إلى مشكلة حالية.

هل هناك مشكلة في التنفيذ؟

هل رصدت خطأ في عملية تنفيذ Chrome؟ أم أنّ عملية التنفيذ مختلفة عن المواصفات؟ يُرجى الإبلاغ عن الخطأ على https://new.crbug.com. واحرص على تضمين أكبر قدر ممكن من التفاصيل، بالإضافة إلى تعليمات إعادة إنتاجه. إنّ تأثير الخطأ يعمل بشكل رائع في مشاركة الأخطاء القابلة للتكرار.