Exalidraw và Fugu: Cải thiện hành trình cốt lõi của người dùng

Bất kỳ công nghệ tiên tiến nào cũng không thể phân biệt được với phép thuật. Trừ phi bạn hiểu được. Tôi là Thomas Steiner, làm việc trong Nhóm quan hệ đối tác nhà phát triển tại Google. Trong bài viết này về bài nói chuyện của tôi tại Google I/O, tôi sẽ xem xét một số API Fugu mới và cách các API này cải thiện hành trình cốt lõi của người dùng trong PWA Excalidraw. Nhờ đó, bạn có thể lấy cảm hứng từ những ý tưởng này và áp dụng cho ứng dụng của riêng mình.

Làm thế nào tôi đến với Excalidraw

Tôi muốn bắt đầu bằng một câu chuyện. Vào ngày 1 tháng 1 năm 2020, Christopher Chedeau, một kỹ sư phần mềm tại Facebook, đã twitte về một ứng dụng vẽ nhỏ mà anh bắt đầu làm việc. Với công cụ này, bạn có thể vẽ các hộp và mũi tên mang phong cách hoạt hình và vẽ tay. Vào ngày tiếp theo, bạn cũng có thể vẽ hình elip và văn bản, cũng như chọn các đối tượng và di chuyển chúng. Vào ngày 3 tháng 1, ứng dụng đã có tên là Excalidraw và giống như mọi dự án phụ hay, việc mua tên miền là một trong những hành động đầu tiên của Christopher. Hiện tại, bạn có thể sử dụng màu và xuất toàn bộ bản vẽ dưới dạng PNG.

Ảnh chụp màn hình ứng dụng nguyên mẫu Excalidraw cho thấy ứng dụng này hỗ trợ hình chữ nhật, mũi tên, hình elip và văn bản.

Vào ngày 15 tháng 1, Christopher đăng một bài đăng trên blog thu hút được nhiều sự chú ý trên Twitter, trong đó có bài đăng của tôi. Bài đăng này mở đầu với một vài số liệu thống kê ấn tượng:

  • 12 nghìn người dùng riêng biệt đang hoạt động
  • 1.5K lượt thích trên GitHub
  • 26 cộng tác viên

Đối với một dự án chỉ bắt đầu cách đây 2 tuần thì như vậy không hề tệ. Nhưng điều thực sự làm tôi hứng thú là ở phần dưới của bài đăng. Christopher viết rằng lần này anh đã thử một cách mới: cho phép tất cả những người đưa ra yêu cầu lấy dữ liệu quyền truy cập cam kết vô điều kiện. Cùng ngày đọc bài đăng trên blog, tôi đã nhận được một yêu cầu kéo về việc thêm tính năng hỗ trợ API Truy cập hệ thống tệp vào Excalidraw, khắc phục một yêu cầu về tính năng mà người dùng đã gửi.

Ảnh chụp màn hình của tweet mà tôi thông báo về mối quan hệ công chúng.

Yêu cầu lấy dữ liệu của tôi được hợp nhất một ngày sau đó và từ đó, tôi có toàn quyền truy cập cam kết. Không cần phải nói, tôi không lạm dụng quyền của mình. Và cũng không có bất kỳ ai khác trong số 149 người đóng góp cho đến nay.

Hiện tại, Excalidraw là một ứng dụng web tiến bộ có thể cài đặt đầy đủ, hỗ trợ ngoại tuyến, chế độ tối tuyệt đẹp và có thể mở và lưu tệp nhờ API Truy cập hệ thống tệp.

Ảnh chụp màn hình PWA Excalidraw ở trạng thái hiện tại.

Lipis chia sẻ lý do anh dành nhiều thời gian cho Excalidraw

Vậy là tôi đã kết thúc câu chuyện "Làm thế nào tôi đến với Excalidraw". Tuy nhiên, trước khi đi sâu vào một số tính năng tuyệt vời của Excalidraw, tôi rất vui được giới thiệu Panayiotis. Panayiotis Lipiridis, trên Internet chỉ được gọi là lipis, là người đóng góp nhiều nhất cho Excalidraw. Tôi đã hỏi lipis về động lực khiến anh dành nhiều thời gian cho Excalidraw:

Giống như mọi người, tôi biết về dự án này qua tweet của Christopher. Đóng góp đầu tiên của tôi là thêm thư viện Open Color (Thư viện màu mở), những màu vẫn còn là một phần của Excalidraw hiện nay. Khi dự án phát triển và chúng tôi có khá nhiều yêu cầu, nên đóng góp lớn tiếp theo của tôi là xây dựng một phần phụ trợ để lưu trữ bản vẽ để người dùng có thể chia sẻ bản vẽ. Nhưng điều thực sự thôi thúc tôi đóng góp là bất cứ ai dùng thử Excalidraw đều muốn tìm lý do để sử dụng lại Excalidraw.

Tôi hoàn toàn đồng ý với lipis. Bất cứ ai đã dùng Excalidraw đều muốn tìm lý do để sử dụng lại ứng dụng này.

Khai thác trong thực tế

Bây giờ, tôi muốn hướng dẫn bạn cách sử dụng Excalidraw trong thực tế. Tôi không phải là một nghệ sĩ giỏi, nhưng biểu trưng Google I/O khá đơn giản, vì vậy, hãy để tôi thử. Hộp là "i", đường kẻ có thể là dấu gạch chéo và "o" là một vòng tròn. Tôi giữ phím shift để có được một vòng tròn hoàn hảo. Hãy để tôi di chuyển dấu gạch chéo một chút để trông đẹp hơn. Bây giờ, hãy thêm màu cho "i" và "o". Màu xanh dương là tốt. Có thể là kiểu tô màu khác? Tất cả đều chắc chắn hay cửa sổ ngang? Không, nét vẽ rất đẹp. Đó không phải là hoàn hảo, nhưng đó là ý tưởng về Excalidraw, vì vậy hãy để tôi lưu lại nó.

Tôi nhấp vào biểu tượng lưu và nhập tên tệp vào hộp thoại lưu tệp. Trong Chrome, một trình duyệt hỗ trợ API Truy cập hệ thống tệp, đây không phải là một tệp tải xuống mà là một thao tác lưu thực sự, trong đó tôi có thể chọn vị trí và tên của tệp, cũng như nơi nếu tôi chỉnh sửa, tôi có thể chỉ cần lưu các tệp đó vào cùng một tệp.

Hãy để tôi thay đổi biểu trưng và làm cho chữ "i" có màu đỏ. Bây giờ, nếu tôi nhấp vào lưu lại, nội dung sửa đổi sẽ được lưu vào cùng một tệp như trước. Để chứng minh, hãy để tôi xoá canvas rồi mở lại tệp. Như bạn có thể thấy, biểu trưng màu đỏ-xanh dương đã sửa đổi lại xuất hiện.

Làm việc với tệp

Trên các trình duyệt hiện không hỗ trợ API truy cập hệ thống tệp, mỗi thao tác lưu là một lượt tải xuống, vì vậy, khi thực hiện thay đổi, tôi sẽ có nhiều tệp có số tăng dần trong tên tệp và lấp đầy thư mục Tải xuống. Nhưng bất chấp nhược điểm này, tôi vẫn có thể lưu tệp.

Mở tệp

Vậy bí quyết là gì? Làm cách nào để mở và lưu hoạt động trên các trình duyệt khác nhau có thể hoặc không hỗ trợ API Truy cập hệ thống tệp? Thao tác mở tệp trong Excalidraw sẽ diễn ra trong một hàm có tên là loadFromJSON)(). Hàm này sẽ gọi một hàm có tên là 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);
};

Hàm fileOpen() bắt nguồn từ một thư viện nhỏ mà tôi đã viết có tên là browser-fs-access mà chúng tôi sử dụng trong Excalidraw. Thư viện này cung cấp quyền truy cập vào hệ thống tệp thông qua API Truy cập hệ thống tệp với một phương thức dự phòng cũ, vì vậy, bạn có thể sử dụng thư viện này trong mọi trình duyệt.

Trước tiên, tôi sẽ cho bạn biết cách triển khai khi API này được hỗ trợ. Sau khi thương lượng các loại MIME và đuôi tệp được chấp nhận, phần trung tâm sẽ gọi hàm showOpenFilePicker() của API Truy cập hệ thống tệp. Hàm này trả về một mảng tệp hoặc một tệp duy nhất, tuỳ thuộc vào việc bạn có chọn nhiều tệp hay không. Tất cả những gì còn lại là đặt handle tệp trên đối tượng tệp để có thể truy xuất lại handle đó.

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

