Excalidraw এবং Fugu: মূল ব্যবহারকারীর যাত্রার উন্নতি

যে কোনো পর্যাপ্ত উন্নত প্রযুক্তি যাদু থেকে আলাদা করা যায় না। না বুঝলে। আমার নাম থমাস স্টেইনার, আমি Google-এ ডেভেলপার রিলেশনে কাজ করি এবং আমার Google I/O টক-এর এই লেখায়, আমি কিছু নতুন Fugu API-এর দিকে নজর দেব এবং কীভাবে তারা Excalidraw PWA-তে মূল ব্যবহারকারীর যাত্রাকে উন্নত করে, তাই আপনি এই ধারণাগুলি থেকে অনুপ্রেরণা নিতে পারেন এবং আপনার নিজের অ্যাপগুলিতে প্রয়োগ করতে পারেন৷

টমাস স্টেইনার
টমাস স্টেইনার

কিভাবে আমি Excalidraw এ এসেছি

আমি একটি গল্প দিয়ে শুরু করতে চাই। 1লা জানুয়ারী, 2020-এ, Facebook-এর একজন সফ্টওয়্যার প্রকৌশলী ক্রিস্টোফার চেডিউ একটি ছোট অঙ্কন অ্যাপ সম্পর্কে টুইট করেছিলেন যেটিতে তিনি কাজ শুরু করেছিলেন। এই টুলের সাহায্যে, আপনি বাক্স এবং তীরগুলি আঁকতে পারেন যা কার্টুনি এবং হাতে আঁকা মনে হয়। পরের দিন, আপনি উপবৃত্তাকার এবং পাঠ্য আঁকতে পারেন, সেইসাথে বস্তু নির্বাচন করুন এবং তাদের চারপাশে সরাতে পারেন। 3 জানুয়ারী, অ্যাপটি তার নাম পেয়েছে, Excalidraw, এবং প্রতিটি ভাল পার্শ্ব প্রকল্পের মত, ডোমেইন নাম কেনা ছিল ক্রিস্টোফারের প্রথম কাজগুলির মধ্যে একটি। এখন পর্যন্ত, আপনি রং ব্যবহার করতে পারেন এবং একটি PNG হিসাবে পুরো অঙ্কনটি রপ্তানি করতে পারেন।

Excalidraw প্রোটোটাইপ অ্যাপ্লিকেশনের স্ক্রিনশট দেখায় যে এটি আয়তক্ষেত্র, তীর, উপবৃত্ত এবং পাঠ্যকে সমর্থন করে।

15 জানুয়ারী, ক্রিস্টোফার একটি ব্লগ পোস্ট করেছেন যা আমার সহ টুইটারে অনেক মনোযোগ আকর্ষণ করেছিল। পোস্টটি কিছু চিত্তাকর্ষক পরিসংখ্যান দিয়ে শুরু হয়েছিল:

  • 12K অনন্য সক্রিয় ব্যবহারকারী
  • GitHub-এ 1.5K তারা
  • 26 জন অবদানকারী

একটি প্রকল্পের জন্য যা মাত্র দুই সপ্তাহ আগে শুরু হয়েছিল, এটি মোটেও খারাপ নয়। কিন্তু যে জিনিসটি সত্যিকার অর্থে আমার আগ্রহ বাড়িয়ে দিয়েছে তা পোস্টে আরও নিচে ছিল। ক্রিস্টোফার লিখেছেন যে তিনি এবার নতুন কিছু করার চেষ্টা করেছেন: যারা একটি পুল অনুরোধ অবতীর্ণ করেছেন তাদের প্রত্যেককে নিঃশর্ত কমিট অ্যাক্সেস দেওয়া। ব্লগ পোস্ট পড়ার একই দিনে, আমার কাছে একটি পুল অনুরোধ ছিল যা Excalidraw-তে ফাইল সিস্টেম অ্যাক্সেস API সমর্থন যোগ করেছে, একটি ফিচার রিকোয়েস্ট ফিক্স করে যা কেউ ফাইল করেছিল।

টুইটের স্ক্রিনশট যেখানে আমি আমার পিআর ঘোষণা করছি।

