我需要创建一个拥有大约30k对象的应用程序,用户可以平移,缩放或“选择单击”任何这些对象。 正在使用Fabric.js Canvas
我使用SVG和svg-pan-zoom插件(没有Canvas Element)做了同样的事情,效果更好
问题:点击时缩放,平移或对象存在显着滞后
尝试过Fabric特定选项
fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.statefullCache = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.needsItsOwnCache = false;
更新 继续更新Fiddle
供参考:
canvas-vs-svg-vs-div Stackoverflow
答案 0 :(得分:4)
虽然不是对更新速度的完全修复,但这个答案将使交互速度加倍。
鼠标和事件与画布(和DOM)交互的一个常见的,几乎是标准的错误是将渲染委托给鼠标/触摸事件。这是非常糟糕的做法,因为鼠标事件以比显示器显示的更高的速率发射。当您排队鼠标事件(伪渲染事件)并为鼠标的每次移动重新渲染时,渲染时间很长会变得更糟
注意阻止代码会停止鼠标事件,但只要引擎处于空闲状态,鼠标就会再次以全速率开始。
使用鼠标事件来获取鼠标状态。使用与显示同步的动画循环仅在需要时渲染并且有时间可用。应该累积记录轮子和鼠标移动增量等内容。
mouse.dx += event.movementX;
mouse.dy += event.movementY;
mouse.wheel += event.wheelDelta;
并在主渲染循环中使用它们......
function update(){
// ... code to use mouse
// consume deltas
mouse.x = mouse.y = mouse.wheel = 0;
...这可确保在渲染更新之间可能有许多鼠标事件时,可以准确地遵循鼠标状态。
在你提供给下面的小提琴中改变你的代码,在我的机器上,它使渲染速度加倍(这仍然非常慢)。
// 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);