एक्सकैलिड्रॉ और फुगु: उपयोगकर्ताओं के मुख्य अनुभवों को बेहतर बनाना

काफ़ी बेहतर टेक्नोलॉजी को जादू से पहचाना नहीं जा सकता. जब तक आपको समझ न आए. मेरा नाम थॉमस स्टेनर है. मैं Google में डेवलपर रिलेशन में काम करता/करती हूं. Google I/O बातचीत के इस राइट-अप लेख में, मुझे नए Fugu API के बारे में जानकारी दी जाएगी. साथ ही, यह भी पता चलेगा कि वे Excalidraw PWA में उपयोगकर्ता की गतिविधियों को कैसे बेहतर बनाते हैं, ताकि आप इन आइडिया से प्रेरणा लेकर उन्हें अपने ऐप्लिकेशन पर लागू कर सकें.

मैं एक्सकैलिड्रॉ कैसे आया

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

Excalidraw प्रोटोटाइप ऐप्लिकेशन का स्क्रीनशॉट, जिसमें दिखाया गया है कि यह रेक्टैंगल, ऐरो, एलिप्सिस, और टेक्स्ट के साथ काम करता है.

15 जनवरी को, क्रिस्टोफ़र ने एक ब्लॉग पोस्ट डाला, जिसने मेरे साथ-साथ Twitter पर भी बहुत ध्यान खींचा. पोस्ट की शुरुआत कुछ शानदार आंकड़ों के साथ हुई थी:

  • 12 हज़ार यूनीक सक्रिय उपयोगकर्ता
  • GitHub पर 1.5 हज़ार स्टार
  • योगदान देने वाले 26 लोग

दो हफ़्ते पहले शुरू हुए प्रोजेक्ट के लिए, यह बिलकुल भी बुरा नहीं है. हालांकि, उस पोस्ट में मेरी दिलचस्पी ज़्यादा बढ़ी. क्रिस्टोफ़र ने लिखा कि उन्होंने इस बार एक नई चीज़ आज़माई: बिना किसी शर्त के पुल का अनुरोध करने वाले सभी लोगों को बिना किसी शर्त के ऐक्सेस देना. ब्लॉग पोस्ट पढ़ने के दिन, मुझे एक अनुरोध भी किया गया था. उसमें, Excalidraw में फ़ाइल सिस्टम ऐक्सेस एपीआई की सुविधा जोड़ दी गई थी. साथ ही, किसी सुविधा के अनुरोध को ठीक किया गया था.

उस ट्वीट का स्क्रीनशॉट जिसमें मैंने अपने पीआर की घोषणा की है.

मेरे पुल के अनुरोध को एक दिन बाद मर्ज कर दिया गया था और उसके बाद, मेरे पास पूरी तरह से ऐक्सेस करने का अधिकार था. कहने की ज़रूरत नहीं है, मैंने अपनी ताकत का गलत इस्तेमाल नहीं किया. साथ ही, योगदान देने वाले 149 लोगों में से किसी ने भी अब तक इसमें हिस्सा नहीं लिया है.

आज, Excalidraw एक पूरी तरह से इंस्टॉल किया जा सकने वाला प्रोग्रेसिव वेब ऐप्लिकेशन है, जिसे इंस्टॉल किया जा सकता है. इसमें ऑफ़लाइन सपोर्ट और शानदार डार्क मोड है. फ़ाइल सिस्टम ऐक्सेस एपीआई की मदद से, यह फ़ाइलों को खोलने और सेव करने की सुविधा भी देता है.

आज की स्थिति में, Excalidraw PWA का स्क्रीनशॉट.

इस बात पर लिपिस ने बात की

