Excalidraw und Fugu: Kaufprozesse bei Hauptdiensten verbessern

Jede hinreichend fortschrittliche Technologie ist nicht von Magie zu unterscheiden. Es sei denn, Sie verstehen es. Mein Name ist Thomas Steiner. Ich arbeite im Bereich Developer Relations bei Google. In diesem Beitrag zu meinem Google I/O-Vortrag werde ich auf einige der neuen Fugu-APIs eingehen und sehen, wie sie die wichtigsten Nutzerpfade in der Excalidraw-PWA verbessern. So können Sie sich von diesen Ideen inspirieren lassen und sie auf Ihre eigenen Apps anwenden.

Wie ich zu Excalidraw kam

Ich möchte mit einer Geschichte beginnen. Am 1. Januar 2020 Christopher Chedeau, Softwareentwickler bei Facebook, Tweet über seine kleine Zeichen-App damit begonnen hat. Mit diesem Tool können Sie Rahmen und Pfeile zeichnen, von Hand gezeichnet. Am nächsten Tag könnt ihr auch Ellipsen und Text zeichnen, Objekte auswählen und um sie herum. Am 3. Januar hatte die App ihren Namen: Excalidraw. wurde der Kauf des Domainnamens eine seiner ersten Handlungen. Von Jetzt können Sie Farben verwenden und die gesamte Zeichnung als PNG exportieren.

Screenshot der Excalidraw-Prototypanwendung, die zeigt, dass sie Rechtecke, Pfeile, Ellipsen und Text unterstützt.

Am 15. Januar gab Christopher Blogpost mit einem auf Twitter Aufmerksamkeit erregt, auch von mir. Der Beitrag begann mit einigen beeindruckenden Statistiken:

  • 12.000 einzelne aktive Nutzer
  • 1.500 Sterne auf GitHub
  • 26 Beitragende

Für ein Projekt, das erst vor zwei Wochen begonnen hat, ist das gar nicht so schlecht. Aber die Tatsache, dass mein Interesse am Ende des Beitrags deutlich wurde. Christopher schrieb, dass er etwas Neues ausprobiert habe. Zeit: Alle erhalten, die eine Pull-Anfrage erhalten haben, uneingeschränkten Commit-Zugriff gewähren. Am selben Tag des Als ich den Blogpost gelesen habe, erhielt ich eine Pull-Anfrage, das Excalidraw unterstützt die File System Access API und behebt Funktionsanfrage, die jemand eingereicht hat.

Screenshot des Tweets, in dem ich meine PR ankündige

Meine Pull-Anfrage wurde einen Tag später zusammengeführt und von da an hatte ich vollen Commit-Zugriff. Offensichtlich Ich habe meine Macht nicht ausgenutzt. Das gilt auch für die anderen 149 Mitwirkenden.

Excalidraw ist heute eine vollwertige installierbare progressive Web-App mit Offline-Unterstützung, ein beeindruckender dunkler Modus und ja, die Möglichkeit, Dateien zu öffnen und zu speichern, dank File System Access API.

Screenshot der Excalidraw-PWA im heutigen Status.

Lipis erklärt, warum er so viel Zeit Excalidraw widmet

Dies ist das Ende meiner Videoreihe „Wie ich zu Excalidraw kam“ aber bevor ich auf einige der Ich freue mich, Ihnen Panayiotis vorzustellen. Panayiotis Lipiridis, auf das Internet einfach als Lipi bekannt ist, trägt am meisten dazu bei, Excalidraw. Ich fragte Lipi, was ihn dazu motiviert, sich so viel Zeit für Excalidraw zu widmen:

Wie alle anderen habe ich in Christophers Tweet von diesem Projekt erfahren. Mein erster Beitrag Open Color library (Farbbibliothek öffnen). Die Farben, die weiterhin heute Teil von Excalidraw. Das Projekt wuchs und wir erhielten sehr viele Anfragen. Meine nächste bestand darin, ein Back-End zum Speichern von Zeichnungen zu erstellen, damit Nutzer sie freigeben konnten. Aber was ist motiviert mich wirklich dazu, beizutragen, ist, dass jeder, der Excalidraw ausprobiert hat, nach Ausreden sucht, noch einmal versuchen.

Ich stimme Liipis vollkommen zu. Wer Excalidraw ausprobiert hat, sucht nach Ausreden, um es noch einmal zu verwenden.

