Mengelola beberapa tampilan dengan Window Management API

Mendapatkan informasi tentang layar yang terhubung dan memosisikan jendela relatif terhadap layar tersebut.

Window Management API

Window Management API memungkinkan Anda menghitung tampilan yang terhubung ke komputer dan menempatkan jendela di layar tertentu.

Kasus penggunaan yang disarankan

Contoh situs yang dapat menggunakan API ini meliputi:

  • Editor grafis multi-aplikasi seperti Gimp dapat menempatkan berbagai alat pengeditan di jendela yang diposisikan secara akurat.
  • Meja perdagangan virtual dapat menampilkan tren pasar di beberapa jendela yang dapat dilihat dalam mode layar penuh.
  • Aplikasi slide show dapat menampilkan catatan pembicara di layar utama internal dan presentasi di projector eksternal.

Cara menggunakan Window Management API

Permasalahan

Pendekatan yang telah teruji untuk mengontrol jendela, Window.open(), sayangnya tidak mengetahui layar tambahan. Meskipun beberapa aspek API ini tampak sedikit kuno, seperti parameter windowFeatures DOMString, API ini telah melayani kami dengan baik selama bertahun-tahun. Untuk menentukan posisi jendela, Anda dapat meneruskan koordinat sebagai left dan top (atau screenX dan screenY) dan meneruskan ukuran yang diinginkan sebagai width dan height (atau innerWidth dan innerHeight). Misalnya, untuk membuka jendela 400x300 pada 50 piksel dari kiri dan 50 piksel dari atas, berikut kode yang dapat Anda gunakan:

const popup = window.open(
  'https://example.com/',
  'My Popup',
  'left=50,top=50,width=400,height=300',
);

Anda bisa mendapatkan informasi tentang layar saat ini dengan melihat properti window.screen, yang menampilkan objek Screen. Berikut adalah output di MacBook Pro 13″ saya:

window.screen;
/* Output from my MacBook Pro 13″:
  availHeight: 969
  availLeft: 0
  availTop: 25
  availWidth: 1680
  colorDepth: 30
  height: 1050
  isExtended: true
  onchange: null
  orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
  pixelDepth: 30
  width: 1680
*/

Seperti kebanyakan orang yang bekerja di bidang teknologi, saya harus menyesuaikan diri dengan realitas kerja yang baru dan menyiapkan kantor rumah pribadi saya. Mine looks like on the photo below (if you are interested, you can read full details about my setup). iPad di samping MacBook saya terhubung ke laptop melalui Sidecar, sehingga setiap kali diperlukan, saya dapat dengan cepat mengubah iPad menjadi layar kedua.

Bangku sekolah di atas dua kursi. Di atas bangku sekolah terdapat kotak sepatu yang menopang laptop dan dua iPad di sekitarnya.
Konfigurasi multilayar.

Jika ingin memanfaatkan layar yang lebih besar, saya dapat menempatkan pop-up dari contoh kode di atas ke layar kedua. Saya melakukannya seperti ini:

popup.moveTo(2500, 50);

Ini adalah perkiraan kasar, karena tidak ada cara untuk mengetahui dimensi layar kedua. Info dari window.screen hanya mencakup layar bawaan, tetapi tidak mencakup layar iPad. width layar bawaan yang dilaporkan adalah 1680 piksel, sehingga beralih ke 2500 piksel mungkin berfungsi untuk memindahkan jendela ke iPad, karena saya kebetulan tahu bahwa iPad berada di sebelah kanan MacBook saya. Bagaimana cara melakukannya secara umum? Ternyata, ada cara yang lebih baik daripada menebak. Caranya adalah Window Management API.

Deteksi fitur

Untuk memeriksa apakah Window Management API didukung, gunakan:

if ('getScreenDetails' in window) {
  // The Window Management API is supported.
}

Izin window-management