Việc triển khai dự phòng dựa vào phần tử input thuộc loại "file". Sau khi thương lượng các loại và tiện ích MIME sẽ được chấp nhận, bước tiếp theo là nhấp vào phần tử đầu vào theo phương thức lập trình để hộp thoại mở tệp hiển thị. Khi thay đổi, tức là khi người dùng đã chọn một hoặc nhiều tệp, lời hứa sẽ được thực hiện.

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

Lưu tệp

Bây giờ hãy lưu. Trong Excalidraw, quá trình lưu sẽ diễn ra trong một hàm có tên là saveAsJSON(). Trước tiên, lớp này sẽ chuyển đổi tuần tự mảng phần tử Excalidraw thành JSON, chuyển đổi JSON thành một blob, sau đó gọi một hàm có tên là fileSave(). Hàm này cũng do thư viện browser-fs-access cung cấp.

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

Trước tiên, hãy cùng tôi xem cách triển khai cho các trình duyệt có hỗ trợ API Truy cập hệ thống tệp. Vài dòng đầu tiên có vẻ hơi liên quan, nhưng tất cả những gì chúng làm là thương lượng các loại MIME và đuôi tệp. Khi tôi đã lưu trước đây và đã có tên người dùng tệp, không cần hiển thị hộp thoại lưu. Tuy nhiên, nếu đây là lần lưu đầu tiên, một hộp thoại tệp sẽ hiển thị và ứng dụng sẽ nhận lại một handle tệp để sử dụng trong tương lai. Sau đó, công việc còn lại chỉ là ghi vào tệp, quá trình này diễn ra thông qua một luồng có thể ghi.

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

Tính năng "lưu dưới dạng"

Nếu quyết định bỏ qua một tên người dùng đã có sẵn, tôi có thể triển khai tính năng "lưu dưới dạng" để tạo tệp mới dựa trên tệp hiện có. Để minh hoạ điều này, hãy để tôi mở một tệp hiện có, thực hiện một số sửa đổi, sau đó không ghi đè tệp hiện có mà tạo một tệp mới bằng cách sử dụng tính năng lưu dưới dạng. Thao tác này sẽ giữ nguyên tệp gốc.

Việc triển khai các trình duyệt không hỗ trợ API Truy cập hệ thống tệp khá ngắn gọn vì tất cả những gì mà công cụ này thực hiện là tạo một phần tử neo với thuộc tính download có giá trị là tên tệp mong muốn và URL của blob làm giá trị thuộc tính 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();
};

Sau đó, phần tử neo sẽ được nhấp theo phương thức lập trình. Để ngăn rò rỉ bộ nhớ, bạn cần thu hồi URL của blob sau khi sử dụng. Vì đây chỉ là một tệp tải xuống, nên sẽ không có hộp thoại lưu tệp nào xuất hiện và tất cả các tệp sẽ nằm trong thư mục Downloads mặc định.

Kéo và thả

Một trong những tính năng tích hợp hệ thống mà tôi yêu thích trên máy tính là tính năng kéo và thả. Trong Excalidraw, khi tôi thả tệp .excalidraw vào ứng dụng, tệp đó sẽ mở ngay lập tức và tôi có thể bắt đầu chỉnh sửa. Trên các trình duyệt hỗ trợ API Truy cập hệ thống tệp, tôi thậm chí có thể lưu ngay các thay đổi của mình. Không cần phải đi qua hộp thoại lưu tệp vì bạn đã lấy được handle tệp bắt buộc từ thao tác kéo và thả.

Bí quyết để làm điều này là gọi getAsFileSystemHandle() trên mục chuyển dữ liệu khi API Truy cập hệ thống tệp được hỗ trợ. Sau đó, tôi chuyển tên người dùng tệp này đến loadFromBlob() mà bạn có thể nhớ qua vài đoạn văn ở trên. Bạn có thể làm rất nhiều việc với tệp: mở, lưu, lưu quá mức, kéo, thả. Đồng nghiệp của tôi là Pete và tôi đã ghi lại tất cả các thủ thuật này và nhiều nội dung khác trong bài viết của chúng tôi để các bạn có thể nắm bắt phòng trường hợp mọi thứ diễn ra quá nhanh.

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

