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

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

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

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

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

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

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

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

उस ट्वीट का स्क्रीनशॉट जिसमें मैंने अपने पीआर का एलान किया है.

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

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

आज की स्थिति के लिए Excalidraw PWA का स्क्रीनशॉट.

लिपिस ने बताया कि वह Excalidraw पर इतना समय क्यों देते हैं

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

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

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

एक्सकैलिड्रॉ काम कर रहा है

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

मैं 'सेव करें' आइकॉन पर क्लिक करता/करती हूं. इसके बाद, फ़ाइल सेव करने के डायलॉग बॉक्स में फ़ाइल का नाम डालता/डालती हूं. Chrome, File System Access API के साथ काम करने वाला ब्राउज़र है. इसमें, फ़ाइल को डाउनलोड करने के बजाय, उसे सेव किया जाता है. इसकी मदद से, फ़ाइल की जगह और नाम चुना जा सकता है. साथ ही, फ़ाइल में बदलाव करने पर, उन्हें उसी फ़ाइल में सेव किया जा सकता है.

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

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

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

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

इसका राज़ क्या है? ऐसे अलग-अलग ब्राउज़र जो फ़ाइल सिस्टम ऐक्सेस एपीआई के साथ काम करते हैं या नहीं करते, उनके लिए काम कैसे खोला और सेव किया जा सकता है? 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() फ़ंक्शन, मेरी लिखी गई एक छोटी लाइब्रेरी से आता है. इस लाइब्रेरी को browser-fs-access कहा जाता है. इसका इस्तेमाल हम Excalidraw में करते हैं. यह लाइब्रेरी, File System Access API के ज़रिए फ़ाइल सिस्टम का ऐक्सेस देती है. साथ ही, इसमें लेगसी फ़ॉलबैक भी शामिल है, ताकि इसका इस्तेमाल किसी भी ब्राउज़र में किया जा सके.

सबसे पहले हम आपको लागू करने का तरीका बताएंगे, ताकि यह बताया जा सके कि एपीआई काम करता है या नहीं. स्वीकार किए गए MIME टाइप और फ़ाइल एक्सटेंशन के बारे में बातचीत करने के बाद, मुख्य हिस्सा, फ़ाइल सिस्टम ऐक्सेस एपीआई के फ़ंक्शन 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() नाम के फ़ंक्शन को कॉल करता है. यह फ़ंक्शन, browser-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();
};

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

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

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

ऐसा तब किया जा सकता है, जब File System Access API काम करता हो, तो डेटा ट्रांसफ़र आइटम पर getAsFileSystemHandle() को कॉल करें. इसके बाद, मैं इस फ़ाइल हैंडल को 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 पर वेब शेयर टारगेट एपीआई की मदद से दूसरा सिस्टम इंटिग्रेशन भी किया जा सकता है. यहां मैं Files ऐप्लिकेशन में अपने Downloads फ़ोल्डर में हूं. मुझे दो फ़ाइलें दिख रही हैं. इनमें से एक का नाम untitled है और उसमें कोई जानकारी नहीं है. साथ ही, उसमें टाइमस्टैंप भी है. यह देखने के लिए कि इसमें क्या है, तीन बिंदुओं पर क्लिक करें, फिर शेयर करें, और दिखने वाला एक विकल्प Excalidraw है. आइकॉन पर टैप करने पर, मुझे पता चलता है कि फ़ाइल में सिर्फ़ I/O लोगो है.

अब इस्तेमाल में नहीं किए जा रहे Electron वर्शन पर Lipis

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

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

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

यह कहा जा सकता है कि Electronicn के लिए 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 ऐप्लिकेशन का वेब वर्शन है.

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

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 का प्रतीक है.

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

WICG Idle Detection repo पर दर्ज किए गए, कुछ समय से इस्तेमाल में नहीं है की स्थिति का पता लगाने वाले टूल के बारे में सुझाव, शिकायत या राय का स्क्रीनशॉट.

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

एक्सकालिड्रा को वापस पकड़े हुए पर लिपिस

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

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

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

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

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

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

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

आखिरी हिस्सा

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

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