कैप्चर किए गए टैब को स्क्रोल और ज़ूम करें

François Beaufort
François Beaufort

वेब प्लैटफ़ॉर्म पर Screen Capture API की मदद से टैब, विंडो, और स्क्रीन शेयर करने की सुविधा पहले से ही उपलब्ध है. जब कोई वेब ऐप्लिकेशन getDisplayMedia() को कॉल करता है, तो Chrome, उपयोगकर्ता को वेब ऐप्लिकेशन से किसी टैब, विंडो या स्क्रीन को MediaStreamTrack वीडियो के तौर पर शेयर करने का निर्देश देता है.

getDisplayMedia() का इस्तेमाल करने वाले कई वेब ऐप्लिकेशन, उपयोगकर्ता को कैप्चर किए गए प्लैटफ़ॉर्म की वीडियो झलक दिखाते हैं. उदाहरण के लिए, वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन अक्सर इस वीडियो को, रिमोट उपयोगकर्ताओं के लिए स्ट्रीम करेंगे. साथ ही, इन्हें किसी लोकल HTMLVideoElement पर रेंडर करेंगे. इससे, स्थानीय उपयोगकर्ता को लगातार, शेयर की जा रही चीज़ों की झलक दिखेगी.

यह दस्तावेज़ Chrome में नया कैप्चर किया गया सरफ़ेस कंट्रोल एपीआई पेश करता है, जिससे आपका वेब ऐप्लिकेशन कैप्चर किए गए टैब को स्क्रोल कर सकता है. साथ ही, कैप्चर किए गए टैब का ज़ूम लेवल पढ़ और लिख सकता है.

एक उपयोगकर्ता, कैप्चर किए गए टैब को स्क्रोल और ज़ूम करता है (डेमो).

कैप्चर किए गए सरफ़ेस कंट्रोल का इस्तेमाल क्यों करें?

सभी वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन में एक जैसी कमी होती है: अगर उपयोगकर्ता किसी कैप्चर किए गए टैब या विंडो से इंटरैक्ट करना चाहता है, तो उसे वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन से बाहर जाकर उस प्लैटफ़ॉर्म पर स्विच करना होगा. इसमें कुछ चुनौतियां हैं:

  • उपयोगकर्ता को कैप्चर किया गया ऐप्लिकेशन और रिमोट उपयोगकर्ताओं के वीडियो एक साथ तब तक नहीं दिखेंगे, जब तक वे वीडियो कॉन्फ़्रेंस टैब और शेयर किए गए टैब के लिए पिक्चर में पिक्चर या अलग-अलग विंडो का इस्तेमाल नहीं करते. छोटी स्क्रीन पर ऐसा करना मुश्किल हो सकता है.
  • उपयोगकर्ता को वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन और कैप्चर की गई सतह के बीच स्विच करने की ज़रूरत नहीं पड़ती.
  • वीडियो कॉन्फ़्रेंसिंग ऐप्लिकेशन से दूर होने पर, उपयोगकर्ता उस कंट्रोल को ऐक्सेस नहीं कर पाएगा. इसमें एम्बेड किया गया चैट ऐप्लिकेशन, इमोजी वाली प्रतिक्रियाएं, कॉल में शामिल होने के लिए अनुरोध करने वाले उपयोगकर्ताओं के बारे में सूचनाएं, मल्टीमीडिया और लेआउट कंट्रोल, और वीडियो कॉन्फ़्रेंसिंग की अन्य सुविधाएं शामिल हैं.
  • प्रज़ेंटर, रिमोट सेशन में शामिल लोगों को कंट्रोल नहीं दे सकता. इससे एक ऐसी स्थिति हो जाती है जहां रिमोट उपयोगकर्ता प्रज़ेंटर को स्लाइड बदलने, थोड़ा ऊपर और नीचे स्क्रोल करने या ज़ूम लेवल अडजस्ट करने के लिए कहते हैं.

कैप्चर किया गया 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;
}

अनुमति का प्रॉम्प्ट

किसी दिए गए CaptureController ऑब्जेक्ट पर, sendWheel() या setZoomLevel() को पहली बार शुरू करने पर अनुमति का अनुरोध मिलता है. अगर उपयोगकर्ता अनुमति देता है, तो उस 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() का इस्तेमाल करके, कैप्चर करने वाला ऐप्लिकेशन, टैब के व्यूपोर्ट में अपनी पसंद के निर्देशांकों के बजाय, व्हील इवेंट को चुने गए तीव्रता के व्हील इवेंट को डिलीवर कर सकता है. कैप्चर किए गए ऐप्लिकेशन को उपयोगकर्ता के इंटरैक्शन से अलग, इवेंट के तौर पर पहचाना नहीं जा सकता.