Chia sẻ tệp

Một phương thức tích hợp hệ thống khác hiện có trên Android, ChromeOS và Windows là thông qua API Mục tiêu chia sẻ trên web. Tôi đang ở trong ứng dụng Files trong thư mục Downloads. Tôi có thể thấy 2 tệp, một trong số đó có tên không phải là mã mô tả untitled và một dấu thời gian. Để kiểm tra nội dung trong đó, tôi nhấp vào biểu tượng ba dấu chấm, sau đó chia sẻ và một trong các tuỳ chọn xuất hiện là Excalidraw. Khi nhấn vào biểu tượng này, tôi có thể thấy rằng tệp chỉ chứa biểu trưng I/O.

Lipis trên phiên bản Electron không dùng nữa

Một việc bạn có thể làm với các tệp mà tôi chưa nói đến đó là kích hoạt lại các tệp đó. Điều thường xảy ra khi bạn nhấp đúp vào một tệp là ứng dụng liên kết với loại MIME của tệp sẽ mở ra. Ví dụ cho .docx, đây sẽ là Microsoft Word.

Excalidraw từng có phiên bản Electron của ứng dụng hỗ trợ các liên kết loại tệp như vậy, vì vậy, khi bạn nhấp đúp vào tệp .excalidraw, ứng dụng Excalidraw Electron sẽ mở ra. Lipis, người mà bạn đã gặp trước đây, vừa là nhà sáng tạo vừa là người ngừng sử dụng Excalidraw Electron. Tôi hỏi ông tại sao ông cảm thấy có thể không dùng phiên bản Electric:

Mọi người đã yêu cầu một ứng dụng Electron ngay từ đầu, chủ yếu là vì họ muốn mở tệp bằng cách nhấp đúp. Chúng tôi cũng đã có ý định đưa ứng dụng này vào các cửa hàng ứng dụng. Song song với đó, có người đề xuất tạo một PWA, vì vậy, chúng tôi đã làm cả hai. May mắn thay, chúng tôi đã được giới thiệu về các API Project Fugu như quyền truy cập vào hệ thống tệp, quyền truy cập vào bảng nhớ tạm, xử lý tệp và nhiều API khác. Chỉ với một cú nhấp chuột duy nhất, bạn có thể cài đặt ứng dụng trên máy tính để bàn hoặc thiết bị di động mà không cần thêm trọng lượng của Electron. Việc ngừng sử dụng phiên bản Electron, chỉ tập trung vào ứng dụng web và biến ứng dụng này thành PWA tốt nhất có thể là một quyết định dễ dàng. Ngoài ra, chúng tôi hiện có thể phát hành PWA lên Cửa hàng Play và Microsoft Store! Thật tuyệt vời!

Có thể nói rằng Excalidraw cho Electron không bị ngừng sử dụng vì Electron không tốt, mà là vì web đã trở nên đủ tốt. Tôi thích nội dung này!

Xử lý tệp

Khi tôi nói "web đã trở nên đủ tốt", đó là nhờ các tính năng như Xử lý tệp sắp ra mắt.

Đây là cách cài đặt macOS Big Sur thông thường. Bây giờ, hãy xem điều gì xảy ra khi tôi nhấp chuột phải vào tệp Excalidraw. Tôi có thể chọn mở tệp bằng Excalidraw, một PWA đã cài đặt. Tất nhiên, việc nhấp đúp cũng sẽ hoạt động, chỉ là ít ấn tượng hơn khi minh hoạ trong bản ghi màn hình.

Vậy cách thức hoạt động như thế nào? Bước đầu tiên là làm cho các loại tệp mà hệ điều hành có thể xử lý. Tôi thực hiện việc này trong một trường mới có tên là file_handlers trong tệp kê khai ứng dụng web. Giá trị của lớp này là một mảng các đối tượng có thao tác và thuộc tính accept. Thao tác này xác định đường dẫn URL mà hệ điều hành chạy ứng dụng của bạn và đối tượng chấp nhận là các cặp khoá-giá trị của loại MIME và đuôi tệp được liên kết.

