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.

Cách 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 trông giống như được vẽ tay và mang phong cách hoạt hình. 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 này đã có tên là Excalidraw. 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. Giờ đây, bạn có thể sử dụng màu sắc 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 nhiều sự chú ý trên Twitter, bao gồm cả tôi. Bài đăng bắt đầu bằng một số số liệu thống kê ấn tượng:

  • 12.000 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 mới bắt đầu cách đây 2 tuần, đó là một kết quả không tồi. 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: cấp quyền cam kết vô điều kiện cho tất cả những người gửi yêu cầu kéo. Vào cùng ngày đọc bài đăng trên blog, tôi đã có một yêu cầu lấy để 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à ai đó đã 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 của tôi được hợp nhất một ngày sau đó và từ đó, tôi có quyền truy cập đầy đủ để 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à cho đến nay, không ai trong số 149 cộng tác viên khác cũng không nhận thấy điều này.

Ngày nay, 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 (Mở thư viện màu), các màu này vẫn là một phần của Excalidraw cho đến ngày nay. Khi dự án phát triển và chúng tôi nhận được khá nhiều yêu cầu, đó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ữ các bản vẽ để người dùng có thể chia sẻ. Nhưng điều thực sự thúc đẩy tôi đóng góp là bất cứ ai đã dùng Excalidraw đều muốn tìm lý do để sử dụng lại ứng dụng này.

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.

Excalidraw 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à một kiểu tô khác? Tất cả đều đặc hay có đường viền chéo? Không, nét vẽ rất đẹp. Nó không hoàn hảo, nhưng đó là ý tưởng của Excalidraw, vì vậy, hãy để tôi lưu lại.

Tôi nhấp vào biểu tượng lưu và nhập tên tệp trong 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 lượt 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, đồng thời nếu chỉnh sửa, tôi chỉ cần lưu các nội dung chỉnh sửa đó 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 và 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. Tuy nhiên, mặc dù có 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 có thể hỗ trợ hoặc không hỗ trợ API truy cập hệ thống tệp? Thao tác mở tệp trong Excalidraw 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() đến từ một thư viện nhỏ mà tôi đã viết có tên là browser-fs-access mà chúng ta 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, hãy để tôi hướng dẫn bạn cách triển khai khi API đượ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 về các loại MIME và phần mở rộng 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 xuất hiện. 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 phân giải.

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 chuyển sang lưu. Trong Excalidraw, quá trình lưu 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. Một vài dòng đầu tiên có vẻ hơi phức tạp, 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 đó và đã có một handle 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. Phần còn lại chỉ là ghi vào tệp, việc 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 tay cầm tệp hiện có, tôi có thể triển khai tính năng "lưu dưới dạng" để tạo một 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 cho các trình duyệt không hỗ trợ API truy cập hệ thống tệp sẽ diễn ra ngắn gọn, vì tất cả những gì trình duyệt này làm là tạo một phần tử neo có thuộc tính download, giá trị của thuộc tính này là tên tệp mong muốn và URL 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 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ả một tệp .excalidraw vào ứng dụng, tệp đó sẽ mở ra 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 các thay đổi ngay lập tức. 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 để thực hiện việc 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 handle tệp này đến loadFromBlob(), bạn có thể nhớ từ một vài đoạn ở trên. Bạn có thể làm rất nhiều việc với các tệp: mở, lưu, lưu nhiều lần, 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 thủ thuật khác trong bài viết của chúng tôi để bạn có thể nắm bắt được nếu tất cả những điều này 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. Ở đây, tôi đang ở trong ứng dụng Files trong thư mục Downloads. Tôi có thể thấy hai tệp, một trong số đó có tên không mô tả untitled và dấu thời gian. Để kiểm tra nội dung của tệp, 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à Excalibur. 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 đề cập đến là nhấp đúp vào 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ụ: đối với .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 anh lý do anh cảm thấy có thể ngừng sử dụng phiên bản Electron:

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 dự định đưa ứng dụng này lên 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 lần nhấp, bạn có thể cài đặt ứng dụng trên máy tính hoặc thiết bị di động mà không cần thêm 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, giờ đây, chúng ta có thể phát hành PWA lên Cửa hàng Play và Cửa hàng Microsoft! Thật tuyệt!

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 ý tưởng 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ì sẽ xảy ra khi tôi nhấp chuột phải vào một tệp Excalibur. 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à cho hệ điều hành biết các loại tệp mà ứng dụng của tôi 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 thuộc tính này là một mảng các đối tượng có một hành động và một 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à các đuôi tệp liên quan.

{
  "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 tên là tệp, giúp tôi có được một mảng các tay điều khiể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 diễn ra 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. Tính năng này dự kiến sẽ ra mắt trong 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ính năng 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 của bản vẽ vào bảng nhớ tạm, có thể thêm hình mờ nếu muốn, sau đó dán bản vẽ đó 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 Paint trên Windows 95.

Cách hoạt động của tính năng này đơn giản đến đáng ngạc nhiên. Tất cả những gì tôi cần là canvas dưới dạng một blob, sau đó tôi sẽ ghi vào bảng nhớ tạm bằng cách truyền một 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 tôi và Jason.

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 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 phiên với cộng tác viên nhờ Web Share API (API chia sẻ trên 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 rằng những thay đổi tôi thực hiện trên một thiết bị sẽ được phản ánh trên tất cả các thiết bị khác.

Tôi thậm chí có thể thấy tất 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 chuyển sang màu đen khi tôi chuyển sang một thẻ trình duyệt hoặc ứng dụng khác. Và khi tôi đang ở trong ứng dụng Excalidraw nhưng không làm gì cả, con trỏ sẽ cho tôi biết là đang ở trạng thái rảnh, được biểu thị bằng ba chữ zZZ.

Những người đọc sành sỏi các ấn phẩm của chúng tôi có thể cho rằng tính năng phát hiện trạng thái rảnh được thực hiện thông qua API Phát hiện trạng thái rảnh, một đề xuất ở giai đoạn đầu đã được triển khai trong bối cảnh của Dự án 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 sử dụng phương pháp truyền thống hơn dựa trên việc đo lường chuyển động con trỏ và chế độ hiển thị trang.

Ảnh chụp màn hình phản hồi về tính năng Phát hiện trạng thái rảnh được gửi trên 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ả API của Dự án Fugu đều đang được phát triển công khai, vì vậy, mọi người đều có thể tham gia và bày tỏ ý kiến!

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

Nói về điều đó, tôi đã hỏi lipis một câu hỏi cuối cùng về những gì anh ấy cho rằng còn thiếu trên nền tảng web khiến Excalidraw bị hạn chế:

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 ngày 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 bao gồm một lớp trừu tượng để 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ể lập trình dựa trên lớp này. 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 tính năng 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 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 còn một điều nữa. Cho đế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. Dưới đây là giao diện của ứng dụng.

Tôi có một tệp hiện có đang mở trong 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 khi có thể thúc đẩy sự phát triển của web và giúp bạn làm được nhiều việc hơn trên nền tảng này. Chúc bạn thành công với Excalidraw ngày càng cải tiến và với tất cả các ứ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 đã giới thiệu 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 đã xem và chúc bạn tận hưởng phần còn lại của sự kiện Google I/O.