Picture-in-Picture voor elk element, niet alleen <video>

François Beaufort
François Beaufort

Browserondersteuning

  • Chroom: 116.
  • Rand: 116.
  • Firefox: niet ondersteund.
  • Safari: niet ondersteund.

Bron

De Document Picture-in-Picture API maakt het mogelijk om een ​​altijd zichtbaar venster te openen dat kan worden gevuld met willekeurige HTML-inhoud. Het breidt de bestaande Picture-in-Picture API voor <video> uit, waardoor alleen een HTML <video> -element in een Picture-in-Picture-venster kan worden geplaatst.

Het Picture-in-Picture-venster in de Document Picture-in-Picture API is vergelijkbaar met een leeg venster van dezelfde oorsprong dat wordt geopend via window.open() , met enkele verschillen:

  • Het Picture-in-Picture-venster zweeft bovenop andere vensters.
  • Het Picture-in-Picture-venster overleeft nooit het openingsvenster.
  • Er kan niet door het Picture-in-Picture-venster worden genavigeerd.
  • De Picture-in-Picture-vensterpositie kan niet door de website worden ingesteld.
Een Picture-in-Picture-venster waarin Sintel-trailervideo wordt afgespeeld.
Een Picture-in-Picture-venster gemaakt met de Document Picture-in-Picture API ( demo ).

Huidige status

Stap Status
1. Maak een uitleg Compleet
2. Maak een eerste ontwerp van specificatie In uitvoering
3. Verzamel feedback en herhaal het ontwerp In uitvoering
4. Oorsprongsproces Compleet
5. Lancering Compleet (bureaublad)

Gebruiksgevallen

Aangepaste videospeler