यह मेरी "मैं एक्सकैलिड्रॉव कैसे पहुंचा" कहानी का अंत है, लेकिन एक्सकैलिड्रॉ की कुछ शानदार सुविधाओं के बारे में बताने से पहले, मुझे पैनैयोटिस को पेश करते हुए खुशी हो रही है. इंटरनेट पर मौजूद पैनैयोटिस लिपिरिडिस, जिसे सिर्फ़ लिपिस के नाम से जाना जाता है, Excalidraw के लिए सबसे ज़्यादा योगदान देने वाला है. मैंने लिपियों से पूछा कि उन्हें अपना ज़्यादातर समय Excalidraw पर लगाने के लिए कौनसी चीज़ प्रेरित करती है:

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

मैं लिपि से पूरी तरह सहमत हूं. Excalidraw को इस्तेमाल करने वाले हर व्यक्ति को इसे फिर से इस्तेमाल करने के बहाने ढूंढने हैं.

एक्सकैलिड्रॉल का इस्तेमाल

अब मुझे आपको दिखाना है कि असल में, Excalidraw का इस्तेमाल कैसे किया जा सकता है. मैं बहुत अच्छा कलाकार नहीं हूं, लेकिन Google I/O लोगो काफ़ी सरल है, इसलिए मैं इसे आज़माकर देखूं. बॉक्स का नाम "i" है. लाइन, स्लैश, और "o" एक सर्कल हो सकता है. Shift को दबाकर रखें, ताकि आपको सही सर्कल मिल जाए. मैं स्लैश को थोड़ा आगे ले जाती हूं, ताकि यह बेहतर दिखे. अब "i" और "o" के लिए कुछ रंग हैं. नीला रंग अच्छा है. शायद कोई अलग फ़िल स्टाइल? सभी सॉलिड या क्रॉस-हैच? नहीं, यह शानदार लग रहा है. यह सटीक नहीं है, लेकिन यह एक्सकैलिड्रॉ का आइडिया है, इसलिए मुझे इसे सेव करने दो.

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

मुझे लोगो बदलने दें और "i" को लाल कर दो. अगर मैं अब फिर से सेव करें पर क्लिक करता हूं, तो मेरा बदलाव पहले की तरह फ़ाइल में सेव हो जाएगा. सबूत के तौर पर, मुझे कैनवस साफ़ करने दें और फ़ाइल को फिर से खोलने दें. जैसा कि आपको दिख रहा है, बदले गए लाल-नीले लोगो में फिर से वही बदलाव दिख रहा है.

फ़ाइलों के साथ काम करना

जो ब्राउज़र फ़िलहाल File System Access API के साथ काम नहीं करते उन पर, सेव करने का हर ऑपरेशन एक डाउनलोड होता है. इसलिए, जब मैं बदलाव करता/करती हूं, तो मेरे डाउनलोड फ़ोल्डर को भरने वाले फ़ाइल नाम में, बढ़ती हुई संख्या वाली कई फ़ाइलें सेव होती हैं. हालांकि, इस समस्या के बावजूद, मैं फ़ाइल को सेव कर सकता हूं.

फ़ाइलें खोलना

