Creating An Effect

The effect base class

Effects in Neon are based on the FX class. To create a new effect you need to extend that class.

import { Fx } from 'react-neon';

export default class MyNeonEffect extends Fx {
    // ... override methods
}

A note about Webpack compatibility

By default Webpack doesn't compile code from node_modules, so creating an effect that extends the Fx base class won't work if you don't have that set up. In order to resolve this React Neon includes a babel build of the code that can be used as the basis of your effect in its dist directory. You need to replace the FX import to get the class from the index.babel.js file;

import { Fx } from 'react-neon/dist/index.babel.js'`

More instructions about configuring babel coming soon...

Initialising data

Anything that's passed in to the effect constructor will be merged with the default options. If you need to do more than simply storing the options you can override the constructor but you'll need to remember to call super() before you can use this.

NOTE: Overriding constructor() means your code will only be run when you first initialse the effect. If you want data to be reinitialised when the animation stops and restarts on a resize event use init().

import { Fx } from 'react-neon';

export default class MyNeonEffect extends Fx {
    constructor(options) {
      super(options);
      // ... code to manipulate options
    }
}

An alternative to using the constructor() is the init() method. This is called every time the component resizes, so it can change the position and size of effects. In general it's a better idea to use init() rather than the constructor.

import { Fx } from 'react-neon';

export default class MyNeonEffect extends Fx {
    init() {
      // ... code to generate data
    }
}

Adding a draw call

The actual drawing is achieved with the draw() method. The base class has an empty function so you need to override it.

The canvas context is available as this.ctx, so your code only needs to concentrate on drawing each frame.

import { Fx } from 'react-neon';

export default class MyNeonEffect extends Fx {
    init() {
      // ... code to generate data
    }

    draw() {
      // ... draw something on this.ctx
    }
}

NOTE: It's worthwhile guarding against trying to draw before the canvas is actually available. As ctx is set to null before it's available this can be a simple if statement.

import { Fx } from 'react-neon';

export default class MyNeonEffect extends Fx {
    init() {
      // ... code to generate data
    }

    draw() {
      if (this.ctx!==null) {
        // ... draw something on this.ctx
      }
      this.raf = requestAnimationFrame(this.draw);
    }
}

Here I've also added a new line to call the draw() method again, and put the callback identifier in to this.raf so it can be cancelled in cancel();

For this simple effect example I'll clear the canvas on each frame, and draw a circle on that moves across from left to right.

import { Fx } from 'react-neon';

export default class MyNeonEffect extends Fx {
    init() {
      // A variable to hold the circle position
      this.x = 0;
    }

    draw() {
      // If we have a canvas to draw on...
      if (this.ctx!==null) {
        // Clear the canvas
        this.ctx.clearRect(0, 0, this.bb.width, this.bb.height);

        // Set the fill style to opaque white
        this.ctx.fillStyle = 'hsla(0,100%,100%,1)';

        // Move the x value right (on the canvas) by one 
        this.x += 1;
        
        // If it's on the right edge move back to the left
        if (this.x > this.bb.width) { this.x = 0; }

        // Draw a circle
        this.ctx.beginPath();
        this.ctx.arc(this.x, this.bb.height / 2 - 25, 50, 0, 2 * Math.PI);
        this.ctx.fill();
      }
      // Call the next frame
      this.raf = requestAnimationFrame(this.draw);
    }
}

Putting all this together and using it as an effect to wrap an image giving us a moving circle effect.