{
  "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"]
      }
    }
  ]
}

Bước tiếp theo là xử lý tệp khi ứng dụng khởi chạy. Điều này xảy ra trong giao diện launchQueue, nơi tôi cần đặt một người tiêu dùng bằng cách gọi setConsumer(). Tham số cho hàm này là một hàm không đồng bộ nhận launchParams. Đối tượng launchParams này có một trường có tên là các tệp để tôi có thể xử lý một mảng các tên tệp để xử lý. Tôi chỉ quan tâm đến tệp đầu tiên và từ handle tệp này, tôi nhận được một blob mà sau đó tôi chuyển vào 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 });
      });
    });
}

Xin nhắc lại, nếu quá trình này quá nhanh, bạn có thể đọc thêm về API Xử lý tệp trong bài viết của tôi. Bạn có thể bật tính năng xử lý tệp bằng cách đặt cờ tính năng nền tảng web thử nghiệm. Theo dự kiến, trò chơi này sẽ có trên Chrome vào cuối năm nay.

Tích hợp bảng nhớ tạm

Một tính năng thú vị khác của Excalidraw là tích hợp bảng nhớ tạm. Tôi có thể sao chép toàn bộ bản vẽ hoặc chỉ một phần bản vẽ vào bảng nhớ tạm, có thể thêm hình mờ nếu muốn, sau đó dán vào một ứng dụng khác. Nhân tiện, đây là phiên bản web của ứng dụng Windows 95 Paint.

Cách thức hoạt động của tính năng này đơn giản đến mức đáng ngạc nhiên. Tất cả những gì tôi cần là canvas dưới dạng một blob mà sau đó tôi ghi vào bảng nhớ tạm bằng cách truyền mảng một phần tử có ClipboardItem với blob vào hàm navigator.clipboard.write(). Để biết thêm thông tin về những việc bạn có thể làm với API bảng nhớ tạm, hãy xem bài viết của Jason và bài viết của tôi.

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

Cộng tác với những người khác

Chia sẻ URL phiên

Bạn có biết rằng Excalidraw cũng có chế độ cộng tác không? Nhiều người có thể cùng làm việc trên cùng một tài liệu. Để bắt đầu một phiên mới, tôi nhấp vào nút cộng tác trực tiếp rồi bắt đầu một phiên. Tôi có thể dễ dàng chia sẻ URL của phiên với các cộng tác viên của mình nhờ API Chia sẻ web mà Excalidraw đã tích hợp.

Cộng tác trực tiếp

Tôi đã mô phỏng một phiên cộng tác cục bộ bằng cách làm việc trên biểu trưng Google I/O trên Pixelbook, điện thoại Pixel 3a và iPad Pro. Bạn có thể thấy những thay đổi tôi thực hiện trên một thiết bị được phản ánh trên tất cả các thiết bị khác.

Tôi thậm chí có thể nhìn thấy tất cả các con trỏ di chuyển xung quanh. Con trỏ của Pixelbook di chuyển ổn định vì được điều khiển bằng bàn di chuột, nhưng con trỏ của điện thoại Pixel 3a và con trỏ của máy tính bảng iPad Pro lại nhảy xung quanh vì tôi điều khiển các thiết bị này bằng cách nhấn bằng ngón tay.

Xem trạng thái của cộng tác viên

Để cải thiện trải nghiệm cộng tác theo thời gian thực, thậm chí còn có một hệ thống phát hiện trạng thái rảnh đang chạy. Con trỏ của iPad Pro hiển thị một chấm màu xanh lục khi tôi sử dụng. Dấu chấm này chuyển sang màu đen khi tôi chuyển sang một ứng dụng hoặc thẻ trình duyệt khác. Và khi tôi đang dùng ứng dụng Excalidraw nhưng không làm gì cả, con trỏ sẽ cho tôi thấy trạng thái rảnh, được biểu thị bằng 3 zZZ.