तो राज़ क्या है? अलग-अलग ब्राउज़र पर फ़ाइल खोलने और सेव करने की सुविधा कैसे काम करती है, जो File System Access API के साथ काम करता है या नहीं करता? Excalidraw में किसी फ़ाइल को loadFromJSON)( नाम के फ़ंक्शन में खोला जाता है. इससे fileOpen() फ़ंक्शन को कॉल किया जाता है.

export const loadFromJSON = async (localAppState: AppState) => {
  const blob = await fileOpen({
    description: 'Excalidraw files',
    extensions: ['.json', '.excalidraw', '.png', '.svg'],
    mimeTypes: ['application/json', 'image/png', 'image/svg+xml'],
  });
  return loadFromBlob(blob, localAppState);
};

मेरी लिखी हुई छोटी लाइब्रेरी से मिला fileOpen() फ़ंक्शन, जिसका नाम है ब्राउज़र-fs-access. इसे हम Excalidraw में इस्तेमाल करते हैं. यह लाइब्रेरी, लेगसी फ़ॉलबैक के साथ फ़ाइल सिस्टम ऐक्सेस एपीआई के ज़रिए फ़ाइल सिस्टम का ऐक्सेस देती है. इसलिए, इसे किसी भी ब्राउज़र में इस्तेमाल किया जा सकता है.

चलिए, सबसे पहले आपको यह बताते हैं कि एपीआई काम करता है या नहीं. स्वीकार किए गए MIME टाइप और फ़ाइल एक्सटेंशन पर बातचीत करने के बाद, इसका मुख्य हिस्सा File System Access API के फ़ंक्शन showOpenFilePicker() को कॉल करना है. यह फ़ंक्शन, फ़ाइलों का कलेक्शन या एक फ़ाइल दिखाता है. यह इस बात पर निर्भर करता है कि एक से ज़्यादा फ़ाइलें चुनी गई हैं या नहीं. अब सिर्फ़ फ़ाइल ऑब्जेक्ट पर फ़ाइल हैंडल रखने का समय बचता है, ताकि उसे फिर से वापस पाया जा सके.

export default async (options = {}) => {
  const accept = {};
  // Not shown: deal with extensions and MIME types.
  const handleOrHandles = await window.showOpenFilePicker({
    types: [
      {
        description: options.description || '',
        accept: accept,
      },
    ],
    multiple: options.multiple || false,
  });
  const files = await Promise.all(handleOrHandles.map(getFileWithHandle));
  if (options.multiple) return files;
  return files[0];
  const getFileWithHandle = async (handle) => {
    const file = await handle.getFile();
    file.handle = handle;
    return file;
  };
};

फ़ॉलबैक लागू करने के लिए, "file" टाइप के input एलिमेंट पर निर्भर करता है. स्वीकार किए जाने वाले MIME टाइप और एक्सटेंशन की तय की गई सहमति के बाद, अगला कदम इनपुट एलिमेंट पर प्रोग्राम के हिसाब से क्लिक करना होता है, ताकि फ़ाइल खोलने का डायलॉग बॉक्स दिखे. बदलाव करने पर, इसका मतलब है कि जब उपयोगकर्ता ने एक या एक से ज़्यादा फ़ाइलें चुनीं, तो प्रॉमिस का समाधान हो जाता है.

export default async (options = {}) => {
  return new Promise((resolve) => {
    const input = document.createElement('input');
    input.type = 'file';
    const accept = [
      ...(options.mimeTypes ? options.mimeTypes : []),
      options.extensions ? options.extensions : [],
    ].join();
    input.multiple = options.multiple || false;
    input.accept = accept || '*/*';
    input.addEventListener('change', () => {
      resolve(input.multiple ? Array.from(input.files) : input.files[0]);
    });
    input.click();
  });
};

फ़ाइलें सेव की जा रही हैं

अब सेव करने के लिए. Excalidraw में, सेव करने की प्रोसेस saveAsJSON() नाम के फ़ंक्शन में होती है. यह सबसे पहले, Excalidraw एलिमेंट के अरे को JSON में क्रम से दिखाता है, JSON को ब्लॉब में बदलता है, और फिर fileSave() नाम वाले फ़ंक्शन को कॉल करता है. इसी तरह, यह फ़ंक्शन ब्राउज़र-fs-access लाइब्रेरी से मिलता है.

export const saveAsJSON = async (
  elements: readonly ExcalidrawElement[],
  appState: AppState,
) => {
  const serialized = serializeAsJSON(elements, appState);
  const blob = new Blob([serialized], {
    type: 'application/vnd.excalidraw+json',
  });
  const fileHandle = await fileSave(
    blob,
    {
      fileName: appState.name,
      description: 'Excalidraw file',
      extensions: ['.excalidraw'],
    },
    appState.fileHandle,
  );
  return { fileHandle };
};

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

export default async (blob, options = {}, handle = null) => {
  options.fileName = options.fileName || 'Untitled';
  const accept = {};
  // Not shown: deal with extensions and MIME types.
  handle =
    handle ||
    (await window.showSaveFilePicker({
      suggestedName: options.fileName,
      types: [
        {
          description: options.description || '',
          accept: accept,
        },
      ],
    }));
  const writable = await handle.createWritable();
  await writable.write(blob);
  await writable.close();
  return handle;
};

"इस रूप में सेव करें" सुविधा

अगर मैं पहले से मौजूद किसी फ़ाइल हैंडल को अनदेखा करना चाहता/चाहती हूं, तो उस फ़ाइल के हिसाब से नई फ़ाइल बनाने के लिए, "इस रूप में सेव करें" सुविधा लागू की जा सकती है. इसे दिखाने के लिए, मुझे कोई मौजूदा फ़ाइल खोलने दें, उसमें कुछ बदलाव करने दें, और फिर मौजूदा फ़ाइल को ओवरराइट न करने दें. हालांकि, इसके लिए सेव करें सुविधा का इस्तेमाल करके एक नई फ़ाइल बनाएं. इससे ओरिजनल फ़ाइल में कोई बदलाव नहीं होता है.

File System Access API के साथ काम न करने वाले ब्राउज़र पर, इसे लागू करने की प्रोसेस कम होती है. ऐसा इसलिए होता है, क्योंकि इससे सिर्फ़ download एट्रिब्यूट की मदद से ऐंकर एलिमेंट बनाया जाता है. इसकी वैल्यू के लिए, मनचाहे फ़ाइल नाम की ज़रूरत होती है और href एट्रिब्यूट की वैल्यू के तौर पर एक blob यूआरएल बनाया जाता है.

export default async (blob, options = {}) => {
  const a = document.createElement('a');
  a.download = options.fileName || 'Untitled';
  a.href = URL.createObjectURL(blob);
  a.addEventListener('click', () => {
    setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000);
  });
  a.click();
};

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

