Fabric.js - 画布视图viewport的自适应(内容自动缩放并居中)
在 Fabric.js 开发时,可能会遇到要显示的完整视图尺寸超过了 canvas 大小的情况。比如下面样例,我们生成 20 个方块,每个方块的位置都是随机的。由于 canvas 大小固定,可能就会造成有些方块落在显示区域外,看不到。


碰到这种情况,一方面我们要提供个画布拖拽和缩放的功能,具体可以参考我之前的文章:Fabric.js - 实现鼠标拖动画布、滚轮缩放画布的功能。另一方面最好让整个视图一开始就自动缩放,让 canvas 刚好能显示下全部的内容。
一、让视图自动缩放以适应 Canvas(Canvas 固定大小)
1,实现原理
- 首先我们遍历所有的对象,获取所有对象左上角坐标的最小值,以及所有对象右下角坐标的最大值。
- 接着根据上面的值以及 Canvas 的宽高,计算出缩放比例以及平移的距离,并对 Canvas 的视图(Viewport)进行平移和缩放操作。
2,样例代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="fabric.js"></script> <script src="jquery-3.1.1.js"></script> <script> var canvas; $(function() { canvas = new fabric.Canvas('canvas',{backgroundColor: '#D6F8FF'}); //创建随机的方块 for(var i=0; i<20; i++){ var left = (Math.random() - 0.5) * 600; var top = (Math.random() - 0.5) * 600; var rect = new fabric.Rect({top: top, left: left, width: 70, height: 70, fill: 'orange'}); canvas.add(rect); } //缩放移动视图,使其适应Canvas大小 zoomToFitCanvas(); }); //缩放移动视图,使其适应Canvas大小 function zoomToFitCanvas() { //遍历所有对对象,获取最小坐标,最大坐标 var objects = canvas.getObjects(); if(objects.length > 0 ){ var rect = objects[0].getBoundingRect(); var minX = rect.left; var minY = rect.top; var maxX = rect.left + rect.width; var maxY = rect.top + rect.height; for(var i = 1; i<objects.length; i++){ rect = objects[i].getBoundingRect(); minX = Math.min(minX, rect.left); minY= Math.min(minY, rect.top); maxX = Math.max(maxX, rect.left + rect.width); maxY= Math.max(maxY, rect.top + rect.height); } } //计算平移坐标 var panX = (maxX - minX - canvas.width)/2 + minX; var panY = (maxY - minY - canvas.height)/2 + minY; //开始平移 canvas.absolutePan({x:panX, y:panY}); //计算缩放比例 var zoom = Math.min(canvas.width/(maxX - minX), canvas.height/(maxY - minY)); //计算缩放中心 var zoomPoint = new fabric.Point(canvas.width / 2 , canvas.height / 2); //开始缩放 canvas.zoomToPoint(zoomPoint, zoom); } </script> </head> <body> <canvas id="canvas" width="400" height="250"></canvas> </body> </html>
3,效果图
可以看到 20 个方块完全显示出来,而且这些内容在画布里居中显示。

二、让视图自动缩放以适应屏幕(Canvas 也自适应屏幕大小)
1,实现原理
- 我们通过监听浏览器窗口的 resize 事件,动态改变 Canvas 的尺寸,从而让 Canvas 大小随着浏览器的大小改变而改变。
- 而 Canvas 尺寸改变后,其内部视图自动缩放的实现原理同上面是一样的。
2,样例代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style> * { margin: 0; padding: 0; } html, body { height: 100%; width: 100%; } canvas { display: block; } </style> <script src="fabric.js"></script> <script src="jquery-3.1.1.js"></script> <script> var canvas; var timer; $(function() { canvas = new fabric.Canvas('canvas',{backgroundColor: '#D6F8FF'}); //创建随机的方块 for(var i=0; i<20; i++){ var left = (Math.random() - 0.5) * 600; var top = (Math.random() - 0.5) * 600; var rect = new fabric.Rect({top: top, left: left, width: 70, height: 70, fill: 'orange'}); canvas.add(rect); } //添加窗口尺寸改变响应监听 $(window).resize(resizeCanvas); //页面加载后先设置一下canvas大小 resizeCanvas(); }); //窗口尺寸改变响应(修改canvas大小) function resizeCanvas() { canvas.setWidth($(window).get(0).innerWidth); canvas.setHeight($(window).get(0).innerHeight); //缩放移动视图,使其适应Canvas大小 zoomToFitCanvas(); }; //缩放移动视图,使其适应Canvas大小 function zoomToFitCanvas() { //先还原缩放比例与位置 canvas.setZoom(1); canvas.absolutePan({x:0, y:0}); //遍历所有对对象,获取最小坐标,最大坐标 var objects = canvas.getObjects(); if(objects.length > 0 ){ var rect = objects[0].getBoundingRect(); var minX = rect.left; var minY = rect.top; var maxX = rect.left + rect.width; var maxY = rect.top + rect.height; for(var i = 1; i<objects.length; i++){ rect = objects[i].getBoundingRect(); minX = Math.min(minX, rect.left); minY= Math.min(minY, rect.top); maxX = Math.max(maxX, rect.left + rect.width); maxY= Math.max(maxY, rect.top + rect.height); } } //计算平移坐标 var panX = (maxX - minX - canvas.width)/2 + minX; var panY = (maxY - minY - canvas.height)/2 + minY; //开始平移 canvas.absolutePan({x:panX, y:panY}); //计算缩放比例 var zoom = Math.min(canvas.width/(maxX - minX), canvas.height/(maxY - minY)); //计算缩放中心 var zoomPoint = new fabric.Point(canvas.width / 2 , canvas.height / 2); //开始缩放 canvas.zoomToPoint(zoomPoint, zoom); } </script> </head> <body> <canvas id="canvas" width="400" height="250"></canvas> </body> </html>
3,效果图
- 不管我们如何改变浏览器大小,Canvas 始终占满整个屏幕。
- 同时随着 Canvas 的改变,内部视图也会随之缩放并居中,让方块都能全部显示出来。