Excalidraw in Aktion

Ich möchte Ihnen jetzt zeigen, wie Sie Excalidraw in der Praxis einsetzen können. Ich bin kein großer Künstler, aber Das Google I/O-Logo ist einfach genug, ich probiere es mal aus. Ein Feld ist das „i“, eine Linie kann das Schrägstrich und das „o“ ist ein Kreis. Ich halte die Umschalttaste gedrückt, bis der Kreis perfekt ist. Lass mich bewegen den Schrägstrich etwas ändern, damit es besser aussieht. Jetzt etwas Farbe für das „i“ und das „O“. Blau ist gut. Vielleicht einen anderen Füllstil? Alles ausgefüllt oder schraffiert? Nee, Hachure sieht toll aus. Sie ist nicht perfekt, Das ist die Idee von Excalidraw, also lassen Sie mich sie speichern.

Ich klicke auf das Symbol zum Speichern und gebe im Dialogfeld zum Speichern der Datei einen Dateinamen ein. In Chrome ist ein Browser, File System Access API unterstützt, ist dies kein Download, sondern ein echter Speichervorgang. den Speicherort und Namen der Datei auswählen und wo ich sie, wenn ich sie bearbeite, dieselbe Datei.

Ich ändere jetzt das Logo und Rot. Wenn ich jetzt erneut auf „Speichern“ klicke, wird meine Änderung dieselbe Datei wie zuvor. Als Beweis möchte ich den Canvas löschen und die Datei wieder öffnen. Wie Sie sehen, Das modifizierte rot-blaue Logo ist wieder da.

Mit Dateien arbeiten

In Browsern, die die File System Access API derzeit nicht unterstützen, ist jeder Speichervorgang ein herunterladen. Wenn ich also Änderungen vornehme, bekomme ich mehrere Dateien mit einer steigenden Zahl im Dateinamen aus, die in meinem Download-Ordner erscheinen. Trotzdem kann ich die Datei trotzdem speichern.

Dateien werden geöffnet

Was ist also das Geheimnis? Wie funktioniert das Öffnen und Speichern in verschiedenen Browsern, die möglicherweise nicht funktionieren? die File System Access API unterstützen? Das Öffnen einer Datei in Excalidraw erfolgt in einer Funktion namens loadFromJSON)(), die wiederum eine Funktion namens fileOpen() aufruft.

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

Die Funktion fileOpen(), die aus einer kleinen, von mir geschriebenen Bibliothek namens browser-fs-access, die wir in Excalidraw. Diese Bibliothek bietet Zugriff auf das Dateisystem über die File System Access API mit einem alten Fallback, sodass sie in beliebigen Browser.

Zuerst zeige ich Ihnen die Implementierung, wenn die API unterstützt wird. Nach der Verhandlung des akzeptierten MIME-Typen und Dateiendungen, ist der Aufruf des File System Access APIs Funktion showOpenFilePicker(). Diese Funktion gibt ein Array von Dateien oder eine einzelne Datei zurück, ob mehrere Dateien ausgewählt werden. Jetzt müssen wir nur noch das Datei-Handle auf die Datei -Objekt, damit es wieder abgerufen werden kann.

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

Die Fallback-Implementierung basiert auf einem input-Element des Typs "file". Nach Verhandlung über die akzeptierten MIME-Typen und -Erweiterungen sind, besteht der nächste Schritt darin, programmatisch auf die Eingabe zu klicken. -Element, sodass das Dialogfeld zum Öffnen von Dateien angezeigt wird. Bei einer Änderung, d. h. wenn der Nutzer ein oder mehrere wird das Versprechen aufgelöst.

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

Dateien werden gespeichert

Jetzt zum Speichern. In Excalidraw erfolgt das Speichern in einer Funktion namens saveAsJSON(). Zuerst serialisiert das Array der Excalidraw-Elemente in JSON, konvertiert das JSON-Format in ein Blob und ruft dann eine mit dem Namen fileSave(). Diese Funktion wird ebenfalls durch den Parameter 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 };
};

Sehen wir uns noch einmal die Implementierung für Browser an, die die File System Access API unterstützen. Die Die ersten Zeilen sind etwas komplizierter, aber es werden lediglich die MIME-Typen und die Datei Erweiterungen. Wenn ich schon einmal gespeichert habe und bereits ein Datei-Handle habe, muss kein Dialogfeld zum Speichern angezeigt. Handelt es sich jedoch um den ersten Speichervorgang, wird ein Dateidialogfeld angezeigt und die App erhält einen Datei-Handle. zur späteren Verwendung zurück. Der Rest wird einfach in die Datei geschrieben, was über eine beschreibbaren Stream.

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