मान लें कि कैप्चर करने वाला ऐप्लिकेशन, "previewTile" नाम के <video> एलिमेंट का इस्तेमाल करता है, तो नीचे दिया गया कोड बताता है कि कैप्चर किए गए टैब में व्हील इवेंट भेजने को कैसे आगे बढ़ाया जाए:

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 further explained 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 आम तौर पर सीमा से बाहर नहीं होगा. इसलिए, उपयोगकर्ता से अनुमति मांगने के लिए उनका इस्तेमाल करना सुरक्षित है.)

ज़ूम करना

कैप्चर किए गए टैब के ज़ूम लेवल से इंटरैक्ट करने के लिए, इन 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.
}

कैप्चर किया गया सरफ़ेस कंट्रोल चालू करें

कैप्चर किया गया सरफ़ेस कंट्रोल एपीआई, डेस्कटॉप पर Chrome में कैप्चर किए गए सरफ़ेस कंट्रोल फ़्लैग के साथ उपलब्ध है. इसे chrome://flags/#captured-surface-control पर चालू किया जा सकता है.

यह सुविधा भी डेस्कटॉप पर Chrome 122 के ऑरिजिन ट्रायल की शुरुआत कर रही है. इससे डेवलपर अपनी साइटों पर आने वाले लोगों के लिए, इस सुविधा को चालू कर पाएंगे, ताकि वे असल उपयोगकर्ताओं का डेटा इकट्ठा कर सकें. ऑरिजिन ट्रायल और उनके काम करने के तरीके के बारे में ज़्यादा जानकारी के लिए, ऑरिजिन ट्रायल का इस्तेमाल शुरू करना देखें.

सुरक्षा और निजता

"captured-surface-control" की अनुमति की नीति से, आपको यह मैनेज करने की सुविधा मिलती है कि कैप्चर करने वाले ऐप्लिकेशन और एम्बेड किए गए तीसरे पक्ष के iframe, कैप्चर किए गए प्लैटफ़ॉर्म कंट्रोल को कैसे ऐक्सेस कर सकते हैं. सुरक्षा से जुड़ी समस्याओं को समझने के लिए, कैप्चर किए गए सरफ़ेस कंट्रोल के बारे में जानकारी देने वाले पेज पर, निजता और सुरक्षा से जुड़ी बातों वाला सेक्शन देखें.

डेमो

Glitch पर डेमो चलाकर, कैप्चर किए गए सरफ़ेस कंट्रोल की मदद से गेम को खेला जा सकता है. सोर्स कोड की जांच करना न भूलें.

Chrome के पिछले वर्शन के बदलाव

यहां कैप्चर किए गए सरफ़ेस कंट्रोल के बारे में व्यवहार से जुड़े कुछ प्रमुख अंतर दिए गए हैं, जिनके बारे में आपको पता होना चाहिए:

  • Chrome 124 और उससे पहले के वर्शन में:
    • अगर अनुमति दी गई है, तो यह उस CaptureController से जुड़े कैप्चर सेशन के दायरे में आती है, न कि कैप्चर करने वाले ऑरिजिन के लिए.
  • Chrome 122 में:
    • getZoomLevel(), टैब के मौजूदा ज़ूम लेवल के साथ प्रॉमिस दिखाता है.
    • अगर उपयोगकर्ता ने ऐप्लिकेशन को इस्तेमाल करने की अनुमति नहीं दी है, तो sendWheel(), गड़बड़ी के मैसेज "No permission." के साथ अस्वीकार किया गया प्रॉमिस दिखाता है. Chrome 123 और उसके बाद के वर्शन में, "NotAllowedError" गड़बड़ी टाइप है.
    • oncapturedzoomlevelchange उपलब्ध नहीं है. setInterval() का इस्तेमाल करके, इस सुविधा को पॉलीफ़िल किया जा सकता है.

सुझाव/राय दें या शिकायत करें

Chrome टीम और वेब मानकों वाला समुदाय, कैप्चर किए गए सरफ़ेस कंट्रोल के साथ आपके अनुभवों के बारे में जानना चाहता है.

हमें इसके डिज़ाइन के बारे में बताएं

क्या कैप्चर किया गया सरफ़ेस कैप्चर ऐसा कुछ है जो आपकी उम्मीद के मुताबिक काम नहीं करता? या फिर, अपना आइडिया लागू करने के लिए, तरीके या प्रॉपर्टी मौजूद नहीं हैं? सुरक्षा मॉडल के बारे में आपका कोई सवाल या टिप्पणी है? GitHub रेपो पर खास जानकारी से जुड़ी समस्या दर्ज करें या किसी मौजूदा समस्या में अपने विचार जोड़ें.

क्या लागू करने में कोई समस्या है?

क्या आपको Chrome को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने की प्रक्रिया खास जानकारी से अलग है? https://new.crbug.com पर गड़बड़ी की शिकायत करें. कृपया ज़्यादा से ज़्यादा जानकारी और पेज को फिर से बनाने के निर्देश ज़रूर शामिल करें. Glitch का इस्तेमाल करके, फिर से जनरेट की जा सकने वाली गड़बड़ियों को शेयर किया जा सकता है.