আমার পুল অনুরোধ একদিন পরে একত্রিত করা হয়েছিল এবং সেখান থেকে, আমার সম্পূর্ণ কমিট অ্যাক্সেস ছিল। বলা বাহুল্য, আমি আমার ক্ষমতার অপব্যবহার করিনি। এবং এখনও পর্যন্ত 149 জন অবদানকারীদের থেকে অন্য কেউ আসেনি।

আজ, Excalidraw হল অফলাইন সাপোর্ট সহ একটি পূর্ণাঙ্গ ইনস্টলযোগ্য প্রগতিশীল ওয়েব অ্যাপ, একটি অত্যাশ্চর্য ডার্ক মোড এবং হ্যাঁ, ফাইল সিস্টেম অ্যাক্সেস API-কে ধন্যবাদ ফাইল খোলা ও সংরক্ষণ করার ক্ষমতা।

আজকের রাজ্যে Excalidraw PWA-এর স্ক্রিনশট।

লিপিস কেন তিনি তার এত বেশি সময় Excalidraw-এ উৎসর্গ করেন

সুতরাং এটি আমার "কীভাবে আমি এক্সক্যালিড্রে এলাম" গল্পের সমাপ্তি চিহ্নিত করে, কিন্তু এক্সক্যালিড্রের কিছু আশ্চর্যজনক বৈশিষ্ট্যের মধ্যে ডুব দেওয়ার আগে, আমি Panayiotis-এর সাথে পরিচয় করিয়ে দিতে পেরে আনন্দিত। প্যানাইওটিস লিপিরিডিস, ইন্টারনেটে যা লিপিস নামে পরিচিত, এটি এক্সক্যালিড্রের সবচেয়ে বেশি অবদানকারী। আমি লিপিসকে জিজ্ঞাসা করেছি যে তাকে তার এত বেশি সময় Excalidraw-এ উৎসর্গ করতে অনুপ্রাণিত করে:

অন্য সবার মতো আমি ক্রিস্টোফারের টুইট থেকে এই প্রকল্প সম্পর্কে শিখেছি। আমার প্রথম অবদান ছিল ওপেন কালার লাইব্রেরি যোগ করা, যে রঙগুলি আজও এক্সক্যালিড্রের অংশ। যেহেতু প্রকল্পটি বেড়েছে এবং আমাদের অনেক অনুরোধ ছিল, আমার পরবর্তী বড় অবদান ছিল অঙ্কন সংরক্ষণের জন্য একটি ব্যাকএন্ড তৈরি করা যাতে ব্যবহারকারীরা সেগুলি ভাগ করতে পারে। কিন্তু যা আমাকে অবদান রাখতে চালিত করে তা হল যে কেউ Excalidraw চেষ্টা করেছে তা আবার ব্যবহার করার জন্য অজুহাত খুঁজছে।

আমি লিপিসের সাথে সম্পূর্ণ একমত। যে কেউ Excalidraw চেষ্টা করেছে তা আবার ব্যবহার করার জন্য অজুহাত খুঁজছে।

কর্মে Excalidraw

আমি আপনাকে এখন দেখাতে চাই কিভাবে আপনি অনুশীলনে Excalidraw ব্যবহার করতে পারেন। আমি একজন মহান শিল্পী নই, কিন্তু Google I/O লোগো যথেষ্ট সহজ, তাই আমাকে এটি চেষ্টা করতে দিন। একটি বাক্স হল "i", একটি লাইন স্ল্যাশ হতে পারে এবং "o" একটি বৃত্ত। আমি শিফট ধরে রাখি, তাই আমি একটি নিখুঁত বৃত্ত পাই। আমাকে স্ল্যাশটি একটু সরাতে দিন, যাতে এটি আরও ভাল দেখায়। এখন "i" এবং "o" এর জন্য কিছু রঙ। নীল ভালো। হয়তো একটি ভিন্ন ভরাট শৈলী? সব কঠিন, নাকি ক্রস হ্যাচ? নাহ, হাচুরে দারুন লাগছে। এটি নিখুঁত নয়, তবে এটি এক্সক্যালিড্রের ধারণা, তাই আমাকে এটি সংরক্ষণ করতে দিন।