खींचें और छोड़ें

डेस्कटॉप पर मेरे पसंदीदा सिस्टम इंटिग्रेशन में से एक है, 'खींचें और छोड़ें' सुविधा. Excalidraw में, जब मैं ऐप्लिकेशन पर .excalidraw फ़ाइल डालता हूं, तो वह तुरंत खुल जाती है और मुझे बदलाव करना शुरू करने का विकल्प मिलता है. File System Access API के साथ काम करने वाले ब्राउज़र में, किए गए बदलावों को तुरंत सेव किया जा सकता है. फ़ाइल सेव करने वाले डायलॉग पर जाने की ज़रूरत नहीं है, क्योंकि ज़रूरी फ़ाइल हैंडल, 'खींचें और छोड़ें' ऑपरेशन से मिल गया है.

ऐसा करने के लिए, डेटा ट्रांसफ़र आइटम पर getAsFileSystemHandle() को कॉल करें. ऐसा तब किया जाता है, जब File System Access API काम करता हो. इसके बाद, मैं इस फ़ाइल हैंडल को loadFromBlob() को पास कर देता हूं, जिसे आपको ऊपर दिए गए कुछ पैराग्राफ़ में याद हो सकता है. फ़ाइलों के साथ आप कई तरह के काम कर सकते हैं: खोलना, सेव करना, ज़्यादा सेव करना, खींचना, छोड़ना. मेरे सहयोगी पीट और मैंने अपने लेख में इन सभी तरकीबों के साथ-साथ और भी बहुत कुछ लिखा है, ताकि अगर ये चीज़ें थोड़ी तेज़ी से हो जाएं, तो आप इन सभी तरीकों को अच्छी तरह समझ सकें.

const file = event.dataTransfer?.files[0];
if (file?.type === 'application/json' || file?.name.endsWith('.excalidraw')) {
  this.setState({ isLoading: true });
  // Provided by browser-fs-access.
  if (supported) {
    try {
      const item = event.dataTransfer.items[0];
      file as any.handle = await item as any
        .getAsFileSystemHandle();
    } catch (error) {
      console.warn(error.name, error.message);
    }
  }
  loadFromBlob(file, this.state).then(({ elements, appState }) =>
    // Load from blob
  ).catch((error) => {
    this.setState({ isLoading: false, errorMessage: error.message });
  });
}

