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

François Beaufort
François Beaufort

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

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

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

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

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

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

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

कैप्चर किए गए प्लैटफ़ॉर्म को कंट्रोल करने वाला एपीआई, इन समस्याओं को हल करता है.

मैं कैप्चर किए गए प्लैटफ़ॉर्म को कंट्रोल करने की सुविधा का इस्तेमाल कैसे करूं?

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

ब्राउज़र टैब कैप्चर करना

सबसे पहले, उपयोगकर्ता को 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 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> एलिमेंट का साइज़, कैप्चर करने वाले ऐप्लिकेशन के डोमेन में होता है. ब्राउज़र के पास इसकी जानकारी नहीं होती. टैब का साइज़, ब्राउज़र के डोमेन में होता है और वेब ऐप्लिकेशन के लिए यह साइज़ नहीं दिखता.

वेब ऐप्लिकेशन, <video> एलिमेंट के ऑफ़सेट को वीडियो ट्रैक के कोऑर्डिनेट स्पेस में बदलने के लिए, translateCoordinates() का इस्तेमाल करता है. इसी तरह, ब्राउज़र कैप्चर किए गए फ़्रेम के साइज़ और टैब के साइज़ के बीच ट्रांसलेट करेगा. साथ ही, वेब ऐप्लिकेशन की उम्मीद के मुताबिक ऑफ़सेट पर स्क्रोल इवेंट डिलीवर करेगा.

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.
}

कैप्चर किए गए प्लैटफ़ॉर्म को कंट्रोल करने की सुविधा चालू करना

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

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

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

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

डेमो

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

Chrome के पिछले वर्शन के मुकाबले हुए बदलाव

कैप्चर किए गए प्लैटफ़ॉर्म को कंट्रोल करने की सुविधा के काम करने के तरीके में कुछ मुख्य अंतर हैं. इनके बारे में आपको पता होना चाहिए:

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

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

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

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

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

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

क्या आपको Chrome में इस सुविधा को लागू करने में कोई गड़बड़ी मिली? या क्या इसे लागू करने का तरीका, खास जानकारी से अलग है? https://new.crbug.com पर जाकर, गड़बड़ी की शिकायत करें. इसमें ज़्यादा से ज़्यादा जानकारी शामिल करें. साथ ही, गड़बड़ी को दोहराने के लिए निर्देश भी दें. Glitch, बार-बार होने वाले गड़बड़ियों की जानकारी शेयर करने के लिए बहुत अच्छा है.