আমি সংরক্ষণ আইকনে ক্লিক করি এবং ফাইল সংরক্ষণ ডায়ালগে একটি ফাইলের নাম লিখি। ক্রোমে, একটি ব্রাউজার যা ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করে, এটি একটি ডাউনলোড নয়, কিন্তু একটি সত্য সংরক্ষণ অপারেশন, যেখানে আমি ফাইলের অবস্থান এবং নাম চয়ন করতে পারি এবং যেখানে, যদি আমি সম্পাদনা করি, আমি সেগুলি সংরক্ষণ করতে পারি একই ফাইলে।

আমাকে লোগো পরিবর্তন এবং "i" লাল করা যাক. যদি আমি এখন আবার সংরক্ষণ ক্লিক করি, আমার পরিবর্তন আগের মতই একই ফাইলে সংরক্ষিত হবে। একটি প্রমাণ হিসাবে, আমাকে ক্যানভাস পরিষ্কার করুন এবং ফাইলটি পুনরায় খুলুন। আপনি দেখতে পাচ্ছেন, পরিবর্তিত লাল-নীল লোগোটি আবার রয়েছে।

ফাইল নিয়ে কাজ করা

বর্তমানে ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করে না এমন ব্রাউজারগুলিতে, প্রতিটি সংরক্ষণ অপারেশন একটি ডাউনলোড, তাই যখন আমি পরিবর্তন করি, তখন আমার ডাউনলোড ফোল্ডারটি পূরণ করার ফাইলের নামটিতে একটি ক্রমবর্ধমান সংখ্যা সহ একাধিক ফাইলের সাথে শেষ হয়। কিন্তু এই খারাপ দিক থাকা সত্ত্বেও, আমি এখনও ফাইলটি সংরক্ষণ করতে পারি।

ফাইল খোলা হচ্ছে

তাহলে রহস্য কি? ফাইল সিস্টেম অ্যাক্সেস 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() ফাংশন যা একটি ছোট লাইব্রেরি থেকে আসে যা আমি লিখেছিলাম ব্রাউজার-এফএস-অ্যাক্সেস যা আমরা এক্সক্যালিড্রতে ব্যবহার করি। এই লাইব্রেরিটি একটি লিগ্যাসি ফলব্যাক সহ ফাইল সিস্টেম অ্যাক্সেস API এর মাধ্যমে ফাইল সিস্টেম অ্যাক্সেস প্রদান করে, তাই এটি যে কোনও ব্রাউজারে ব্যবহার করা যেতে পারে।

এপিআই সমর্থিত হলে আমি প্রথমে আপনাকে বাস্তবায়ন দেখাই। গৃহীত MIME প্রকার এবং ফাইল এক্সটেনশন নিয়ে আলোচনা করার পরে, কেন্দ্রীয় অংশটি ফাইল সিস্টেম অ্যাক্সেস 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-অ্যাক্সেস লাইব্রেরি দ্বারা সরবরাহ করা হয়।

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 };
};

আবার আমাকে প্রথমে ফাইল সিস্টেম অ্যাক্সেস 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;
};

"সেভ এজ" বৈশিষ্ট্য

যদি আমি ইতিমধ্যে বিদ্যমান ফাইল হ্যান্ডেলকে উপেক্ষা করার সিদ্ধান্ত নিই, তাহলে বিদ্যমান ফাইলের উপর ভিত্তি করে একটি নতুন ফাইল তৈরি করতে আমি একটি "সেভ অ্যাজ" বৈশিষ্ট্য প্রয়োগ করতে পারি। এটি দেখানোর জন্য, আমাকে একটি বিদ্যমান ফাইল খুলতে দিন, কিছু পরিবর্তন করতে দিন, এবং তারপরে বিদ্যমান ফাইলটি ওভাররাইট করবেন না, তবে সেভ-এজ বৈশিষ্ট্যটি ব্যবহার করে একটি নতুন ফাইল তৈরি করুন। এটি মূল ফাইলটি অক্ষত রাখে।

ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করে না এমন ব্রাউজারগুলির বাস্তবায়ন সংক্ষিপ্ত, যেহেতু এটি শুধুমাত্র একটি download অ্যাট্রিবিউট সহ একটি অ্যাঙ্কর উপাদান তৈরি করে যার মানটি কাঙ্খিত ফাইলের নাম এবং একটি ব্লব URL এর 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 ফাইল ড্রপ করি, তখনই এটি খুলে যায় এবং আমি সম্পাদনা শুরু করতে পারি। ফাইল সিস্টেম অ্যাক্সেস API সমর্থন করে এমন ব্রাউজারগুলিতে, আমি আমার পরিবর্তনগুলি অবিলম্বে সংরক্ষণ করতে পারি। ড্র্যাগ অ্যান্ড ড্রপ অপারেশন থেকে প্রয়োজনীয় ফাইল হ্যান্ডেল পাওয়া গেছে বলে একটি ফাইল সংরক্ষণ ডায়ালগের মাধ্যমে যাওয়ার দরকার নেই।