फ़ाइलें शेयर करना

Android, ChromeOS, और Windows पर फ़िलहाल एक और सिस्टम इंटिग्रेशन वेब शेयर टारगेट एपीआई के ज़रिए किया जा रहा है. यहां मैं Downloads फ़ोल्डर में Files ऐप्लिकेशन में हूं. मुझे दो फ़ाइलें दिख रही हैं. इनमें से एक की जानकारी नहीं है untitled और एक टाइमस्टैंप. यह देखने के लिए कि इसमें क्या-क्या है, तीन बिंदुओं पर क्लिक करें, फिर शेयर करें, आपको दिखने वाले विकल्पों में से एक एक्सकैलिड्रॉल है. आइकॉन पर टैप करने पर, मुझे दिखेगा कि फ़ाइल में I/O लोगो फिर से दिख रहा है.

अब काम न करने वाले Electron वर्शन पर लिपि का डेटा

मैंने जिन फ़ाइलों के बारे में अभी तक बात नहीं की है उनके साथ किया जा सकता है. उनके लिए आपको 'क्लिक-टू-एक्सेप्ट' सुविधा चालू करनी होगी. आम तौर पर, किसी फ़ाइल को फिर से चालू करने पर ऐसा होता है कि फ़ाइल के MIME टाइप से जुड़ा ऐप्लिकेशन खुल जाता है. उदाहरण के लिए, .docx के लिए यह Microsoft Word होगा.

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

लोग शुरुआत से ही Electron ऐप्लिकेशन मांग रहे हैं, क्योंकि वे दो बार क्लिक करके फ़ाइलें खोलना चाहते थे. हमारा मकसद ऐप्लिकेशन को ऐप स्टोर में भी उपलब्ध कराना था. साथ ही, किसी व्यक्ति ने PWA बनाने का सुझाव दिया, इसलिए हमने दोनों काम किए. अच्छी बात यह है कि हमें Project Fugu API का परिचय फ़ाइल सिस्टम ऐक्सेस, क्लिपबोर्ड ऐक्सेस, फ़ाइल हैंडलिंग वगैरह से मिला है. सिर्फ़ एक क्लिक से, सिर्फ़ अपने डेस्कटॉप या मोबाइल पर ऐप्लिकेशन इंस्टॉल किया जा सकता है. इसके लिए, आपको Electron के अतिरिक्त वज़न की चिंता करने की ज़रूरत नहीं है. Electron वर्शन को बंद करना, सिर्फ़ वेब ऐप्लिकेशन पर ध्यान देना, और इसे सबसे बेहतर PWA बनाना था, यह एक आसान फ़ैसला था. सबसे बड़ी बात, अब हम Play Store और Microsoft Store पर PWA पब्लिश कर सकते हैं! यह बहुत बड़ा है!

यह कहा जा सकता है कि इलेक्ट्रॉन के लिए Excalidraw को बंद नहीं किया गया था, क्योंकि इलेक्ट्रॉन खराब है, बिलकुल भी नहीं, बल्कि इसलिए क्योंकि वेब काफ़ी अच्छा बन चुका है. मुझे यह पसंद है!

फ़ाइल मैनेज करना

जब मैं कहता/कहती हूं कि "वेब अब अच्छा हो गया है", तो ऐसा आने वाले फ़ाइल हैंडलिंग जैसी सुविधाओं की वजह से होता है.

यह macOS Big Sur पर नियमित तौर पर इंस्टॉल किया जाता है. अब देखें कि Excalidraw फ़ाइल पर राइट क्लिक करने से क्या होता है. मेरे पास इसे इंस्टॉल किए गए PWA, Excalidraw के साथ खोलने का विकल्प है. बेशक, डबल-क्लिक करने से भी नतीजे दिखाए जा सकते हैं. स्क्रीनकास्ट में दिखाना काफ़ी कम नाटकीय है.