Een website kan een Picture-in-Picture-video-ervaring bieden met de bestaande Picture-in-Picture API voor <video> , maar deze is zeer beperkt. Het bestaande Picture-in-Picture-venster accepteert weinig invoer en heeft beperkte mogelijkheden om deze op te maken. Met een volledig Document in Picture-in-Picture kan de website aangepaste bedieningselementen en invoer bieden (bijvoorbeeld ondertitels , afspeellijsten, tijdscrubber, video's leuk of niet leuk vinden) om de Picture-in-Picture-video-ervaring van de gebruiker te verbeteren.

Videoconferenties

Het is gebruikelijk dat gebruikers het browsertabblad verlaten tijdens een videoconferentiesessie om verschillende redenen (bijvoorbeeld door een ander tabblad aan het gesprek te presenteren of te multitasken) terwijl ze het gesprek toch willen zien. Dit is dus een prima gebruiksvoorbeeld voor Picture-in- Afbeelding. Nogmaals, de huidige ervaring die een website voor videoconferenties kan bieden via de Picture-in-Picture API voor <video> is beperkt in stijl en invoer. Met een volledig Document in Picture-in-Picture kan de website eenvoudig meerdere videostreams combineren in één PiP-venster zonder afhankelijk te zijn van canvas-hacks en aangepaste bedieningselementen bieden, zoals het verzenden van een bericht, het dempen van een andere gebruiker of het opsteken van een hand.

Productiviteit

Onderzoek heeft aangetoond dat gebruikers meer manieren nodig hebben om productief te zijn op internet. Document in Picture-in-Picture geeft webapps de flexibiliteit om meer te bereiken. Of het nu gaat om tekstbewerking, het maken van aantekeningen, takenlijsten, berichtenuitwisseling en chatten, of ontwerp- en ontwikkelingstools, webapps kunnen hun inhoud nu altijd toegankelijk houden.

Interface

Eigenschappen

documentPictureInPicture.window
Retourneert het huidige Picture-in-Picture-venster, indien aanwezig. Anders wordt null geretourneerd.

Methoden

documentPictureInPicture.requestWindow(options)

Retourneert een belofte die wordt opgelost wanneer een Picture-in-Picture-venster wordt geopend. De belofte wordt afgewezen als deze wordt gebeld zonder een gebruikersgebaar. Het options bevat de optionele volgende leden:

width
Stelt de initiële breedte van het Picture-in-Picture-venster in.
height
Stelt de beginhoogte van het Picture-in-Picture-venster in.
disallowReturnToOpener
Verbergt de knop "Terug naar tabblad" in het Picture-in-Picture-venster als dit waar is. Het is standaard onwaar.
preferInitialWindowPlacement
Open het Picture-in-Picture-venster in de standaardpositie en -grootte, indien waar. Het is standaard onwaar.

Evenementen

documentPictureInPicture.onenter
Wordt geactiveerd op documentPictureInPicture wanneer een Picture-in-Picture-venster wordt geopend.

Voorbeelden

Met de volgende HTML wordt een aangepaste videospeler en een knopelement ingesteld om de videospeler in een Picture-in-Picture-venster te openen.

<div id="playerContainer">
  <div id="player">
    <video id="video"></video>
  </div>
</div>
<button id="pipButton">Open Picture-in-Picture window</button>

Open een Picture-in-Picture-venster

Het volgende JavaScript roept documentPictureInPicture.requestWindow() aan wanneer de gebruiker op de knop klikt om een ​​leeg Picture-in-Picture-venster te openen. De geretourneerde belofte wordt opgelost met een Picture-in-Picture-venster JavaScript-object. De videospeler wordt met append() naar dat venster verplaatst.

pipButton.addEventListener('click', async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

Stel de grootte van het Picture-in-Picture-venster in

Om de grootte van het Picture-in-Picture-venster in te stellen, stelt u de width en height opties van documentPictureInPicture.requestWindow() in op de gewenste Picture-in-Picture-venstergrootte. Chrome kan de optiewaarden vastzetten als deze te groot of te klein zijn voor een gebruiksvriendelijke venstergrootte.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window whose size is
  // the same as the player's.
  const pipWindow = await documentPictureInPicture.requestWindow({
    width: player.clientWidth,
    height: player.clientHeight,
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

Verberg de knop "Terug naar tabblad" van het Picture-in-Picture-venster

Om de knop in het Picture-in-Picture-venster te verbergen waarmee de gebruiker terug kan gaan naar het opener-tabblad, stelt u de disallowReturnToOpener -optie van documentPictureInPicture.requestWindow() in op true .

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window which hides the "back to tab" button.
  const pipWindow = await documentPictureInPicture.requestWindow({
    disallowReturnToOpener: true,
  });
});

Open het Picture-in-Picture-venster in de standaardpositie en -grootte

Als u de positie of grootte van het vorige Picture-in-Picture-venster niet opnieuw wilt gebruiken, stelt u de optie preferInitialWindowPlacement van documentPictureInPicture.requestWindow() in op true .

pipButton.addEventListener("click", async () => {
  // Open a Picture-in-Picture window in its default position / size.
  const pipWindow = await documentPictureInPicture.requestWindow({
    preferInitialWindowPlacement: true,
  });
});

Kopieer stijlbladen naar het Picture-in-Picture-venster

Om alle CSS-stijlbladen uit het oorspronkelijke venster te kopiëren, loopt u door styleSheets die expliciet zijn gekoppeld aan of ingebed in het document en voegt u deze toe aan het Picture-in-Picture-venster. Let op: dit is een eenmalige kopie.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Copy style sheets over from the initial document
  // so that the player looks the same.
  [...document.styleSheets].forEach((styleSheet) => {
    try {
      const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join('');
      const style = document.createElement('style');

      style.textContent = cssRules;
      pipWindow.document.head.appendChild(style);
    } catch (e) {
      const link = document.createElement('link');

      link.rel = 'stylesheet';
      link.type = styleSheet.type;
      link.media = styleSheet.media;
      link.href = styleSheet.href;
      pipWindow.document.head.appendChild(link);
    }
  });

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);
});

Behandelen wanneer het Picture-in-Picture-venster sluit

Luister naar de gebeurtenis "pagehide" van het venster om te weten wanneer het Picture-in-Picture-venster wordt gesloten (omdat de website dit heeft gestart of omdat de gebruiker het handmatig heeft gesloten). De gebeurtenishandler is een goede plek om de elementen terug uit het Picture-in-Picture-venster te halen, zoals hieronder weergegeven.

