I need make an App that has about 30k Objects, a user can Pan, Zoom or "Select on click" any of those objects. Fabric.js Canvas is being used
I have done the same using SVG's and the svg-pan-zoom plugin (no Canvas Element) with better results
Problem: there is a significant Lag while Zooming, Panning or Object on Click
Have tried Fabric specific options
fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.statefullCache = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.needsItsOwnCache = false;
UPDATE Heres the updated Fiddle
for reference :
canvas-vs-svg-vs-div Stackoverflow
Stackoverflow
Though not a complete fix to the update speed this answer will about double the interaction speed.
A common, almost standard, mistake made with mouse and event interaction with the canvas (and DOM) is to delegate rendering to mouse/touch events. This is very bad practice as mouse events fire at much higher rates than the display can display. It becomes worse when your rendering time is high as you queue up mouse events (pseudo render events) and do a re render for every movement of the mouse
Note blocking code will stop mouse events but as soon as the engine is idle the mouse will start firing at full rate again.
Use the mouse events just to get the mouse state. Use an animation loop that is synced to the display to render only when needed and there is time available. Things like the wheel and mouse movement deltas should be recorded cumulatively.
mouse.dx += event.movementX;
mouse.dy += event.movementY;
mouse.wheel += event.wheelDelta;
And consume them in the main render loop...
function update(){
// ... code to use mouse
// consume deltas
mouse.x = mouse.y = mouse.wheel = 0;
...this ensures that the mouse state is accurately followed when you may have many mouse events between render updates.
Change you code in the fiddle you provided to the following, on my machine it about doubled the rendering speed (which is still very slow).
// from just after the function applyZoom replace all the code
var mouse = { // holds the mouse state
x : 0,
y : 0,
down : false,
w : 0,
delta : new fabric.Point(0,0),
}
// event just track mouse state
function zoom(e) {
if(e != null) { e.preventDefault() }
var evt=window.event || e;
mouse.x = e.offsetX;
mouse.y = e.offsetY;
mouse.w += evt.detail? evt.detail*(-120) : evt.wheelDelta;
return false;
}
canvas.on('mouse:up', function (e) { mouse.down = false });
canvas.on('mouse:out', function (e) { mouse.down = false });
canvas.on('mouse:down', function (e) { mouse.down = true });
canvas.on('mouse:move', function(e) {
if (e && e.e) {
mouse.delta.x += e.e.movementX;
mouse.delta.y += e.e.movementY;
}
});
// main animation loop
function update(){
if(mouse.w !== 0){ // if the wheel has moved do zoom
var curZoom = canvas.getZoom();
canvas.zoomToPoint(
{ x : mouse.x, y: mouse.y },
canvas.getZoom() + mouse.w / 4000
);
mouse.w = 0; // consume wheel delta
}else if(mouse.down) { // if mouse button down
canvas.relativePan(mouse.delta);
}
// consume mouse delta
mouse.delta.x = 0;
mouse.delta.y = 0;
requestAnimationFrame(update);
}
requestAnimationFrame(update);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With