Sebelum dapat menggunakan Window Management API, saya harus meminta izin kepada pengguna untuk melakukannya. Izin window-management dapat dikueri dengan Permissions API seperti ini:

let granted = false;
try {
  const { state } = await navigator.permissions.query({ name: 'window-management' });
  granted = state === 'granted';
} catch {
  // Nothing.
}

Saat browser dengan nama izin lama dan baru digunakan, pastikan untuk menggunakan kode defensif saat meminta izin, seperti dalam contoh di bawah.

async function getWindowManagementPermissionState() {
  let state;
  // The new permission name.
  try {
    ({ state } = await navigator.permissions.query({
      name: "window-management",
    }));
  } catch (err) {
    return `${err.name}: ${err.message}`;
  }
  return state;
}

document.querySelector("button").addEventListener("click", async () => {
  const state = await getWindowManagementPermissionState();
  document.querySelector("pre").textContent = state;
});

Browser dapat memilih untuk menampilkan perintah izin secara dinamis pada upaya pertama untuk menggunakan salah satu metode API baru. Baca terus untuk mempelajari lebih lanjut.

Properti window.screen.isExtended

Untuk mengetahui apakah lebih dari satu layar terhubung ke perangkat saya, saya mengakses properti window.screen.isExtended. Fungsi ini menampilkan true atau false. Untuk penyiapan saya, metode ini menampilkan true.

window.screen.isExtended;
// Returns `true` or `false`.

Metode getScreenDetails()

Setelah mengetahui bahwa penyiapan saat ini adalah multi-layar, saya dapat memperoleh informasi selengkapnya tentang layar kedua menggunakan Window.getScreenDetails(). Memanggil fungsi ini akan menampilkan perintah izin yang bertanya apakah situs dapat membuka dan menempatkan jendela di layar saya. Fungsi ini menampilkan promise yang diselesaikan dengan objek ScreenDetailed. Di MacBook Pro 13 saya dengan iPad yang terhubung, ini mencakup kolom screens dengan dua objek ScreenDetailed:

await window.getScreenDetails();
/* Output from my MacBook Pro 13″ with the iPad attached:
{
  currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …}
  oncurrentscreenchange: null
  onscreenschange: null
  screens: [{
    // The MacBook Pro
    availHeight: 969
    availLeft: 0
    availTop: 25
    availWidth: 1680
    colorDepth: 30
    devicePixelRatio: 2
    height: 1050
    isExtended: true
    isInternal: true
    isPrimary: true
    label: "Built-in Retina Display"
    left: 0
    onchange: null
    orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
    pixelDepth: 30
    top: 0
    width: 1680
  },
  {
    // The iPad
    availHeight: 999
    availLeft: 1680
    availTop: 25
    availWidth: 1366
    colorDepth: 24
    devicePixelRatio: 2
    height: 1024
    isExtended: true
    isInternal: false
    isPrimary: false
    label: "Sidecar Display (AirPlay)"
    left: 1680
    onchange: null
    orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
    pixelDepth: 24
    top: 0
    width: 1366
  }]
}
*/

Informasi tentang layar yang terhubung tersedia di array screens. Perhatikan bagaimana nilai left untuk iPad dimulai dari 1680, yang sama persis dengan width layar bawaan. Hal ini memungkinkan saya menentukan dengan tepat bagaimana layar disusun secara logis (berdampingan, di atas satu sama lain, dll.). Sekarang juga ada data untuk setiap layar guna menunjukkan apakah layar tersebut adalah layar isInternal atau layar isPrimary. Perhatikan bahwa layar bawaan tidak harus merupakan layar utama.

Kolom currentScreen adalah objek aktif yang sesuai dengan window.screen saat ini. Objek diperbarui pada penempatan jendela lintas layar atau perubahan perangkat.

Peristiwa screenschange