ফাইল সিস্টেম অ্যাক্সেস 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-এ আরেকটি সিস্টেম ইন্টিগ্রেশন হল ওয়েব শেয়ার টার্গেট API এর মাধ্যমে। এখানে আমি আমার Downloads ফোল্ডারে ফাইল অ্যাপে আছি। আমি দুটি ফাইল দেখতে পাচ্ছি, তাদের মধ্যে একটির নাম untitled এবং একটি টাইমস্ট্যাম্প সহ। এটিতে কী আছে তা পরীক্ষা করতে, আমি তিনটি বিন্দুতে ক্লিক করি, তারপর শেয়ার করি এবং যে বিকল্পগুলি উপস্থিত হয় তার মধ্যে একটি হল Excalidraw। যখন আমি আইকনে আলতো চাপি, তখন আমি দেখতে পাব যে ফাইলটিতে আবার I/O লোগো রয়েছে।

অবলুপ্ত ইলেক্ট্রন সংস্করণে লিপিস

আমি এখনও যে ফাইলগুলির বিষয়ে কথা বলিনি সেগুলির সাথে আপনি একটি জিনিস করতে পারেন তা হল সেগুলিতে ডাবল ক্লিক করুন৷ আপনি যখন একটি ফাইলে ডাবল ক্লিক করেন তখন সাধারণত যা ঘটে তা হল ফাইলের MIME প্রকারের সাথে যুক্ত অ্যাপটি খোলে৷ উদাহরণস্বরূপ .docx এর জন্য এটি Microsoft Word হবে।

Excalidraw অ্যাপের একটি ইলেক্ট্রন সংস্করণ ব্যবহার করত যা এই ধরনের ফাইল টাইপ অ্যাসোসিয়েশনগুলিকে সমর্থন করে, তাই আপনি যখন একটি .excalidraw ফাইলে ডাবল-ক্লিক করেন, তখন Excalidraw Electron অ্যাপটি খুলবে। লিপিস, যার সাথে আপনি ইতিমধ্যেই দেখা করেছেন, তিনি ছিলেন Excalidraw Electron এর স্রষ্টা এবং অবমাননাকারী। আমি তাকে জিজ্ঞাসা করলাম কেন তিনি মনে করেন ইলেক্ট্রন সংস্করণকে অবমূল্যায়ন করা সম্ভব:

লোকেরা শুরু থেকেই একটি ইলেক্ট্রন অ্যাপের জন্য জিজ্ঞাসা করছে, মূলত কারণ তারা ডাবল-ক্লিক করে ফাইল খুলতে চায়। আমরা অ্যাপ স্টোরগুলিতে অ্যাপটি রাখারও উদ্দেশ্য করেছি। সমান্তরালভাবে, কেউ পরিবর্তে একটি PWA তৈরি করার পরামর্শ দিয়েছে, তাই আমরা উভয়ই করেছি। সৌভাগ্যবশত আমরা ফাইল সিস্টেম অ্যাক্সেস, ক্লিপবোর্ড অ্যাক্সেস, ফাইল হ্যান্ডলিং এবং আরও অনেক কিছুর মতো প্রজেক্ট ফুগু API-এর সাথে পরিচিত হয়েছিলাম। শুধুমাত্র একটি ক্লিকেই আপনি আপনার ডেস্কটপ বা মোবাইলে ইলেকট্রনের অতিরিক্ত ওজন ছাড়াই অ্যাপটি ইনস্টল করতে পারবেন। এটি একটি সহজ সিদ্ধান্ত ছিল ইলেক্ট্রন সংস্করণকে অবমূল্যায়ন করা, শুধুমাত্র ওয়েব অ্যাপে মনোনিবেশ করা এবং এটিকে সেরা-সম্ভব PWA করে তোলা। উপরে, আমরা এখন প্লে স্টোর এবং মাইক্রোসফ্ট স্টোরে PWA প্রকাশ করতে সক্ষম! যে বিশাল!