Die Schaltfläche „Speichern unter“ Funktion

Wenn ich ein bereits vorhandenes Datei-Handle ignorieren möchte, kann ich die Funktion „Speichern unter“ implementieren. Funktion zum Erstellen basierend auf einer vorhandenen Datei eine neue Datei erstellen. Dazu öffne ich eine vorhandene Datei, der Änderung. Die vorhandene Datei wird dann nicht überschrieben, sondern mithilfe der Funktion zum Speichern unter . Dadurch bleibt die Originaldatei erhalten.

Die Implementierung für Browser, die die File System Access API nicht unterstützen, ist kurz, da sie erstellt ein Ankerelement mit einem download-Attribut, dessen Wert dem gewünschten Dateinamen entspricht, und eine Blob-URL als href-Attributwert.

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

Das Ankerelement wird dann programmatisch angeklickt. Um Speicherlecks zu vermeiden, muss die Blob-URL nach der Nutzung widerrufen werden. Da es sich hierbei nur um einen Download handelt, wird kein Dialogfeld zum Speichern von Dateien angezeigt. -Dateien landen im Standardordner Downloads.

Drag-and-Drop

Eine meiner Lieblings-Systemintegrationen auf dem Desktop ist Drag-and-drop. Wenn ich in Excalidraw ein .excalidraw-Datei in die Anwendung hoch, öffnet sich sie sofort und ich kann mit der Bearbeitung beginnen. In Browsern die die File System Access API unterstützen, kann ich meine Änderungen sogar sofort speichern. Du musst nicht gehen über ein Dialogfeld zum Speichern von Dateien, da das erforderliche Datei-Handle per Drag-and-drop abgerufen wurde .

Das Geheimnis ist, dass getAsFileSystemHandle() auf der data Transfer-Element ansehen, wenn die File System Access API unterstützt wird. Dann übergebe ich das Datei-Handle loadFromBlob(), wie du dir vielleicht aus den obigen Abschnitten erinnerst. So viele Die Möglichkeiten von Dateien: Öffnen, Speichern, Überspeichern, Ziehen und Ablegen. Mein Kollege Pete Diese Tricks und mehr habe ich in unserem Artikel dokumentiert. für den Fall, dass das alles zu schnell ging.

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

Dateien teilen

Eine weitere Systemintegration, die derzeit unter Android, ChromeOS und Windows läuft, erfolgt über die Web Share Target API. Hier bin ich in der App „Dateien“ in meinem Ordner „Downloads“. Ich kann zwei Dateien sehen, eine davon mit dem nicht beschreibenden Namen untitled und einem Zeitstempel. Um zu überprüfen, klicke ich auf das Dreipunkt-Menü und wähle „Share“ aus. Eine der angezeigten Optionen Excalidraw. Wenn ich auf das Symbol tippe, sehe ich, dass die Datei wieder nur das I/O-Logo enthält.

Lipis auf der veralteten Electron-Version

Dateien, über die ich noch nicht gesprochen habe, können Sie beispielsweise mit doubleclick. Was in der Regel wenn Sie auf eine Datei doppelklicken, ist die App, die dem MIME-Typ der Datei zugeordnet ist, wird geöffnet. Für .docx wäre das beispielsweise Microsoft Word.

Excalidraw hatte zuvor eine Electron-Version der App, die solche Dateitypverknüpfungen unterstützt. Wenn Sie also auf eine .excalidraw-Datei doppelklicken, wird das Ereignis Die Excalidraw Electron App wird geöffnet. Lipis, die ihr bereits kennt, war sowohl der Creator als auch und die Abschaffung von Excalidraw Electron. Ich fragte ihn, warum er es für möglich hält, das Produkt Elektronenversion:

