使用其对象调整 canvas 大小的最佳方法
The best way to resize canvas with its objects
我有一个 Fabric.js canvas 里面有一个带有 boostrap 的响应式设计。
要调整 canvas 的大小,我使用 canvas.setDimensions({width:w, height:h});
来自当前window的宽度和高度的clientWidth和clientHeight。这是我的 canvas 和他的容器 :
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'></canvas>
</div>
调整 canvas 大小时,对于 canvas 中的每个对象,我会按比例更改它们的大小和位置。我使用原始和新的 canvas 大小计算了一个应用于每个对象 top/left/width/height 的系数。每次调整 canvas 大小时运行此代码:
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-container')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
canvas.calcOffset();
canvas.forEachObject(function(o) {
o.setCoords();
});
if (canvas.width != containerWidth) {
var scaleMultiplier = newWidth / canvas.width;
var objects = canvas.getObjects();
var factorX = newWidth / canvas.getWidth();
var factorY = newWidth / canvas.getHeight();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX *factorX;
objects[i].scaleY = objects[i].scaleY *factorX;
objects[i].left = factorX * objects[i].left;
objects[i].top = factorX * objects[i].top ;
objects[i].setCoords();
};
canvas.setWidth(canvas.getWidth() * factorX);
canvas.setHeight(canvas.getHeight() * factorY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
调整大小效果很好,所有对象都正确地改变了它们的尺寸。
问题是在 canvas 调整大小后无法选择大多数对象。
此外,单击 canvas 的空白区域有时会选择对象...
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({width: 1000, height: 1000});
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-container')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
canvas.calcOffset();
canvas.forEachObject(function(o) {
o.setCoords();
});
if (canvas.width != containerWidth) {
var containerWidth_ = $(outerCanvasContainer).width();
var scaleMultiplier = containerWidth_ / canvas.width;
var objects = canvas.getObjects();
var factorX = containerWidth_ / canvas.getWidth();
var factorY = containerWidth_ / canvas.getHeight();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX *factorX;
objects[i].scaleY = objects[i].scaleY *factorX;
objects[i].left = factorX * objects[i].left + 15;
objects[i].top = factorX * objects[i].top + 10;
objects[i].setCoords();
};
canvas.setWidth(canvas.getWidth() * factorX);
canvas.setHeight(canvas.getHeight() * factorY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body { background-color:#000 }
#canvas{border: 1px solid #666}
.upper-canvas {max-width: 1000px;max-height: 1000px;}
.container{margin:0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>
正如您在代码片段中看到的,当页面加载时,您可以随意修改文本,但如果您单击“整页”,您将无法再这样做,或者变得很难做到。
这里有一个解释问题的视频:https://a.uguu.se/pgOYGfJy.webm
我在互联网上做了很多研究并尝试了很多东西,我想知道 是否有人知道在保持正确值的同时进行响应式设计的最佳方法canvas objects 为了避免这个问题的发生。
谢谢
很抱歉告诉你这个消息,但你的努力可能是多余的。 :(
似乎 setDimensions
方法的 backstoreOnly
和 cssOnly
选项为我们完成了所有工作。
我大大简化了您的代码,它似乎与您的代码完全一样。 “完全”是指这两个代码都受到同一个问题的影响。
问题似乎不是你(或我)的代码引起的,似乎是织物本身引起的;当 canvas 高于视口时,问题似乎就显现出来了。
如果我们展开片段,我们可以看到它们都工作正常,直到 canvas 的高度小于视口的高度。
查看实际问题:
- 展开代码段
- 调整大小使 canvas 高于视口
- 垂直拖动文本
我在网上搜索了一段时间,没有找到相关内容。
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({ width: 1000, height: 1000 }, { backstoreOnly: true });
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
top: 50,
left: 50,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
// function to resize canvas and its objects
function resizeCanvas() {
const { clientWidth } = $('.canvas-container')[0];
const { innerHeight } = window; // viewport height
const side = Math.min(clientWidth, innerHeight, 1000) + "px";
canvas.setDimensions({ width: side, height: side }, { cssOnly: true });
}
$(window).resize(resizeCanvas);
body {
background-color: #000
}
#canvas {
border: 1px solid #666
}
.upper-canvas {
max-width: 1000px;
max-height: 1000px;
}
.container {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>
两件事:
- Fabric.js 自动添加
.canvas-container
包装器。你不
必须提供它。您的代码最终创建了两个
.canvas-container
个元素。那打乱了布局。
- 您可以直接使用
window.innerHeight
,而不是在父容器上设置宽度 100% 并从中读取它。
假设您希望 canvas 适合视口,您可以试试这个:
// Create a new instance of Canvas
var canvas = new fabric.Canvas('canvas');
let width = window.innerWidth <= 1000 ? window.innerWidth : 1000;
let height = window.innerHeight <= 1000 ? window.innerHeight : 1000;
canvas.setDimensions({width, height});
// do initial resizing after we add the text
setTimeout(resizeCanvas);
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 60,
borderColor: '#000',
cornerColor: '#000',
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const newWidth = window.innerWidth <= 1000 ? window.innerWidth : 1000;
const newHeight = window.innerHeight <= 1000 ? window.innerHeight : 1000;
if (canvas.width != newWidth || canvas.height != newHeight) {
const scaleX = newWidth / canvas.width;
const scaleY = newHeight / canvas.height;
var objects = canvas.getObjects();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX * scaleX;
objects[i].scaleY = objects[i].scaleY * scaleY;
objects[i].left = objects[i].left * scaleX;
objects[i].top = objects[i].top * scaleY;
objects[i].setCoords();
}
var obj = canvas.backgroundImage;
if (obj) {
obj.scaleX = obj.scaleX * scaleX;
obj.scaleY = obj.scaleY * scaleY;
}
canvas.discardActiveObject();
canvas.setWidth(canvas.getWidth() * scaleX);
canvas.setHeight(canvas.getHeight() * scaleY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body {
background-color: #000 !important;
}
#canvas {
border: 1px solid #666;
}
.container {
margin: 0;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<canvas id="canvas" class="img-fluid">
<p
>This is fallback content for users of assistive technologies or of browsers that
don't have full support for the Canvas API.</p
>
</canvas>
</div>
</div>
</div>
如果你想要正方形 canvas 则不要使用 window.innerHeight
或在上面的代码中将 window.innerHeight
替换为 window.innerWidth
。
如果您希望 canvas 适合整个 window,而不删除父元素,则添加以下 CSS 规则:
.canvas-container {
position: fixed !important;
top: 0;
left: 0;
}
正方形 canvas 对象将按比例缩放。
// Create a new instance of Canvas
var canvas = new fabric.Canvas('canvas');
let width = 1000;
let height = 1000;
canvas.setDimensions({width, height});
// do initial resizing after we add the text
setTimeout(resizeCanvas);
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 60,
borderColor: '#000',
cornerColor: '#000',
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const newWidth = window.innerWidth <= 1000 ? window.innerWidth : 1000;
if (canvas.width != newWidth) {
const scaleX = newWidth / canvas.width;
var objects = canvas.getObjects();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX * scaleX;
objects[i].scaleY = objects[i].scaleY * scaleX;
objects[i].left = objects[i].left * scaleX;
objects[i].top = objects[i].top * scaleX;
objects[i].setCoords();
}
var obj = canvas.backgroundImage;
if (obj) {
obj.scaleX = obj.scaleX * scaleX;
obj.scaleY = obj.scaleY * scaleX;
}
canvas.discardActiveObject();
canvas.setWidth(canvas.getWidth() * scaleX);
canvas.setHeight(canvas.getHeight() * scaleX);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body {
background-color: #000 !important;
}
#canvas {
border: 1px solid #666;
}
.container {
margin: 0;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<canvas id="canvas" class="img-fluid">
<p
>This is fallback content for users of assistive technologies or of browsers that
don't have full support for the Canvas API.</p
>
</canvas>
</div>
</div>
</div>
更大 canvas: 大小不是问题。查看全页。
// Create a new instance of Canvas
var canvas = new fabric.Canvas('canvas');
let width = 2000;
let height = 2000;
canvas.setDimensions({width, height});
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000',
});
// Render the Text on Canvas
canvas.add(text);
canvas.setActiveObject(text);
#canvas {
border: 1px solid #666;
}
.container {
margin: 0;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
<canvas id="canvas" class="img-fluid">
<p
>This is fallback content for users of assistive technologies or of browsers that
don't have full support for the Canvas API.</p
>
</canvas>
我删除了调整大小函数中的额外代码并将最大 containerWidth 值限制为 1000,并且我更改了 canvas 包装器 div 的 class 名称以避免与 Fabric.js代码。
@Daniele Ricci:感谢您向我展示调整大小时超过 1000 像素时的 canvas 错误。关于您的解决方案:执行代码段时,canvas 不占用 540px 的全宽(我应该在评论中指定它,但我说的是 boostrap 的响应规则)。它是 200 像素,您无法获得最小 window 尺寸的对象控制按钮。
@the Hutt:谢谢你告诉我 Fabric.js 本身用 canvas-container class 创建了一个 div,我没有注意它。关于您的解决方案:问题是当 canvas 为整页时,文本无法适应正确的大小(尤其是在这个高度上)。
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({width: 1000, height: 1000});
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-wrapper')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = ($(outerCanvasContainer).width() > 1000 ? 1000 : outerCanvasContainer.clientWidth);
console.clear(); console.log(containerWidth);
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
}
$(window).resize(resizeCanvas);
body { background-color:#000 }
#canvas{border: 1px solid #666}
.upper-canvas {max-width: 1000px;max-height: 1000px;}
.container{margin:0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-wrapper">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>
我有一个 Fabric.js canvas 里面有一个带有 boostrap 的响应式设计。 要调整 canvas 的大小,我使用 canvas.setDimensions({width:w, height:h}); 来自当前window的宽度和高度的clientWidth和clientHeight。这是我的 canvas 和他的容器 :
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'></canvas>
</div>
调整 canvas 大小时,对于 canvas 中的每个对象,我会按比例更改它们的大小和位置。我使用原始和新的 canvas 大小计算了一个应用于每个对象 top/left/width/height 的系数。每次调整 canvas 大小时运行此代码:
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-container')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
canvas.calcOffset();
canvas.forEachObject(function(o) {
o.setCoords();
});
if (canvas.width != containerWidth) {
var scaleMultiplier = newWidth / canvas.width;
var objects = canvas.getObjects();
var factorX = newWidth / canvas.getWidth();
var factorY = newWidth / canvas.getHeight();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX *factorX;
objects[i].scaleY = objects[i].scaleY *factorX;
objects[i].left = factorX * objects[i].left;
objects[i].top = factorX * objects[i].top ;
objects[i].setCoords();
};
canvas.setWidth(canvas.getWidth() * factorX);
canvas.setHeight(canvas.getHeight() * factorY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
调整大小效果很好,所有对象都正确地改变了它们的尺寸。 问题是在 canvas 调整大小后无法选择大多数对象。 此外,单击 canvas 的空白区域有时会选择对象...
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({width: 1000, height: 1000});
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-container')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = outerCanvasContainer.clientWidth;
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
canvas.calcOffset();
canvas.forEachObject(function(o) {
o.setCoords();
});
if (canvas.width != containerWidth) {
var containerWidth_ = $(outerCanvasContainer).width();
var scaleMultiplier = containerWidth_ / canvas.width;
var objects = canvas.getObjects();
var factorX = containerWidth_ / canvas.getWidth();
var factorY = containerWidth_ / canvas.getHeight();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX *factorX;
objects[i].scaleY = objects[i].scaleY *factorX;
objects[i].left = factorX * objects[i].left + 15;
objects[i].top = factorX * objects[i].top + 10;
objects[i].setCoords();
};
canvas.setWidth(canvas.getWidth() * factorX);
canvas.setHeight(canvas.getHeight() * factorY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body { background-color:#000 }
#canvas{border: 1px solid #666}
.upper-canvas {max-width: 1000px;max-height: 1000px;}
.container{margin:0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>
正如您在代码片段中看到的,当页面加载时,您可以随意修改文本,但如果您单击“整页”,您将无法再这样做,或者变得很难做到。
这里有一个解释问题的视频:https://a.uguu.se/pgOYGfJy.webm
我在互联网上做了很多研究并尝试了很多东西,我想知道 是否有人知道在保持正确值的同时进行响应式设计的最佳方法canvas objects 为了避免这个问题的发生。
谢谢
很抱歉告诉你这个消息,但你的努力可能是多余的。 :(
似乎 setDimensions
方法的 backstoreOnly
和 cssOnly
选项为我们完成了所有工作。
我大大简化了您的代码,它似乎与您的代码完全一样。 “完全”是指这两个代码都受到同一个问题的影响。
问题似乎不是你(或我)的代码引起的,似乎是织物本身引起的;当 canvas 高于视口时,问题似乎就显现出来了。
如果我们展开片段,我们可以看到它们都工作正常,直到 canvas 的高度小于视口的高度。
查看实际问题:
- 展开代码段
- 调整大小使 canvas 高于视口
- 垂直拖动文本
我在网上搜索了一段时间,没有找到相关内容。
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({ width: 1000, height: 1000 }, { backstoreOnly: true });
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
top: 50,
left: 50,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
// function to resize canvas and its objects
function resizeCanvas() {
const { clientWidth } = $('.canvas-container')[0];
const { innerHeight } = window; // viewport height
const side = Math.min(clientWidth, innerHeight, 1000) + "px";
canvas.setDimensions({ width: side, height: side }, { cssOnly: true });
}
$(window).resize(resizeCanvas);
body {
background-color: #000
}
#canvas {
border: 1px solid #666
}
.upper-canvas {
max-width: 1000px;
max-height: 1000px;
}
.container {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-container">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>
两件事:
- Fabric.js 自动添加
.canvas-container
包装器。你不 必须提供它。您的代码最终创建了两个.canvas-container
个元素。那打乱了布局。 - 您可以直接使用
window.innerHeight
,而不是在父容器上设置宽度 100% 并从中读取它。
假设您希望 canvas 适合视口,您可以试试这个:
// Create a new instance of Canvas
var canvas = new fabric.Canvas('canvas');
let width = window.innerWidth <= 1000 ? window.innerWidth : 1000;
let height = window.innerHeight <= 1000 ? window.innerHeight : 1000;
canvas.setDimensions({width, height});
// do initial resizing after we add the text
setTimeout(resizeCanvas);
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 60,
borderColor: '#000',
cornerColor: '#000',
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const newWidth = window.innerWidth <= 1000 ? window.innerWidth : 1000;
const newHeight = window.innerHeight <= 1000 ? window.innerHeight : 1000;
if (canvas.width != newWidth || canvas.height != newHeight) {
const scaleX = newWidth / canvas.width;
const scaleY = newHeight / canvas.height;
var objects = canvas.getObjects();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX * scaleX;
objects[i].scaleY = objects[i].scaleY * scaleY;
objects[i].left = objects[i].left * scaleX;
objects[i].top = objects[i].top * scaleY;
objects[i].setCoords();
}
var obj = canvas.backgroundImage;
if (obj) {
obj.scaleX = obj.scaleX * scaleX;
obj.scaleY = obj.scaleY * scaleY;
}
canvas.discardActiveObject();
canvas.setWidth(canvas.getWidth() * scaleX);
canvas.setHeight(canvas.getHeight() * scaleY);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body {
background-color: #000 !important;
}
#canvas {
border: 1px solid #666;
}
.container {
margin: 0;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<canvas id="canvas" class="img-fluid">
<p
>This is fallback content for users of assistive technologies or of browsers that
don't have full support for the Canvas API.</p
>
</canvas>
</div>
</div>
</div>
如果你想要正方形 canvas 则不要使用 window.innerHeight
或在上面的代码中将 window.innerHeight
替换为 window.innerWidth
。
如果您希望 canvas 适合整个 window,而不删除父元素,则添加以下 CSS 规则:
.canvas-container {
position: fixed !important;
top: 0;
left: 0;
}
正方形 canvas 对象将按比例缩放。
// Create a new instance of Canvas
var canvas = new fabric.Canvas('canvas');
let width = 1000;
let height = 1000;
canvas.setDimensions({width, height});
// do initial resizing after we add the text
setTimeout(resizeCanvas);
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 60,
borderColor: '#000',
cornerColor: '#000',
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const newWidth = window.innerWidth <= 1000 ? window.innerWidth : 1000;
if (canvas.width != newWidth) {
const scaleX = newWidth / canvas.width;
var objects = canvas.getObjects();
for (var i in objects) {
objects[i].scaleX = objects[i].scaleX * scaleX;
objects[i].scaleY = objects[i].scaleY * scaleX;
objects[i].left = objects[i].left * scaleX;
objects[i].top = objects[i].top * scaleX;
objects[i].setCoords();
}
var obj = canvas.backgroundImage;
if (obj) {
obj.scaleX = obj.scaleX * scaleX;
obj.scaleY = obj.scaleY * scaleX;
}
canvas.discardActiveObject();
canvas.setWidth(canvas.getWidth() * scaleX);
canvas.setHeight(canvas.getHeight() * scaleX);
canvas.renderAll();
canvas.calcOffset();
}
}
$(window).resize(resizeCanvas);
body {
background-color: #000 !important;
}
#canvas {
border: 1px solid #666;
}
.container {
margin: 0;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<canvas id="canvas" class="img-fluid">
<p
>This is fallback content for users of assistive technologies or of browsers that
don't have full support for the Canvas API.</p
>
</canvas>
</div>
</div>
</div>
更大 canvas: 大小不是问题。查看全页。
// Create a new instance of Canvas
var canvas = new fabric.Canvas('canvas');
let width = 2000;
let height = 2000;
canvas.setDimensions({width, height});
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000',
});
// Render the Text on Canvas
canvas.add(text);
canvas.setActiveObject(text);
#canvas {
border: 1px solid #666;
}
.container {
margin: 0;
background-color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" />
<canvas id="canvas" class="img-fluid">
<p
>This is fallback content for users of assistive technologies or of browsers that
don't have full support for the Canvas API.</p
>
</canvas>
我删除了调整大小函数中的额外代码并将最大 containerWidth 值限制为 1000,并且我更改了 canvas 包装器 div 的 class 名称以避免与 Fabric.js代码。
@Daniele Ricci:感谢您向我展示调整大小时超过 1000 像素时的 canvas 错误。关于您的解决方案:执行代码段时,canvas 不占用 540px 的全宽(我应该在评论中指定它,但我说的是 boostrap 的响应规则)。它是 200 像素,您无法获得最小 window 尺寸的对象控制按钮。
@the Hutt:谢谢你告诉我 Fabric.js 本身用 canvas-container class 创建了一个 div,我没有注意它。关于您的解决方案:问题是当 canvas 为整页时,文本无法适应正确的大小(尤其是在这个高度上)。
// Create a new instance of Canvas
var canvas = new fabric.Canvas("canvas");
canvas.setDimensions({width: 1000, height: 1000});
resizeCanvas();
// Create a new Text instance
var text = new fabric.Text('Texte', {
fill: '#000',
fontSize: 100,
borderColor: '#000',
cornerColor: '#000'
});
// Render the Text on Canvas
canvas.add(text);
canvas.centerObject(text);
canvas.setActiveObject(text);
// function to resize canvas and its objects
function resizeCanvas() {
const outerCanvasContainer = $('.canvas-wrapper')[0];
const ratio = canvas.getWidth() / canvas.getHeight();
const containerWidth = ($(outerCanvasContainer).width() > 1000 ? 1000 : outerCanvasContainer.clientWidth);
console.clear(); console.log(containerWidth);
const containerHeight = outerCanvasContainer.clientHeight;
const scale = containerWidth / canvas.getWidth();
const zoom = canvas.getZoom() * scale;
canvas.setDimensions({width: containerWidth, height: containerWidth / ratio});
canvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);
}
$(window).resize(resizeCanvas);
body { background-color:#000 }
#canvas{border: 1px solid #666}
.upper-canvas {max-width: 1000px;max-height: 1000px;}
.container{margin:0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/521/fabric.min.js"></script>
<script src="https://raw.githubusercontent.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<div class="container mx-auto">
<div class="col-12">
<div class="row">
<div style="width: 100%;" class="canvas-wrapper">
<canvas id="canvas" class='img-fluid'>
<p>This is fallback content for users of assistive technologies or of browsers that don't have full support for the Canvas API.</p>
</canvas>
</div>
</div>
</div>
</div>