यह कैसे काम करता है? पहला कदम यह है कि ऑपरेटिंग सिस्टम पर ऐसे फ़ाइल टाइप बनाए जाएं जिन्हें मेरा ऐप्लिकेशन हैंडल कर सके. मैं इसे वेब ऐप्लिकेशन मेनिफ़ेस्ट में file_handlers नाम के नए फ़ील्ड में करता/करती हूं. इसकी वैल्यू, कार्रवाई और accept प्रॉपर्टी के साथ ऑब्जेक्ट का कलेक्शन है. यह कार्रवाई तय करती है कि ऑपरेटिंग सिस्टम किस यूआरएल पाथ पर आपके ऐप्लिकेशन को लॉन्च करेगा. साथ ही, MIME टाइप और उससे जुड़े फ़ाइल एक्सटेंशन के मुख्य वैल्यू पेयर को स्वीकार किया जाने वाला ऑब्जेक्ट माना जाता है.

{
  "name": "Excalidraw",
  "description": "Excalidraw is a whiteboard tool...",
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff",
  "file_handlers": [
    {
      "action": "/",
      "accept": {
        "application/vnd.excalidraw+json": [".excalidraw"]
      }
    }
  ]
}

अगला चरण ऐप्लिकेशन लॉन्च होने पर फ़ाइल को हैंडल करना है. यह launchQueue इंटरफ़ेस में होगा, जहां मुझे setConsumer() को कॉल करके, उपभोक्ता को चुनना होगा. इस फ़ंक्शन का पैरामीटर एक एसिंक्रोनस फ़ंक्शन है, जो launchParams पाता है. इस launchParams ऑब्जेक्ट में फ़ाइल नाम का एक फ़ील्ड है. इसमें मुझे कई फ़ाइल हैंडल मिलते हैं, जिन पर मैं काम कर सकता हूं. मुझे सिर्फ़ पहले वाले बटन की परवाह है और इस फ़ाइल हैंडल से मुझे एक ब्लॉब मिलता है, जिसे मैं अपने पुराने दोस्त loadFromBlob() को भेज देता हूं.

if ('launchQueue' in window && 'LaunchParams' in window) {
  window as any.launchQueue
    .setConsumer(async (launchParams: { files: any[] }) => {
      if (!launchParams.files.length) return;
      const fileHandle = launchParams.files[0];
      const blob: Blob = await fileHandle.getFile();
      blob.handle = fileHandle;
      loadFromBlob(blob, this.state).then(({ elements, appState }) =>
        // Initialize app state.
      ).catch((error) => {
        this.setState({ isLoading: false, errorMessage: error.message });
      });
    });
}

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

क्लिपबोर्ड इंटिग्रेशन

Excalidraw की एक और बेहतरीन सुविधा है क्लिपबोर्ड इंटिग्रेशन. मैं अपनी पूरी ड्रॉइंग या उसके कुछ हिस्सों को क्लिपबोर्ड पर कॉपी कर सकता हूं. चाहें, तो वॉटरमार्क जोड़कर किसी दूसरे ऐप्लिकेशन में चिपकाया जा सकता है. वैसे, यह Windows 95 Paint ऐप्लिकेशन का वेब वर्शन है.

इसके काम करने का तरीका बेहद आसान है. मुझे सिर्फ़ ब्लॉब के तौर पर कैनवस की ज़रूरत है. इसके बाद, इसे क्लिपबोर्ड पर लिखने के लिए, ब्लॉब के साथ ClipboardItem के साथ एक एलिमेंट वाली अरे को navigator.clipboard.write() फ़ंक्शन में पास किया जाएगा. क्लिपबोर्ड एपीआई की मदद से क्या-क्या किया जा सकता है, इस बारे में ज़्यादा जानने के लिए जेसन और मेरा लेख पढ़ें.

