Search code examples
performancecachingkineticjs

Kinetic-js: How to cache a complete layer as an image


I have a problem an hope to find any solution for it.

I am using Kinetic.js to create a HMI solution with special look-and-feel. Therefor I have created a function that creates 3 layers for a stage: a background layer with a grid, a layer with static shapes for the base layout of the HMI-screen and the third layer for all interactive elements (like buttons, valuedisplays and so on...). Now I want to cache the grid and the static layer to improve performance, because this layers will never change until the whole HMI-screen will change...

As a test I started to code the caching for the grid layer using the following code:

// Create a grid layer if showGrid is set to TRUE...
console.log('Start to create background grid if required');
if (this.actualPageConfig.showGrid) {
    var grid = new Kinetic.Layer();
    for (var x=1; x <= this.cols; x++) {
        var eLoc = LCARSElements.posToRealPos(x, 1, this.cols, this.rows);
        if (x <= this.actualPageConfig.columns) {
            grid.add(new Kinetic.Line({
                points: [eLoc.x, eLoc.y, eLoc.x, eLoc.height],
                stroke: "red",
                strokeWidth: 1,
                lineCap: "round",
                lineJoin: "round" 
            }));
        }
    }
    for (var y=1; y <= this.rows; y++) {
        var eLoc = LCARSElements.posToRealPos(1, y, this.cols, this.rows);
        if (y <= this.actualPageConfig.rows) {
            grid.add(new Kinetic.Line({
                points: [eLoc.x, eLoc.y, eLoc.width, eLoc.y],
                stroke: "red",
                strokeWidth: 1,
                lineCap: "round",
                lineJoin: "round"
            }));
        }
    }

    // Add grid layer to stage
    //this.stage.add(grid);  <-- to be replaced by cache image

    // Convert grid into an image and add this to the stage
    console.log('convert grid to image to increase performance');
    grid.toImage({
        width:      displayManager.stage.getWidth(),
        height:     displayManager.stage.getHeight(),
        callback:   function(img) {
            var cacheGrid = new Kinetic.Image({ 
                image:  img,
                x:      0,
                y:      0,
                width:  displayManager.stage.getWidth(),
                height: displayManager.stage.getHeight()
            });
            console.log('insert grid-image to stage');
            displayManager.stage.add(cacheGrid);
            console.log('redraw stage...');
            displayManager.stage.draw();
        }
    });
}

My problem is, that's not working. The grid is not visible any more and the console log shows the following error information:

Type error: layer.canvas is undefined
layer.canvas.setSize(this.attrs.width, this.attrs.height);      kinetic.js (Zeile 3167)

As I already figured out the error rise when the code "displayManger.stage.add(cacheGrid) will be executed (displayManager is the outside-class where this code snipped reside). Can anyone see where I made the mistake? When I directly add the layer grid anything works fine...

I have created a jsfiddle to demonstrate the problem: jsfiddle

In fiddle you can run both versions by changing one parameter. Hope this helps....

Thanks for help.

Best regards Thorsten


Solution

  • Actually, the problem is simpler than you might think - after caching the layer into an image, you're trying to add an image object directly to the stage (you can't do that).

    To fix the problem, you need to create a new layer, say cahcedLayer, add the image to cachedLayer, and then add cachedLayer to the stage.

    Check out the KineticJS info page to learn more about Node nesting:

    https://github.com/ericdrowell/KineticJS/wiki