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

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

मैं Excalidraw का इस्तेमाल कैसे करने लगा

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

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

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

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

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

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

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

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

Excalidraw PWA की मौजूदा स्थिति का स्क्रीनशॉट.

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

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

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

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

फिर से, मुझे पहले उन ब्राउज़र के लिए लागू करने का तरीका देखना है जिनमें File System Access API काम करता है. पहली दो लाइनें थोड़ी मुश्किल लगती हैं, लेकिन इनमें सिर्फ़ 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;
};

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

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

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

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 के साथ काम करने वाले ब्राउज़र पर, मैं अपने बदलाव तुरंत सेव कर सकता/सकती हूं. फ़ाइल सेव करने के लिए डायलॉग बॉक्स में जाने की ज़रूरत नहीं है, क्योंकि खींचकर छोड़ने की कार्रवाई से ज़रूरी फ़ाइल हैंडल मिल गया है.

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

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

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

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

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

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

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

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

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

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 ऐप्लिकेशन में हूं, लेकिन कुछ नहीं कर रहा हूं, तो कर्सर मुझे 'कुछ नहीं किया जा रहा है' के तौर पर दिखाता है. इसके लिए, तीन zZZ का इस्तेमाल किया जाता है.

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

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

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

Excalidraw को बेहतर बनाने के बारे में Lipis की बात

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

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

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

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

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

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

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

आखिरी हिस्सा

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

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