export const copyCanvasToClipboardAsPng = async (canvas: HTMLCanvasElement) => {
  const blob = await canvasToBlob(canvas);
  await navigator.clipboard.write([
    new window.ClipboardItem({
      'image/png': blob,
    }),
  ]);
};

export const canvasToBlob = async (canvas: HTMLCanvasElement): Promise<Blob> => {
  return new Promise((resolve, reject) => {
    try {
      canvas.toBlob((blob) => {
        if (!blob) {
          return reject(new CanvasError(t('canvasError.canvasTooBig'), 'CANVAS_POSSIBLY_TOO_BIG'));
        }
        resolve(blob);
      });
    } catch (error) {
      reject(error);
    }
  });
};

दूसरों के साथ मिलकर काम करना

सेशन का यूआरएल शेयर करना

क्या आपको पता है कि Excalidraw में मिलकर काम करने की सुविधा भी है? अलग-अलग लोग एक ही दस्तावेज़ पर एक साथ काम कर सकते हैं. नया सेशन शुरू करने के लिए, लाइव मिलकर काम करने के बटन पर क्लिक करें. इसके बाद, सेशन शुरू करें. मैं Excalidraw के साथ इंटिग्रेट किए गए Web Share API की मदद से, अपने सहयोगियों के साथ सेशन का यूआरएल आसानी से शेयर कर सकता हूं.

लाइव साथ मिलकर काम करने की सुविधा

मैंने अपने Pixelbook, Pixel 3a फ़ोन, और iPad Pro पर Google I/O लोगो पर काम करके, स्थानीय तौर पर कोलैब सेशन सिम्युलेट किया. आपने देखा होगा कि एक डिवाइस पर मेरे किए गए बदलाव, दूसरे सभी डिवाइसों पर भी लागू होते हैं.

यहां तक कि मैं सभी कर्सर को इधर-उधर जाता हुआ भी देख सकता हूँ. Pixelbook का कर्सर एक जगह से मूव करता है, क्योंकि इसे ट्रैकपैड से कंट्रोल किया जाता है. हालांकि, Pixel 3a फ़ोन का कर्सर और iPad Pro के टैबलेट का कर्सर इधर-उधर कूदता है, क्योंकि मैं अपनी उंगली से टैप करके इन डिवाइसों को कंट्रोल करती हूँ.

सहयोगी की स्थितियां देखी जा रही हैं

साथ ही, रीयल टाइम में साथ मिलकर काम करने के अनुभव को बेहतर बनाने के लिए, सिस्टम कुछ समय से इस्तेमाल में न होने पर भी काम कर रहा है. iPad Pro का इस्तेमाल करने पर, कर्सर पर हरा बिंदु दिखता है. जब मैं किसी दूसरे ब्राउज़र टैब या ऐप्लिकेशन पर स्विच करता/करती हूँ, तो यह बिंदु काला हो जाता है. साथ ही, जब मैं Excalidraw ऐप्लिकेशन पर हूँ, लेकिन कुछ भी नहीं कर रहा होता हूँ, तो कर्सर मुझे कुछ काम नहीं करता हुआ दिखाता है. इस सिंबल के तौर पर तीन zZZs हैं.

हमारे पब्लिकेशन के पढ़ने में दिलचस्पी रखने वाले लोगों को यह लग सकता है कि कोई गतिविधि न होने का पता लगाने के लिए, आइडल डिटेक्शन एपीआई का इस्तेमाल किया गया है. यह एक शुरुआती प्रस्ताव है जिस पर Project Fugu के संदर्भ में काम किया गया है. स्पॉइलर अलर्ट: ऐसा नहीं है. हालांकि, हमने Excalidraw में इस एपीआई को लागू किया था, लेकिन आखिर में हमने पॉइंटर के मूवमेंट और पेज दिखने की सेटिंग पर आधारित परंपरागत तरीके को लागू करने का फ़ैसला किया.