Die Leute haben von Anfang an nach einer Electron-App gefragt, hauptsächlich, weil sie Dateien mit einem Doppelklick öffnen. Außerdem wollten wir die App in App-Shops anbieten. Parallel dazu schlug vor, stattdessen eine PWA zu erstellen, also haben wir einfach beides getan. Zum Glück haben wir das Projekt Fugu vorgestellt. APIs wie Zugriff auf Dateisystem, Zugriff auf Zwischenablage, Dateiverwaltung usw. Mit nur einem Klick können Sie die App auf Ihrem Desktop oder Mobilgerät installieren, ohne das zusätzliche Gewicht von Electron. Es war einfach die Entscheidung, die Electron-Version einzustellen, sich nur auf die Web-App zu konzentrieren und sie die bestmögliche PWA. Außerdem können wir jetzt PWAs im Play Store und in der Microsoft Geschäft! Das ist großartig!

Man könnte sagen, Excalidraw für Electron wurde nicht eingestellt, weil Electron schlecht ist, aber weil das Web mittlerweile gut genug ist. Gefällt mir!

Dateiverwaltung

Wenn ich sage, „das Web ist gut genug geworden“, liegt das an Funktionen wie der neuen Datei Handhabung.

Dies ist eine reguläre macOS Big Sur-Installation. Sehen Sie sich nun an, was passiert, wenn ich Excalidraw-Datei. Ich kann sie mit Excalidraw öffnen, der installierten PWA. Natürlich Doppelklicks funktioniert auch, die Darstellung in einem Screencast ist nur weniger dramatisch.

Wie funktioniert das? Zunächst machen Sie die Dateitypen, die meine Anwendung verarbeiten kann, bekannt. des Betriebssystems. Dazu verwende ich im Web-App-Manifest ein neues Feld namens file_handlers. Das value ist ein Array von Objekten mit einer Aktion und einem accept-Attribut. Die Aktion bestimmt die URL Pfad, unter dem das Betriebssystem Ihre App startet, und das Accept-Objekt sind Schlüssel/Wert-Paare von MIME und die zugehörigen Dateiendungen.

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

Der nächste Schritt besteht darin, die Datei zu verarbeiten, wenn die Anwendung gestartet wird. Das passiert im launchQueue Schnittstelle, in der ich einen Nutzer durch Aufrufen von setConsumer() einrichten muss. Der Parameter für diesen ist eine asynchrone Funktion, die das launchParams empfängt. Dieses launchParams-Objekt ein Feld namens files , mit dem ich ein Array von Datei-Handles erhalte, mit denen ich arbeiten kann. Mir sind nur die und aus diesem Datei-Handle ein Blob, das ich dann an unseren alten 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 });
      });
    });
}

Falls dies zu schnell ging, finden Sie weitere Informationen zur File Handling API in meinen Artikel. Sie können die Dateiverwaltung aktivieren, indem Sie die experimentelle Webplattform festlegen Features. Es ist voraussichtlich noch in diesem Jahr in Chrome verfügbar.

Einbindung der Zwischenablage

Eine weitere coole Funktion von Excalidraw ist die Einbindung der Zwischenablage. kann ich meine Zeichnung kopieren oder in die Zwischenablage kopieren, ein Wasserzeichen hinzufügen, eine andere App. Dies ist übrigens eine Webversion der Windows 95 Paint-App.

Das funktioniert erstaunlich einfach. Alles, was ich brauche, ist der Canvas als Blob, das ich dann in die Zwischenablage kopieren, indem Sie ein Ein-Element-Array mit einem ClipboardItem mit dem Blob an den navigator.clipboard.write(). Weitere Informationen zur Verwendung der Zwischenablage API: Siehe Jasons und meinen Artikel.

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

Zusammenarbeit mit Anderen

Sitzungs-URL teilen

Wussten Sie, dass Excalidraw auch einen Collab-Modus hat? An einem Projekt können verschiedene Personen zusammenarbeiten. dasselbe Dokument. Um eine neue Sitzung zu starten, klicke ich auf die Schaltfläche für die Live-Zusammenarbeit und starte eine Sitzung. Dank der Funktion Die von Excalidraw integrierte Web Share API.

Zusammenarbeit in Echtzeit

Ich habe vor Ort eine Zusammenarbeit simuliert, indem ich am Google I/O-Logo auf meinem Pixelbook gearbeitet habe. mein Pixel 3a und mein iPad Pro. Wie Sie sehen, werden Änderungen, die ich auf einem Gerät vornehme, allen anderen Geräten.

Ich kann sogar sehen, wie sich die Cursor bewegen. Der Cursor des Pixelbook bewegt sich gleichmäßig, da er gesteuert wird. mit dem Touchpad, aber der Cursor des Pixel 3a und des Tablets des iPad Pro springen herum, weil ich diese Geräte durch Tippen mit dem Finger steuern.

