PWA Inking Enable 2D inking for the web!

There are many ways to enable inking on the web, but they all involve their challenges to set up. Do you need to support 2D drawing or 3D rendering?

July 15, 2021

Killian McCoy

via GIPHY

There are many ways to enable inking on the web, but they all involve their challenges to set up. Do you need to support 2D drawing or 3D rendering? How will you minimize rendering latency? How should the drawing respond to browser events like window resizing, tab switching, or zooming? What kinds of input do you want to handle? What do you want to do with a finished drawing?

The PWABuilder team built a solution that enables a basic inking experience for the modern web and addresses the above considerations. We are excited to announce the 1.0 version of the pwa-inking component is now available!

pwa-inking is a web component that

  • Uses a desynchronized 2D HTML canvas.
  • Optimizes canvas redraws through the requestAnimationFrame() api and the requestIdleCallback() api functions.
  • Resizes and refocuses with the browser.
  • Supports pointer (mouse, touch, and pen) events.
  • Offers 4 inking experiences: pen, pencil, highlighter, and eraser.
  • Allows you to copy your drawing to the clipboard and save it as a png through the native device file system

In other words, pwa-inking can let users draw a picture as quickly as they can doodle it with a finger and then save it to their phone camera roll! And developer can make it happen by adding only a few lines of code to their existing web apps

Why would I use this?

  • modern using the latest web APIs to keep your web apps fast while handling and rendering user input: touch, pen, and mouse friendly!
  • ready to go wherever you want to use it in your web apps, right on your homepage or nested in another web component.
  • customizable through CSS shadow parts and you can set any configuration of the included tools you want to use.
  • free to use and open-source because why not!

Getting Started

Install it

You can install this component through npm or a script tag. If you are already using npm, we recommend installing the pwa-inking npm package. Otherwise, the script tag works fine for simple use cases.

Script tag

  1. Add this script tag in the head of your index.html

NPM

  1. Run this command in your project directory:

    npm install @pwabuilder/pwa-inking
  2. Add this import statement to your script file:

    import @pwabuilder/pwa-inking

Pick your starter

This component can be used with or without an included toolbar:

Canvas with toolbar

A screenshot of the pwa-inking component with the default toolbar.

A screenshot of the pwa-inking component with the default toolbar.

The default and recommended experience is to add an inking-component with a nested inking-toolbar to get the most functionality for the least amount of code:

Try the component with the default toolbar live! | See the code for the component with the default toolbar

Canvas without toolbar

A screenshot of the pwa-inking component without a toolbar.

A screenshot of the pwa-inking component without a toolbar.

Some advanced users might want to implement their own toolbar or control the canvas purely through JavaScript, so the inking-canvas can also be used alone and controlled via the components exposed API:

Try the component without a toolbar live! | See the code for the component without a toolbar

Customize it

Pick your tools

A screenshot of pwa-inking with a custom toolbar positioned in the bottom right corner.

A screenshot of pwa-inking with a custom toolbar positioned in the bottom right corner.

Only want some of the tools? You can specify the toolbar contents and even change its position and orientation on the canvas:

See the component live with a custom positioned toolbar | See the code for the component with a custom positioned toolbar

Modify the CSS

A screenshot of pwa-inking with customized styles on the toolbar and the canvas.

A screenshot of pwa-inking with customized styles on the toolbar and the canvas.

The canvas and the toolbar tool styles are completely customizable through the CSS shadow parts feature in CSS:

See the component fully customized live | See the code for fully customizing the component

Limitations

At the time of this release, browsers do not fully support features that impact the inking experience.

Pointer event properties

Some pointer event properties that could be used to influence stroke behavior are available today but do not yet report meaningful data. These include:

  • tangentialPressure
  • tiltX
  • tiltY
  • twist

The pointer event properties utilized in this release to influence stroke size are width and pressure.

Low latency canvas

The 2D canvas contexts of this web component rely on the availability of the desynchronized attribute to support low latency.

If a browser does not recognize this attribute, then the canvas contexts are established without it.

A Chromium bug related to image extraction of the low latency canvas is preventing this web component copy & save features from working on impacted platforms. The fix has been applied the Chromium source code, but many Chromium-based browsers (including the stable versions of Edge and Chrome) have not received it yet. We have a GitHub issue tracking this.

requestIdleCallback()

The ability to process inking component events in a way that yields to other activity on the main thread is made possible through the requestIdleCallback() function, but it is not widely supported across browsers yet.

If a browser does not support this API, the impacted inking component calls are run instead as IIFE (immediately invoked function expressions).

Clipboard API

The canvas state is copied as a png image to the browser clipboard through the Clipboard API.

If a browser does not support navigator.clipboard or ClipboardItem, then a failure toast (and console error message if you clone and run the source code locally) will appear when a user clicks the copy button.

What next

We are still planning our roadmap and we would love to hear from you! Let the PWABuilder team know what you think of this version and what you think should come next.

Find us on our Twitter (@pwabuilder) and engage with us on our GitHub repo.

Thanks for reading!

module.exports = {
eleventyComputed: {
eleventyNavigation: {
name: (data) => data.title,
excerpt: (data) => data.excerpt,
description: (data) => data.description,
},
},
}

Documentation you may like...

Back to Blog Home

Categories