6
\$\begingroup\$

I have created a jump'n'run browser-game based on SVG. The »World« grew large (~80px * ~20000px, before scaled to viewport height) and rendering went slow. In consequence I included a range searching algorithm to exclude elements from the render tree, if they are out of the visible area. To get all elements inside the viewport, I am using a range query on a AVL-Tree.

Basically the approach was very effective and increased the performance up to 40%, unfortunately it also results in flickering of the graphic if the player is in motion.

The initialization looks like this:

//for each element of type: path, rect, polygon, line, circle, polyline,use,text or tspan

var box = bbox.call(this, element, mtr),
  data = {
    style:    element.style,
    x1:       box[0].x,
    x2:       box[1].x,
    visible:  false
  }
this.tree.insert(box[0].x, data);
this.tree.insert(box[1].x, data);
element.style.display = 'none';

whereby bbox() creates gets the bounding box in global coordinates.

Each time at rendering the following is done:

var x1      = this.viewBox.x - 1, 
    x2      = this.viewBox.x + this.viewBox.width + 1,
    result  = this.tree.query(x1, x2),
    visible = this.visible,
    i       = 0, 
    n       = result.length, 
    data;

for (; i < n; i++) {
  data = result[i];
  if (!data.visible) {
    data.style.display = 'block'
    data.visible = true;
  }
}

for (i = 0, n = visible.length; i < n; i++) {
  data = visible[i];
  if (data.x1 > x2 || data.x2 < x1) {
    data.style.display = 'none';
    data.visible = false;
  } 
}

this.visible = result;

As mentioned above, the framerate increased between 20% and 40% on each platform, but flickering and kind of sloppy rendering began.

What could I do to gain a more fluent rendering?

\$\endgroup\$
  • \$\begingroup\$ You're missing a var in your first for loop. How often are you rendering and why would you render the background multiple times? Render the background once and then positioning it on the screen so that the browser or parent element clips the view, then you can move it around with simple javascript. Now the only things you need to re-draw are things in front of the background and if they're not animated then you only need to draw those once and move them around with javascript too. \$\endgroup\$ – Jade Aug 27 '15 at 22:00
1
\$\begingroup\$

There are several performance issues with the code sample you supplied.

Consider using pop to increase performance

for (; i < n; i++) {
  data = result[i];

vs

while((data = result.pop()) != null) {...

If it can't be destructive which I think looking at your code it can be then you can clone using

var clone = myArray.slice(0);

Performance is between 260% and 15000% (Jsperf is no longer up to show you sorry)

Dereference variables before loops, each reference adds around 7ms per reference in the chain on my 4.6GHZ i7.
if (!data.visible) { data.style.display = 'block' data.visible = true; } }

Again dereference, the visible.length is referenced every run

for (i = 0, n = visible.length; i < n; i++) {
  data = visible[i];
  if (data.x1 > x2 || data.x2 < x1) {
    data.style.display = 'none';
    data.visible = false;
  } 
}

Also use

requestAnimationFrame(delegate);

Request animation frame explained

When drawing to prevent DOM redraws.

[Source] : I'm an internationally renowned code analysis expert who studies code performance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.