Status von Mitbearbeitern ansehen

Um die Zusammenarbeit in Echtzeit zu verbessern, wird sogar ein System zur Erkennung inaktiver Daten ausgeführt. Wenn ich das iPad Pro verwende, wird der Cursor mit einem grünen Punkt angezeigt. Der Punkt wird schwarz, wenn ich zu einem auf einem anderen Browsertab oder in einer anderen App. Wenn ich in der Excalidraw-App bin, aber einfach nichts tue, der Cursor als inaktiv angezeigt, symbolisiert durch die drei zZZs.

Eifrige Leser unserer Publikationen könnten glauben, dass die Inaktivitätserkennung durch der Idle Detection API, einem Vorschlag in einer frühen Phase, der im zum Projekt Fugu. Achtung, Spoiler: Ist es nicht. Wir hatten eine Implementierung, die auf dieser API basierte. bei Excalidraw entschieden wir uns für einen traditionelleren Ansatz, der auf Messungen Zeigerbewegung und Seitensichtbarkeit.

Screenshot des Feedbacks zur Inaktivitätserkennung, das im WICG-Repository für die Inaktivitätserkennung gesendet wurde.

Wir haben Feedback dazu eingereicht, warum die Idle Detection API verfügbar ist unseren Anwendungsfall nicht lösen konnten. Alle Project Fugu APIs werden offen entwickelt. Alle können sich einbringen und ihrer Stimme Gehör verschaffen.

Was hält Excalidraw zurück

Apropos: Ich habe Lipi eine letzte Frage zu den Informationen gestellt, die seiner Meinung nach im Web fehlen Plattform, die Excalidraw zurückhält:

Die File System Access API ist toll, aber weißt du was? Die meisten Dateien, die mir aktuell wichtig sind in meiner Dropbox oder Google Drive gespeichert, nicht auf meiner Festplatte. Ich wünschte, die File System Access API Integrieren Sie eine Abstraktionsebene für Remote-Dateisystemanbieter wie Dropbox oder Google zur Integration mit denen Entwickler programmieren können. Die Nutzenden konnten sich dann entspannen und das Gewissheit haben, dass ihre Dateien sicher sind. mit dem vertrauenswürdigen Cloud-Anbieter.

Ich stimme Liipis vollkommen zu, ich lebe auch in der Cloud. Wir hoffen, dass diese Funktion .

Anwendungsmodus mit Tabs

Wow! Wir haben in Excalidraw viele tolle API-Integrationen gesehen. Dateisystem, Dateiverwaltung, Zwischenablage, Webfreigabe und Webfreigabeziel. Aber hier noch eine Sache. Bisher konnte ich nur jeweils nur ein Dokument bearbeiten. Zum Glück nicht. Freuen Sie sich zum ersten Mal auf eine frühe Version von Tab-Anwendungsmodus in Excalidraw. Und so sieht es aus.

Ich habe bereits eine Datei in der installierten Excalidraw-PWA geöffnet, die im eigenständigen Modus ausgeführt wird. Jetzt Ich öffne einen neuen Tab im eigenständigen Fenster. Dies ist kein regulärer Browsertab, sondern ein PWA-Tab. In dieser in einem neuen Tab eine sekundäre Datei öffnen und unabhängig vom gleichen App-Fenster an ihnen arbeiten.

Der Tab-Anwendungsmodus befindet sich noch in der Anfangsphase und nicht alles ist in Stein gemeißelt. Wenn Sie wenn Sie daran interessiert sind, informieren Sie sich in der meinen Artikel an.

Abschluss

Informationen zu dieser und anderen Funktionen findest du in unserer Fugu API-Tracker Wir freuen uns sehr, das Web voranzubringen und um auf der Plattform mehr zu tun. Ein Hoch auf einen sich ständig verbessernden Excalidraw tollen Anwendungen erstellen, die Sie entwickeln werden. Du kannst jetzt loslegen und excalidraw.com.

Ich bin gespannt, ob einige der APIs, die ich heute gezeigt habe, in Ihren Apps angezeigt werden. Ich heiße Tom Du findest mich als @tomayac auf Twitter und allgemein im Internet. Vielen Dank fürs Zusehen. Viel Spaß beim Rest der Google I/O.