WICG आइडल डिटेक्शन रेपो में फ़ाइल किए गए डिवाइस के कुछ समय से इस्तेमाल में न होने की पहचान करने के सुझाव का स्क्रीनशॉट.

हमने इस बारे में सुझाव सबमिट किया कि डिवाइस कुछ समय से इस्तेमाल में न होने की पहचान करने वाला एपीआई, हमारे इस्तेमाल के उदाहरण को क्यों हल नहीं कर रहा है. Project Fugu के सभी एपीआई ओपन करके डेवलप किए जा रहे हैं, ताकि सभी लोग इसमें शामिल हो सकें और अपनी बात रख सकें!

एक्सकैलिड्रॉव को पीछे की ओर पकड़े हुए लिपिज़

इसके बारे में बात करते हुए, मैंने लिपि से एक आखिरी सवाल पूछा कि उन्हें क्या लगता है कि Excalidraw को होल्ड करने वाले वेब प्लैटफ़ॉर्म पर क्या नहीं है:

File System Access API बहुत अच्छा है, लेकिन क्या आपको पता है? इन दिनों मेरी पसंदीदा फ़ाइलें मेरे Dropbox या Google Drive में रहती हैं, न कि हार्ड डिस्क में. मैं चाहता हूं कि File System Access API रिमोट फ़ाइल सिस्टम प्रोवाइडर जैसे कि Dropbox या Google के लिए एक ऐब्स्ट्रैक्शन लेयर शामिल करे, ताकि इसके साथ इंटिग्रेट किया जा सके और डेवलपर कोड कर सकें. इससे उपयोगकर्ता आराम कर सकते हैं और जान सकते हैं कि उनकी फ़ाइलें भरोसेमंद क्लाउड प्रोवाइडर के पास सुरक्षित हैं.

मैं लिपि से पूरी तरह सहमत हूं, मैं क्लाउड में भी रहता हूं. ऐसी उम्मीद है कि इसे जल्द ही लागू किया जाएगा.

टैब वाला ऐप्लिकेशन मोड

वाह! हमने Excalidraw में बहुत अच्छे एपीआई इंटिग्रेशन देखे हैं. फ़ाइल सिस्टम, फ़ाइल हैंडलिंग, क्लिपबोर्ड, वेब शेयर, और वेब शेयर टारगेट. हालांकि, यहां एक और बात बताई गई है. अब तक, मैं एक बार में एक ही दस्तावेज़ में बदलाव कर सकती थी. अब नहीं. कृपया Excalidraw में टैब किए गए ऐप्लिकेशन मोड के शुरुआती वर्शन का पहली बार आनंद लें. यह ऐसा दिखता है.

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

टैब वाले ऐप्लिकेशन मोड अभी शुरुआती दौर में है. इसमें बाकी सब कुछ सेट नहीं किया जा सकता. अगर आप इसमें दिलचस्पी रखते हैं, तो मेरे लेख में इस सुविधा की मौजूदा स्थिति के बारे में ज़रूर पढ़ें.

आखिरी हिस्सा

इस और अन्य सुविधाओं के बारे में अप-टू-डेट रहने के लिए, हमारे Fugu API ट्रैकर को देखना न भूलें. हम वेब को आगे बढ़ाने और आपको इस प्लैटफ़ॉर्म पर ज़्यादा काम करने की सुविधा देने को लेकर बहुत उत्साहित हैं. Excalidraw का इस्तेमाल, और बेहतर हो रहा है. इसके लिए, आपके बनाए गए सभी शानदार ऐप्लिकेशन के बारे में जानकारी दी गई है. excalidraw.com पर जाकर वीडियो बनाना शुरू करें.

मुझे आपके ऐप्लिकेशन में कुछ एपीआई के पॉप-अप देखने का बेसब्री से इंतज़ार है. मेरा नाम टॉम है. मुझे Twitter और इंटरनेट पर, @toMAac के तौर पर मिल सकता है. वीडियो देखने के लिए धन्यवाद और Google I/O की बाकी सुविधाओं का आनंद लें.