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 的改变,内部视图也会随之缩放并居中,让方块都能全部显示出来。