Những độc giả đam mê ấn phẩm của chúng tôi có thể có xu hướng nghĩ rằng tính năng phát hiện trạng thái rảnh sẽ được hiện thực hoá thông qua API Phát hiện trạng thái rảnh. Đây là một đề xuất ở giai đoạn đầu được triển khai trong bối cảnh của Project Fugu. Cảnh báo tiết lộ nội dung: không phải. Mặc dù đã triển khai dựa trên API này trong Excalidraw, nhưng cuối cùng, chúng tôi đã quyết định chuyển sang một phương pháp truyền thống hơn dựa trên việc đo lường chuyển động của con trỏ và chế độ hiển thị trang.

Ảnh chụp màn hình nội dung phản hồi về tính năng Phát hiện trạng thái không hoạt động được gửi trong kho lưu trữ Phát hiện trạng thái rảnh của WICG.

Chúng tôi đã gửi phản hồi về lý do API Phát hiện trạng thái rảnh không giải quyết được trường hợp sử dụng của chúng tôi. Tất cả các API của Project Fugu đều đang được phát triển công khai để mọi người đều có thể tham gia và lắng nghe ý kiến của họ!

Lipis về những điều đang kìm hãm Excalidraw

Nhân dịp này, tôi hỏi lipis một câu hỏi cuối cùng về những gì anh ấy cho là còn thiếu trong nền tảng web giữ lại Excalidraw:

API Quyền truy cập vào hệ thống tệp rất tuyệt, nhưng bạn biết điều gì không? Hầu hết các tệp mà tôi quan tâm hiện nay đều nằm trong Dropbox hoặc Google Drive, chứ không phải trên ổ đĩa cứng. Tôi muốn API Truy cập hệ thống tệp sẽ bao gồm một tầng trừu tượng cho các nhà cung cấp hệ thống tệp từ xa như Dropbox hoặc Google để tích hợp và nhà phát triển có thể viết mã dựa vào đó. Sau đó, người dùng có thể yên tâm vì biết rằng các tệp của họ được an toàn với nhà cung cấp dịch vụ đám mây mà họ tin tưởng.

Tôi hoàn toàn đồng ý với lipis, tôi cũng sống trên đám mây. Chúng tôi hy vọng điều này sẽ sớm được triển khai.

Chế độ ứng dụng dạng thẻ

Rất ấn tượng! Chúng tôi đã thấy rất nhiều tính năng tích hợp API thực sự tuyệt vời trong Excalidraw. Hệ thống tệp, xử lý tệp, bảng nhớ tạm, chia sẻ trên webmục tiêu chia sẻ trên web. Nhưng đây là một điều nữa. Từ trước đến nay, tôi chỉ có thể chỉnh sửa một tài liệu tại một thời điểm nhất định. Không còn nữa. Hãy tận hưởng phiên bản đầu tiên của chế độ ứng dụng theo thẻ trong Excalidraw. Đây là giao diện của ứng dụng.

Tôi có một tệp hiện có đang mở trong ứng dụng web tiến bộ (PWA) Excalidraw đã cài đặt và đang chạy ở chế độ độc lập. Bây giờ, tôi mở một thẻ mới trong cửa sổ độc lập. Đây không phải là thẻ trình duyệt thông thường mà là thẻ PWA. Trong thẻ mới này, tôi có thể mở một tệp phụ và làm việc độc lập với các tệp đó trong cùng một cửa sổ ứng dụng.

Chế độ ứng dụng theo thẻ đang ở giai đoạn đầu và chưa có gì là chắc chắn. Nếu bạn quan tâm, hãy nhớ đọc về trạng thái hiện tại của tính năng này trong bài viết của tôi.

Closing (Đang đóng)

Để nắm bắt thông tin về tính năng này và các tính năng khác, hãy nhớ theo dõi công cụ theo dõi API Fugu của chúng tôi. Chúng tôi rất vui mừng được thúc đẩy web và giúp bạn làm được nhiều việc hơn trên nền tảng này. Hướng đến một Excalidraw không ngừng cải tiến và ở đây là tất cả những ứng dụng tuyệt vời mà bạn sẽ xây dựng. Hãy bắt đầu sáng tạo tại excalidraw.com.

Tôi rất mong được thấy một số API mà tôi hiển thị hôm nay xuất hiện trong ứng dụng của bạn. Tôi là Tom, bạn có thể tìm thấy tôi với tên @tomayac trên Twitter và trên Internet nói chung. Cảm ơn bạn rất nhiều vì đã xem và tận hưởng phần còn lại của Google I/O.