1

I am having some serious performance issues with kineticjs as the number of shapes on the canvas increases. I have two functions, one that initializes a path, a text and renders them on a stage. The second function gets called every 5 seconds and it updates any changes on the path and text drawn earlier. Here's a sample snippet of what i am trying,

  /**
  * Function that inits the shapes
  */
  init = function(params) {
  //Create the path object
  var path = new Kinetic.Path({
    data : params.geom,
    fill : params.fill,
    stroke : params.stroke.fill,
    strokeEnabled : false,
    scale : 1
  });
  path.setId(params.id + '.path');
  var simpleText = new Kinetic.Text({
    x : params.x,
    y : params.y + (params.height /2),
    text : params.displayText,
    fontSize : 12,
    fontFamily : params.family,
    fontStyle : params.style,
    fill : params.fill
  });
  simpleText.setId(params.id + '.text');

  var layer = new Kinetic.Layer();
  layer.setId(params.id);
  layer.add(path);
  layer.add(simpleText);
  stage.add(layer);
}

/**
* Update every 5 seconds based on new data
*/
update = function(params) {
  var layer = null;
  if (Kinetic.Global.ids[params.id] != undefined) {
    layer = Kinetic.Global.ids[params.id];
    //Set text
    var textItem = Kinetic.Global.ids[params.id + '.text'];
    textItem.setText(params.displayText);
    //center the text
    textItem.setAttr('x', params.x + (params.width / 2) - (textItem.textWidth / 2));
    textItem.setAttr('y', params.y + (params.height / 2) -            textItem.getAttr('fontSize'));
    // set center style
    textItem.setAlign('center');
    //Set path color
    var pathItem = Kinetic.Global.ids[params.id + '.path'];
    pathItem.setFill(params.fill);
    pathItem.setOpacity(params.alpha);

    layer.clear();
    layer.draw();
  }
}

This code will get sluggish and consume high memory as the number of shapes to draw increases. There is probably many areas in the code above to improve and I am looking for those pointers. Specifically I am not convinced if Id look-up and update is the best way to update an existing shape.

Vik
  • 55
  • 7

1 Answers1

4

Instead of finding objects through the Kinetic.Global.ids object, you can use the layer.get('#someID') function. Not sure if that'll help performance much but it's a start.

Also, I don't think you need to use layer.clear() the layer every time you update, do you? I think layer.draw() should be sufficient for just updating shapes.

A suggestion: perhaps you might only need to use drawScene() every 5 seconds instead of draw() which might help as you don't need to redraw the hit layer every time. See here for the difference between Kinetic draw functions: What is the difference between KineticJS draw methods?

No matter what, it's going to be very expensive to use the draw() method on a layer every 5 seconds, especially when you start to have a lot of shapes in the layer.

Another important question is: Do your objects always change every 5 seconds? What I mean by this is, maybe sometimes you might not need to draw the layer because no updates have occurred. If you can check if an object has been updated or not, you can decide whether the update function needs to be called and if the layer needs to be redrawn.

My last suggestion which builds on the last point mentioned, is maybe you don't need to redraw the layer every time, thus redrawing all objects inside the layer where possibly not all objects in the layer have been updated (and need redrawing). Maybe only some of the objects have been updated. In this case, if you use Kinetic.Group to group each text/path together, you can use group.draw() instead of layer.draw(). Now if you can find which groups have updated data every 5 seconds, you only have to draw the Kinetic.Group instead of the entire layer every 5 seconds.

By the way you can also use the .get() function like this:

var layers = stage.get('Layer'); // Returns an array of all Kinetic.Layers inside stage
var groups = layers[0].get('Group'); // Returns an array of all Kinetic.Groups inside the first layer (in the layers array)

See here for more info on the get method: http://kineticjs.com/docs/Kinetic.Container.html#get

Community
  • 1
  • 1
projeqht
  • 3,160
  • 3
  • 18
  • 32
  • 1
    These are great points and I have implemented a few thank you! However the change that improved the performance significantly was using just a single layer instead of a layer for each of my graphic item (which included a path and a text). My requirement is to support about 1000 graphic items each having a path and a text and this seems to work ok now. However, if the requirement changes to support more I believe I might need more than a single layer. – Vik Sep 12 '13 at 18:38
  • Yes, definitely! You don't want to have a layer for each item (not sure if that was apparent in your code above) as that will be a huge performance hit. Just think, **each layer adds 2 canvases** to the DOM, one to render the nodes and one to use as a hit canvas. Instead, if you need to group your nodes together, use [Kinetic.Group](http://kineticjs.com/docs/Kinetic.Group.html) See this link for more: http://stackoverflow.com/questions/17632068/what-are-the-differences-between-group-and-layer-in-kineticjs – projeqht Sep 12 '13 at 18:53
  • Thanks, groups are now in place and performance is far better. – Vik Sep 12 '13 at 23:00