Satu-satunya hal yang hilang sekarang adalah cara untuk mendeteksi kapan konfigurasi layar saya berubah. Peristiwa baru, screenschange, melakukan hal itu: peristiwa ini diaktifkan setiap kali konstelasi layar diubah. (Perhatikan bahwa "screens" adalah bentuk jamak dalam nama peristiwa.) Artinya, peristiwa diaktifkan setiap kali layar baru atau layar yang ada (secara fisik atau virtual dalam kasus Sidecar) dicolokkan atau dicabut.

Perhatikan bahwa Anda perlu mencari detail layar baru secara asinkron, peristiwa screenschange itu sendiri tidak memberikan data ini. Untuk mencari detail layar, gunakan objek live dari antarmuka Screens yang di-cache.

const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
screenDetails.addEventListener('screenschange', (event) => {
  if (screenDetails.screens.length !== cachedScreensLength) {
    console.log(
      `The screen count changed from ${cachedScreensLength} to ${screenDetails.screens.length}`,
    );
    cachedScreensLength = screenDetails.screens.length;
  }
});

Peristiwa currentscreenchange

Jika hanya tertarik dengan perubahan pada layar saat ini (yaitu, nilai objek live currentScreen), saya dapat memproses peristiwa currentscreenchange.

const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
  const details = screenDetails.currentScreen;
  console.log('The current screen has changed.', event, details);
});

Peristiwa change

Terakhir, jika hanya tertarik dengan perubahan pada layar tertentu, saya dapat memproses peristiwa change layar tersebut.

const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
  console.log('The first screen has changed.', event, firstScreen);
});

Opsi layar penuh baru

Hingga saat ini, Anda dapat meminta agar elemen ditampilkan dalam mode layar penuh melalui metode requestFullScreen() yang dinamai dengan tepat. Metode ini menggunakan parameter options tempat Anda dapat meneruskan FullscreenOptions. Sejauh ini, satu-satunya propertinya adalah navigationUI. Window Management API menambahkan properti screen baru yang memungkinkan Anda menentukan layar tempat tampilan layar penuh dimulai. Misalnya, jika Anda ingin membuat layar utama berukuran penuh:

try {
  const primaryScreen = (await getScreenDetails()).screens.filter((screen) => screen.isPrimary)[0];
  await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
  console.error(err.name, err.message);
}

Polyfill

Anda tidak dapat melakukan polyfill pada Window Management API, tetapi Anda dapat melakukan shim pada bentuknya sehingga Anda dapat membuat kode secara eksklusif terhadap API baru:

if (!('getScreenDetails' in window)) {
  // Returning a one-element array with the current screen,
  // noting that there might be more.
  window.getScreenDetails = async () => [window.screen];
  // Set to `false`, noting that this might be a lie.
  window.screen.isExtended = false;
}

Aspek lain dari API, yaitu berbagai peristiwa perubahan layar dan properti screen FullscreenOptions, tidak akan pernah diaktifkan atau diabaikan secara diam-diam oleh browser yang tidak mendukung.

Demo

Jika Anda seperti saya, Anda terus memantau perkembangan berbagai mata uang kripto. (Sebenarnya saya tidak ingin melakukannya karena saya mencintai planet ini, tetapi, untuk artikel ini, anggap saja saya ingin melakukannya.) Untuk melacak cryptocurrency yang saya miliki, saya telah mengembangkan aplikasi web yang memungkinkan saya memantau pasar dalam semua situasi kehidupan, seperti dari kenyamanan tempat tidur saya, tempat saya memiliki penyiapan layar tunggal yang bagus.

Layar TV besar di ujung tempat tidur dengan kaki penulis yang terlihat sebagian. Di layar, terdapat meja perdagangan mata uang kripto palsu.
Bersantai dan mengamati pasar.

Karena ini adalah tentang mata uang kripto, pasar dapat menjadi kacau kapan saja. Jika hal ini terjadi, saya dapat dengan cepat berpindah ke meja kerja tempat saya memiliki penyiapan multilayar. Saya dapat mengklik jendela mata uang mana pun dan dengan cepat melihat detail lengkapnya dalam tampilan layar penuh di layar yang berlawanan. Berikut adalah foto terbaru saya yang diambil selama perang berdarah YCY terakhir. Hal itu membuat saya sama sekali tidak siap dan membuat saya menutupi wajah dengan tangan.

