npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

canvas-sequencer

v3.1.0

Published

Store, serialize, parse, and execute sequences of canvas context instructions.

Downloads

2,861

Readme

canvas-sequencer

Node.js CI Coverage Status Maintainability

Store, serialize, parse, and execute series of canvas context instructions!

Contents

Why

Normally, if you have a sequence of canvas instructions, you might predefine them in a function which will be distributed in a script file to all your clients.

Suppose, however, that you wish to be able to dynamically define instructions from the server, and have those instructions executed on the canvas contexts of your clients. One option would be to wrap the instructions up in a string on the server, distribute the string, then have the clients call eval() on the string. This is error-prone and risky however, and exposes you to all the incumbent problems of the eval() function.

With canvas-sequencer you can package those instructions up in a sequence and transmit them. Once on the client side, you can unpack the instructions and execute them on any given context (or even multiple contexts), and all the issues with the eval() technique fade away.

Importing:

Server side, or in a Node environment.

const { CanvasSequence, CanvasBlueprint } = require('canvas-sequencer');

The code is also available pre-bundled, via parcel-bundler. You should probably create your own bundle though, so that you have control over browser targets, etc.

const { CanvasSequence, CanvasBlueprint } = require('canvas-sequencer/dist');

Client side, to access the bundled code in a script tag:

<script src="path/to/node_modules/canvas-sequencer/dist/index.js"></script>

CanvasSequence API

Creating a sequence:

const seq = new CanvasSequence();

Defining instructions:

You have access to the standard library of CanvasRenderingContext2D instructions, with the exception of access to the underlying canvas object, for safety reasons. You can access these instructions just as you would with a normal CanvasRenderingContext2D object. Each instruction will be added onto the end of the sequence.

seq.beginPath();
seq.arc(25,25,42, 0, 2 * Math.PI);
seq.fillStyle = 'green';
seq.fill();
seq.lineWidth = 15;
seq.closePath();
seq.stroke();

Transmitting the sequence

The sequencer exposes a toJSON() function, ensuring that with any library which uses JSON methods to bundle data into packets for transmission (such as socket.io) you will not need to do anything fancy for transmission of your sequences. Just send the sequence object as you would any other piece of serializable data.

emitter.emit('new-sequence', seq);

Unpacking the sequence.

The transmitted sequence needs to be revived in order for the CanvasSequence functionality to be available. This can be done by passing the transmitted data object to the constructor:

// Assumes that you have recieve the packaged sequence in a 'data' variable.
const seq = new CanvasSequence(data);

Executing the sequence.

You can execute the sequence on any CanvasRenderingContext2D as such:

const ctx1 = document.querySelector('#canvas1').getContext('2d');
seq.execute(ctx1);

// And again on another context!
const ctx2 = document.querySelector('#canvas2').getContext('2d');
seq.execute(ctx2);

CanvasBlueprint API

Also accessible through this library are sequence 'blueprints'. These allow you to define a sequence once using placeholder tags for values, then build executable sequences using the blueprint and a set of values to take the place of the tags.

How does it work?

The tags you can pass to a blueprint are strings wrapped in curly braces. The string inside the curly braces should be the name of a property on the object with which you intend to build the executable sequence.

Don't worry- if you want to pass the name of such a property into an actual context function, you can still do that. Strings without curly braces are ignored. If you want to pass a string wrapped in curly braces through to a context object, just add an extra set of curly braces.

Here's an example that demonstrates the complete system in action:

const { CanvasBlueprint } = require('canvas-sequencer');
const values = { x: 250, y: 99 };
const bp = new CanvasBlueprint();
const ctx = document.querySelector('#canvas1').getContext('2d');

bp.fillText('y',7,8);
bp.fillText('{{x}}',5,6);
bp.fillRect('{x}','{y}',30,40);

bp.build(values).execute(ctx);

/*
 * The result will be the same as if you had done:
 *
 * ctx.fillText('y',7,8);
 * ctx.fillText('{x}',5,6);
 * ctx.fillRect(250,99,30,40);
 */

// If you later change the x,y values:
values.x = 101;
values.y = 42;

// You can simply rebuild and execute:
bp.build(values).execute(ctx);

/*
 * Now the result will be the same as if you had done:
 *
 * ctx.fillText('y',7,8);
 * ctx.fillText('{x}',5,6);
 * ctx.fillRect(101,42,30,40);
 */

Transmitting and unpacking blueprints

You can transmit and unpack a CanvasBlueprint just as you would with the regular CanvasSequence object:

Transmitting:

emitter.emit('new-blueprint', bp);

Unpacking:

const bp = new CanvasBlueprint(data);

Limitations

The canvas sequences will be executed one at a time, in the correct sequence, but you cannot retrieve values in a useful manner. Therefore any context method which is intended as a getter has been removed and is currently unavailable. If you have a good idea for how to make it possible to remotely access these return values, let me know!

Also be warned that I have not yet fully tested the API with complex arguments, for example Path objects. I suspect the library will need a bit of fine tuning to make sure this can happen.

Changes

  • 3.1.0 Switch from parcel-bunlder to parcel for distribution, add github CI
  • 3.0.6 Fix typo in new instruction support
  • 3.0.5 Slight performance improvement, fixed a buggy test, added support for some newer experimental instructions.
  • 3.0.4 Added badges, fixed up the README a bit.
  • 3.0.3 Fixed a minor bug in the CanvasSequence class, improved test coverage, update dependencies.
  • 3.0.2 Switched to parcel-bundler for the bundle. Simpler to use, more efficient.
  • 3.0.1 Added babelify transform for the bundle.
  • CanvasSequencer was renamed to CanvasSequence.
  • Internal documentation was added.

Future Work

At some point I will get around to testing the API with complex arguments (e.g. Path objects).