pipButton.addEventListener("click", async () => {
  const player = document.querySelector("#player");

  // Open a Picture-in-Picture window.
  const pipWindow = await documentPictureInPicture.requestWindow();

  // Move the player to the Picture-in-Picture window.
  pipWindow.document.body.append(player);

  // Move the player back when the Picture-in-Picture window closes.
  pipWindow.addEventListener("pagehide", (event) => {
    const playerContainer = document.querySelector("#playerContainer");
    const pipPlayer = event.target.querySelector("#player");
    playerContainer.append(pipPlayer);
  });
});

Sluit het Picture-in-Picture-venster programmatisch met behulp van de close() -methode.

// Close the Picture-in-Picture window programmatically. 
// The "pagehide" event will fire normally.
pipWindow.close();

Luister wanneer de website Picture-in-Picture opent

Luister naar de gebeurtenis "enter" op documentPictureInPicture om te weten wanneer een Picture-in-Picture-venster wordt geopend. De gebeurtenis bevat een window waarmee u toegang krijgt tot het Picture-in-Picture-venster.

documentPictureInPicture.addEventListener("enter", (event) => {
  const pipWindow = event.window;
});

Toegang tot elementen in het Picture-in-Picture-venster

Krijg toegang tot elementen in het Picture-in-Picture-venster via het object dat wordt geretourneerd door documentPictureInPicture.requestWindow() of met documentPictureInPicture.window , zoals hieronder wordt weergegeven.

const pipWindow = documentPictureInPicture.window;
if (pipWindow) {
  // Mute video playing in the Picture-in-Picture window.
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
}

Behandel gebeurtenissen vanuit het Picture-in-Picture-venster

Maak knoppen en bedieningselementen en reageer op invoergebeurtenissen van de gebruiker, zoals "click" zoals u normaal zou doen in JavaScript.

// Add a "mute" button to the Picture-in-Picture window.
const pipMuteButton = pipWindow.document.createElement("button");
pipMuteButton.textContent = "Mute";
pipMuteButton.addEventListener("click", () => { 
  const pipVideo = pipWindow.document.querySelector("#video");
  pipVideo.muted = true;
});
pipWindow.document.body.append(pipMuteButton);

Wijzig het formaat van het Picture-in-Picture-venster

Gebruik de methoden resizeBy() en resizeTo() Window om het formaat van het Picture-in-Picture-venster te wijzigen. Voor beide methoden is een gebruikersgebaar vereist.

const resizeButton = pipWindow.document.createElement('button');
resizeButton.textContent = 'Resize';
resizeButton.addEventListener('click', () => {
  // Expand the Picture-in-Picture window's width by 20px and height by 30px.
  pipWindow.resizeBy(20, 30);
});
pipWindow.document.body.append(resizeButton);

Stel het openervenster scherp

Gebruik de focus() Window-methode om het openingsvenster vanuit het Picture-in-Picture-venster scherp te stellen. Voor deze methode is een gebruikersgebaar vereist.

const returnToTabButton = pipWindow.document.createElement("button");
returnToTabButton.textContent = "Return to opener tab";
returnToTabButton.addEventListener("click", () => {
  window.focus();
});
pipWindow.document.body.append(returnToTabButton);

CSS beeld-in-beeld weergavemodus

Gebruik de CSS picture-in-picture weergavemodus om specifieke CSS-regels te schrijven die alleen worden toegepast wanneer (een deel van) de webapp wordt weergegeven in de Picture-in-Picture-modus.

@media all and (display-mode: picture-in-picture) {
  body {
    margin: 0;
  }
  h1 {
    font-size: 0.8em;
  }
}

Functiedetectie

Om te controleren of de Document Picture-in-Picture API wordt ondersteund, gebruikt u:

if ('documentPictureInPicture' in window) {
  // The Document Picture-in-Picture API is supported.
}

Demo's

VideoJS-speler

Je kunt spelen met de Document Picture-in-Picture API VideoJS player-demo . Zorg ervoor dat u de broncode bekijkt.

Pomodoro

Tomodoro , een pomodoro-webapp, maakt ook gebruik van de Document Picture-in-Picture API, indien beschikbaar (zie GitHub pull request ).

Screenshot van Tomodoro, een pomodoro-webapp.
Een Picture-in-Picture-venster in Tomodoro.

Feedback

Dien problemen op GitHub in met suggesties en vragen.

Dankbetuigingen

Heldenafbeelding door Jakob Owens .