views:

319

answers:

4

Hi

Using the Canvas element, I draw a line from one element to another element Another element is draggable, and when dragging the element the line follows the draggable element.

My problem is that the rendering apears slow (Fx 3.5 on a Mac PowerBook) I think I have seen much better performance in Canvas before

Anyone with Canvas experience who can give some performance tips?

Thanks in advance

The following method is called on the on drag event,

// Runs when the element is dragged.
function onDrag(key)
{
  var ctx = canvas.context;
  var fromRect = $('#box-' + key).offset();
  var fromHeight = $('#box-' + key).height();
  var fromWidth = $('#box-' + key).height();

  var toRect = $('#draggable').offset();
  var toWidth = $('#draggable').width();

  var startX = toRect.left + toWidth / 2;
  var startY = toRect.top + 4;
  var endX = fromRect.left + fromWidth / 2;
  var endY = fromRect.top + fromHeight / 2;

  ctx.clearRect(0, 0, 5000, 5000);
  ctx.beginPath();
  ctx.moveTo(startX, startY);
  ctx.lineTo(endX, endY);
  ctx.strokeStyle = "rgba(0, 0, 0,1)";
  ctx.stroke();

}

Thanks for tips,

best regards Eric

+1  A: 

I would be willing to bet that the jQuery function calls are taking longer than the drawing. If your application allows you to compute offset and dimensions easily without using jQuery, you might be able to extract some additional speed there.

nullptr
+1  A: 

Where possible, cache jQuery selections:

var onDrag = (function(){

    var draggable = $('#draggable'),
        ctx = canvas.context; // btw, don't you mean canvas.getContext('2d')?

    return function(key) {

        var box = $('#box-' + key),
            fromRect = box.offset(),
            fromHeight = box.height(),
            fromWidth = box.height(),
            toRect = draggable.offset(),
            toWidth = draggable.width(),
            startX = toRect.left + toWidth / 2,
            startY = toRect.top + 4,
            endX = fromRect.left + fromWidth / 2,
            endY = fromRect.top + fromHeight / 2;

        ctx.clearRect(0, 0, 5000, 5000);
        ctx.beginPath();
        ctx.moveTo(startX, startY);
        ctx.lineTo(endX, endY);
        ctx.strokeStyle = "rgba(0, 0, 0,1)";
        ctx.stroke();

    };

})();


General rule: If you have a function that will be run multiple times in quick succession then make sure you're only doing what ABSOLUTELY HAS TO BE DONE on each call of the function.

J-P
+1  A: 

In case locating the elements by their ids and reading their dimensions is the bottleneck, you can try memoizing your function:

function onDrag(key) {
    var cached = onDrag.cache[key];

    if (!cached) {
        cached = {
            fromRect = $('#box-' + key).offset();
            // etc.
        };

        onDrag.cache[key] = cached;
    }

    var toRect = $('#draggable').offset();
    // etc.
}

onDrag.cache = {};

This might give you some performance gain.

Also, can you try taking out the clearRect() to see if it makes a big difference? You may want to store the location of the previous drag and just retrace the previous line to erase it instead of painting 5000 x 5000 = 25 million pixels. Just a hunch, as filling 25M pixels may or may not be an issue based on the canvas implementation.

Ates Goral
A: 

I really think you should closePath() at the end

Fabien Ménager