কেউ বলতে পারে ইলেক্ট্রনের জন্য এক্সক্যালিড্রকে অবমূল্যায়ন করা হয়নি কারণ ইলেক্ট্রন খারাপ, মোটেই নয়, কিন্তু ওয়েব যথেষ্ট ভালো হয়ে গেছে। আমি এটা পছন্দ করি!

ফাইল হ্যান্ডলিং

আমি যখন বলি "ওয়েব যথেষ্ট ভালো হয়ে গেছে", এটা আসন্ন ফাইল হ্যান্ডলিং এর মত বৈশিষ্ট্যের কারণে।

এটি একটি নিয়মিত macOS Big Sur ইনস্টলেশন। এখন আমি একটি Excalidraw ফাইলে রাইট ক্লিক করলে কি হয় তা পরীক্ষা করে দেখুন। আমি ইনস্টল করা PWA, Excalidraw দিয়ে এটি খুলতে পারি। অবশ্যই ডাবল-ক্লিক করাও কাজ করবে, এটি একটি স্ক্রিনকাস্টে প্রদর্শন করা কম নাটকীয়।

তাহলে এটা কিভাবে কাজ করে? প্রথম ধাপ হল অপারেটিং সিস্টেমের কাছে আমার অ্যাপ্লিকেশান যে ধরনের ফাইলগুলি পরিচালনা করতে পারে তা জানাতে হবে৷ আমি ওয়েব অ্যাপ ম্যানিফেস্টে file_handlers নামে একটি নতুন ক্ষেত্রে এটি করি। এর মান হল একটি অ্যাকশন এবং accept প্রপার্টি সহ অবজেক্টের একটি অ্যারে। ক্রিয়াটি অপারেটিং সিস্টেম আপনার অ্যাপটি লঞ্চ করার URL পাথ নির্ধারণ করে এবং গ্রহণ করা বস্তু হল 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 });
      });
    });
}

আবার, যদি এটি খুব দ্রুত চলে যায়, আপনি আমার নিবন্ধে ফাইল হ্যান্ডলিং API সম্পর্কে আরও পড়তে পারেন। আপনি পরীক্ষামূলক ওয়েব প্ল্যাটফর্ম বৈশিষ্ট্য পতাকা সেট করে ফাইল পরিচালনা সক্ষম করতে পারেন। এটি এই বছরের শেষের দিকে ক্রোমে অবতরণ করার জন্য নির্ধারিত হয়েছে৷

ক্লিপবোর্ড ইন্টিগ্রেশন

Excalidraw এর আরেকটি দুর্দান্ত বৈশিষ্ট্য হল ক্লিপবোর্ড ইন্টিগ্রেশন। আমি আমার সম্পূর্ণ অঙ্কন বা এটির কিছু অংশ ক্লিপবোর্ডে অনুলিপি করতে পারি, আমার মনে হলে একটি ওয়াটারমার্ক যোগ করতে পারি এবং তারপরে এটি অন্য অ্যাপে পেস্ট করতে পারি। এটি উইন্ডোজ 95 পেইন্ট অ্যাপের একটি ওয়েব সংস্করণ।

এই কাজ করার উপায় আশ্চর্যজনকভাবে সহজ। আমার যা দরকার তা হল একটি ব্লব হিসাবে ক্যানভাস, যা আমি ক্লিপবোর্ডে একটি এক-উপাদান অ্যারেকে ব্লব সহ একটি ClipboardItem আইটেম দিয়ে navigator.clipboard.write() ফাংশনে পাস করে লিখি। ক্লিপবোর্ড 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);
    }
  });
};

অন্যদের সাথে সহযোগিতা করা

একটি সেশন URL শেয়ার করা হচ্ছে