Penulis dengan tangan di wajahnya yang panik menatap meja perdagangan mata uang kripto palsu.
Panik, menyaksikan pembantaian YCY.

Anda dapat memainkan demo yang disematkan di bawah, atau melihat kode sumbernya di glitch.

Keamanan dan izin

Tim Chrome telah mendesain dan menerapkan Window Management API menggunakan prinsip inti yang ditentukan dalam Mengontrol Akses ke Fitur Platform Web yang Andal, termasuk kontrol pengguna, transparansi, dan ergonomi. Window Management API mengekspos informasi baru tentang layar yang terhubung ke perangkat, sehingga meningkatkan platform pengambilan sidik jari pengguna, terutama pengguna dengan beberapa layar yang terhubung secara konsisten ke perangkat mereka. Sebagai salah satu mitigasi masalah privasi ini, properti layar yang ditampilkan dibatasi hingga minimum yang diperlukan untuk kasus penggunaan penempatan umum. Izin pengguna diperlukan agar situs dapat mendapatkan informasi multilayar dan menempatkan jendela di layar lain. Meskipun Chromium menampilkan label layar yang mendetail, browser bebas menampilkan label yang kurang deskriptif (atau bahkan kosong).

Kontrol pengguna

Pengguna memiliki kontrol penuh atas eksposur penyiapannya. Mereka dapat menerima atau menolak permintaan izin, dan mencabut izin yang sebelumnya diberikan melalui fitur informasi situs di browser.

Kontrol perusahaan

Pengguna Chrome Enterprise dapat mengontrol beberapa aspek Window Management API seperti yang diuraikan di bagian yang relevan pada setelan Atomic Policy Groups.

Transparansi

Fakta apakah izin untuk menggunakan Window Management API telah diberikan ditampilkan di informasi situs browser dan juga dapat dikueri melalui Permissions API.

Persistensi izin

Browser mempertahankan pemberian izin. Izin dapat dicabut melalui informasi situs browser.

Masukan

Tim Chrome ingin mengetahui pengalaman Anda saat menggunakan Window Management API.

Ceritakan kepada kami tentang desain API

Apakah ada sesuatu tentang API yang tidak berfungsi seperti yang Anda harapkan? Atau apakah ada metode atau properti yang tidak ada yang Anda perlukan untuk menerapkan ide Anda? Ada pertanyaan atau komentar tentang model keamanan?

  • Ajukan masalah spesifikasi di repo GitHub yang sesuai, atau tambahkan pendapat Anda ke masalah yang ada.

Melaporkan masalah terkait penerapan

Apakah Anda menemukan bug pada penerapan Chrome? Atau apakah implementasinya berbeda dengan spesifikasi?

  • Ajukan bug di new.crbug.com. Pastikan untuk menyertakan detail sebanyak mungkin, petunjuk sederhana untuk mereproduksi, dan masukkan Blink>Screen>MultiScreen di kotak Components. Glitch sangat cocok untuk membagikan rekaman ulang yang cepat dan mudah.

Menampilkan dukungan untuk API

Apakah Anda berencana menggunakan Window Management API? Dukungan publik Anda membantu tim Chrome memprioritaskan fitur dan menunjukkan kepada vendor browser lain betapa pentingnya mendukung fitur tersebut.

Link bermanfaat

Ucapan terima kasih

Spesifikasi Window Management API diedit oleh Victor Costan, Joshua Bell, dan Mike Wasserman. API ini diimplementasikan oleh Mike Wasserman dan Adrienne Walker. Artikel ini ditinjau oleh Joe Medley, François Beaufort, dan Kayce Basques. Terima kasih kepada Laura Torrent Puig atas fotonya.