আপনি কি জানেন যে Excalidraw এর একটি সহযোগী মোড আছে? একই নথিতে বিভিন্ন ব্যক্তি একসাথে কাজ করতে পারে। একটি নতুন সেশন শুরু করতে, আমি লাইভ সহযোগিতা বোতামে ক্লিক করি এবং তারপর একটি সেশন শুরু করি। Excalidraw একত্রিত করা ওয়েব শেয়ার API- এর জন্য আমি সহজে আমার সহযোগীদের সাথে সেশন URL শেয়ার করতে পারি।

লাইভ সহযোগিতা

আমি আমার Pixelbook, আমার Pixel 3a ফোন, এবং আমার iPad Pro-এ Google I/O লোগোতে কাজ করে স্থানীয়ভাবে একটি সহযোগিতা সেশন সিমুলেট করেছি। আপনি দেখতে পাচ্ছেন যে আমি একটি ডিভাইসে যে পরিবর্তনগুলি করি তা অন্য সমস্ত ডিভাইসে প্রতিফলিত হয়৷

আমি এমনকি সব কার্সার ঘুরে দেখতে পাচ্ছি। Pixelbook এর কার্সারটি স্থিরভাবে চলে, যেহেতু এটি একটি ট্র্যাকপ্যাড দ্বারা নিয়ন্ত্রিত, কিন্তু Pixel 3a ফোনের কার্সার এবং iPad Pro এর ট্যাবলেট কার্সারটি ঘুরে বেড়ায়, যেহেতু আমি আমার আঙুল দিয়ে ট্যাপ করে এই ডিভাইসগুলি নিয়ন্ত্রণ করি৷

সহযোগী স্ট্যাটাস দেখা হচ্ছে

রিয়েলটাইম সহযোগিতার অভিজ্ঞতা উন্নত করতে, এমনকি একটি নিষ্ক্রিয় সনাক্তকরণ সিস্টেম চালু আছে। আমি যখন এটি ব্যবহার করি তখন আইপ্যাড প্রো-এর কার্সারটি একটি সবুজ বিন্দু দেখায়। যখন আমি একটি ভিন্ন ব্রাউজার ট্যাব বা অ্যাপে স্যুইচ করি তখন বিন্দুটি কালো হয়ে যায়। এবং যখন আমি Excalidraw অ্যাপে থাকি, কিন্তু কিছুই করছি না, তখন কার্সারটি আমাকে নিষ্ক্রিয় হিসাবে দেখায়, তিনটি zZZ দ্বারা প্রতীকী।

আমাদের প্রকাশনার উত্সাহী পাঠকরা ভাবতে পারেন যে নিষ্ক্রিয় সনাক্তকরণটি Idle Detection API এর মাধ্যমে উপলব্ধি করা হয়েছে, এটি একটি প্রাথমিক পর্যায়ের প্রস্তাব যা প্রজেক্ট ফুগুর প্রসঙ্গে কাজ করা হয়েছে। স্পয়লার সতর্কতা: এটা না. যদিও আমরা এক্সক্যালিড্রতে এই API-এর উপর ভিত্তি করে একটি বাস্তবায়ন করেছি, শেষ পর্যন্ত, আমরা পয়েন্টার মুভমেন্ট এবং পৃষ্ঠার দৃশ্যমানতা পরিমাপের উপর ভিত্তি করে আরও ঐতিহ্যগত পদ্ধতিতে যাওয়ার সিদ্ধান্ত নিয়েছি।

WICG নিষ্ক্রিয় সনাক্তকরণ রেপোতে ফাইল করা নিষ্ক্রিয় সনাক্তকরণ প্রতিক্রিয়ার স্ক্রিনশট।

কেন নিষ্ক্রিয় সনাক্তকরণ API আমাদের ব্যবহারের ক্ষেত্রে সমাধান করছে না সে বিষয়ে আমরা প্রতিক্রিয়া দাখিল করেছি। সমস্ত প্রজেক্ট ফুগু এপিআই খোলা জায়গায় তৈরি করা হচ্ছে, যাতে প্রত্যেকে তাদের কণ্ঠস্বর শুনতে পারে!

Excalidraw আটকে আছে কি উপর Lipis

যার কথা বলতে গিয়ে, আমি লিপিসকে এক্সক্যালিড্রকে আটকে রাখা ওয়েব প্ল্যাটফর্ম থেকে কী অনুপস্থিত বলে মনে করেন সে সম্পর্কে একটি শেষ প্রশ্ন জিজ্ঞাসা করেছি:

ফাইল সিস্টেম অ্যাক্সেস API দুর্দান্ত, কিন্তু আপনি কি জানেন? আজকাল আমার যত্ন নেওয়া বেশিরভাগ ফাইল আমার ড্রপবক্স বা গুগল ড্রাইভে থাকে, আমার হার্ড ডিস্কে নয়। আমি আশা করি ফাইল সিস্টেম অ্যাক্সেস এপিআই ড্রপবক্স বা গুগলের মতো দূরবর্তী ফাইল সিস্টেম সরবরাহকারীদের জন্য একটি বিমূর্ত স্তর অন্তর্ভুক্ত করবে যাতে বিকাশকারীরা এর বিরুদ্ধে কোড করতে পারে। ব্যবহারকারীরা তখন শিথিল হতে পারে এবং জানতে পারে যে তাদের ফাইলগুলি তারা বিশ্বাস করে এমন ক্লাউড সরবরাহকারীর কাছে নিরাপদ।

আমি লিপিসের সাথে সম্পূর্ণ একমত, আমিও মেঘে থাকি। এখানে আশা করা যায় যে এটি দ্রুত বাস্তবায়ন করা হবে।

ট্যাবযুক্ত অ্যাপ্লিকেশন মোড

কি দারুন! আমরা Excalidraw-এ অনেক সত্যিই দুর্দান্ত API ইন্টিগ্রেশন দেখেছি। ফাইল সিস্টেম , ফাইল হ্যান্ডলিং , ক্লিপবোর্ড , ওয়েব শেয়ার , এবং ওয়েব শেয়ার টার্গেট । তবে এখানে আরও একটি বিষয়। এখন পর্যন্ত, আমি একটি নির্দিষ্ট সময়ে শুধুমাত্র একটি নথি সম্পাদনা করতে পারি। আর না. Excalidraw-এ ট্যাবড অ্যাপ্লিকেশন মোডের একটি প্রাথমিক সংস্করণ প্রথমবারের জন্য উপভোগ করুন। এই এটা দেখায় কিভাবে হয়।

আমার কাছে ইনস্টল করা Excalidraw PWA-তে একটি বিদ্যমান ফাইল খোলা আছে যা স্বতন্ত্র মোডে চলছে। এখন আমি স্বতন্ত্র উইন্ডোতে একটি নতুন ট্যাব খুলছি। এটি একটি নিয়মিত ব্রাউজার ট্যাব নয়, কিন্তু একটি PWA ট্যাব। এই নতুন ট্যাবে আমি একটি মাধ্যমিক ফাইল খুলতে পারি এবং একই অ্যাপ উইন্ডো থেকে স্বাধীনভাবে সেগুলিতে কাজ করতে পারি।

ট্যাবড অ্যাপ্লিকেশন মোড তার প্রাথমিক পর্যায়ে রয়েছে এবং সবকিছু পাথরে সেট করা হয় না। আপনি যদি আগ্রহী হন তবে আমার নিবন্ধে এই বৈশিষ্ট্যটির বর্তমান অবস্থা পড়তে ভুলবেন না।

বন্ধ

এই এবং অন্যান্য বৈশিষ্ট্য সম্পর্কে লুপ থাকার জন্য, আমাদের Fugu API ট্র্যাকার দেখতে ভুলবেন না। আমরা ওয়েবকে এগিয়ে নিয়ে যেতে এবং আপনাকে প্ল্যাটফর্মে আরও কিছু করার অনুমতি দিতে খুব উত্তেজিত। এখানে একটি সর্বদা উন্নত হওয়া Excalidraw-এর কথা, এবং এখানে আপনি তৈরি করবেন এমন সব আশ্চর্যজনক অ্যাপ্লিকেশন রয়েছে। excalidraw.com এ তৈরি করা শুরু করুন।

আমি আজ আপনার অ্যাপে পপ আপ দেখানো কিছু API দেখতে অপেক্ষা করতে পারি না। আমার নাম টম, আপনি আমাকে টুইটারে এবং ইন্টারনেটে @tomayac হিসাবে খুঁজে পেতে পারেন। দেখার জন্য আপনাকে অনেক ধন্যবাদ, এবং বাকি Google I/O উপভোগ করুন৷