用对象调整帆布大小的最佳方法

发布于 2025-01-20 09:54:48 字数 5654 浏览 1 评论 0原文

我在带Boostrap的响应设计中有一个织物。 要调整画布大小,我使用 canvas.setDimensions({width:w,height:h}); 从当前窗口clientwidth和clientheight的宽度和高度。这是我的画布和他的容器:

<div style="width: 100%;" class="canvas-container">
   <canvas id="canvas" class='img-fluid'></canvas>
</div>

调整画布时,对于画布中的每个对象,我按比例更改它们的大小和位置。我计算出使用原始画布和新的帆布尺寸,以适用于每个对象的顶部/左/宽度/高度。该代码每次调整大小时都会运行:

 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);

调整大小正常,所有对象都正确地更改其尺寸。 问题在于,大多数对象在调整画布后无法选择。 另外,单击画布的空区有时会选择对象...

// 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/[email protected]/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

我已经在互联网上进行了很多研究,并尝试了很多事情,并且我想知道如果有人知道做出响应式设计的最佳方法,同时保持帆布对象的正确价值 为了避免发生这个问题。

谢谢

I have a Fabric.js canvas inside in a responsive design with boostrap.
To resize the canvas, i use canvas.setDimensions({width:w, height:h});
From the width and the height of the current window clientWidth and clientHeight. Here is my canvas and his container :

<div style="width: 100%;" class="canvas-container">
   <canvas id="canvas" class='img-fluid'></canvas>
</div>

When the canvas is resized, for each object in the canvas i change proportionally their size and location. I calculate a factor to apply to each object's top/left/width/height using the original and new canvas sizes. This code runs every time the canvas is resized:

 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);

Resizing works fine, all the objects change their dimensions correctly.
The problem is that most objects cannot be selected after the canvas is resized.
Also, clicking on empty areas of the canvas sometimes selects objects...

// 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/[email protected]/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>

As you can see in the snippet, when page is loaded, you can modify the text like you want but if you click to "Full page", you cannot do it anymore or it become difficult to do it.

Here a video explaining the problem : https://a.uguu.se/pgOYGfJy.webm

I have done a lot of research on the internet and tried a lot of things and i would like to know if anyone knows the best way to make a responsive design while keeping the correct values of the canvas objects in order to avoid this problem happening.

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

紙鸢 2025-01-27 09:54:48

有几件事:

  1. Fabric.js 自动添加 .canvas-container 包装器。你不
    必须提供它。你的代码最终创建了两个
    .canvas-container 元素。这会扰乱布局。
  2. 您可以直接使用 window.innerHeight,而不是在父容器上设置宽度 100% 并从中读取它。

假设您希望画布适合视口,您可以尝试以下操作:

// 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/[email protected]/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>

如果您想要方形画布,请不要使用上面代码中的 window.innerHeight 或将 window.innerHeight 替换为 window.innerWidth
如果您希望画布适合整个窗口,而不删除父元素,请添加以下 CSS 规则:

.canvas-container {
  position: fixed !important;
  top: 0;
  left: 0;
}

方形画布 对象将按比例缩放。

// 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/[email protected]/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>


更大的画布:尺寸不是问题。请参阅全页。

// 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/[email protected]/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>

Couple of things:

  1. Fabric.js adds the .canvas-container wrapper automatically. You don't
    have to provide it. Your code ends up creating two
    .canvas-container elements. That disturbs the layout.
  2. You can directly use window.innerHeight, instead of setting width 100% on parent container and reading it from it.

Assuming you want the canvas to fit the viewport you can try this:

// 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/[email protected]/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>

If you want square canvas then don't use window.innerHeight or replace window.innerHeight with window.innerWidth in above code.
If you want canvas to fit entire window, without removing parent elements, then add following CSS rule:

.canvas-container {
  position: fixed !important;
  top: 0;
  left: 0;
}

Square canvas Objects will scale in proportion.

// 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/[email protected]/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>


Bigger canvas: size is not an issue. See in full page.

// 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/[email protected]/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>

烧了回忆取暖 2025-01-27 09:54:48

我很抱歉告诉你这个消息,但你的努力可能是多余的。 :(

看来 setDimensions 方法的 backstoreOnlycssOnly 选项为我们完成了所有工作。

我简化了你的代码很多,它似乎与你的完全一样,我的意思是这两个代码都受到同一问题的影响,

问题似乎不是由于你的(或我的)代码造成的,似乎是由于结构本身造成的。当画布较高时,问题就会显现出来 如果我们展开片段

,我们可以看到它们都工作正常,直到画布的高度小于视口的高度。

要查看问题的实际情况:

  1. 展开片段
  2. 调整大小以使画布更高。比视口
  3. 垂直拖动文本

我在互联网上搜索了一段时间,但没有发现任何相关内容。

// 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/[email protected]/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>

I'm sorry to give you this news, but probably your effort is superfluous. :(

It seems that the backstoreOnly and cssOnly options of the setDimensions method do all the job for us.

I simplified your code a lot and it seems to work exactly as your one. With "exactly" I mean that both the codes are affected by the same problem.

The problem seems not to be due to your (or my) code, seems to be due to fabric itself; it seems the problem manifests itself when the canvas is higher than the viewport.

If we expand the snippets, we can see both of them work fine until the height of the canvas is lesser than the one of the viewport.

To see the problem in action:

  1. expand the snippet
  2. resize it to make the canvas higher than the viewport
  3. drag the text vertically

I searched for a while on the internet, but I found nothing relevant.

// 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/[email protected]/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>

阿楠 2025-01-27 09:54:48

我在调整大小函数中删除了额外的代码,并将最大容器宽度值限制在1000中,然后更改Canvas包装器Div的类名称,以避免与Fabric.js代码混淆。

@Daniele Ricci:感谢您向我展示,调整大小超过1000px时的帆布错误。关于您的解决方案:在执行摘要时,画布并未在评论中指定全部宽度(我应该在评论中指定它,但我谈论的是boostrap的响应性规则)。它是200px,您无法在最小的窗口大小中获得对象控制按钮。

@hutt:感谢您向我展示Fabric.js本身与Canvas-container类创建了Div,我没有注意它。关于您的解决方案:问题在于,当画布在整页中时,文本不会适应正确的尺寸(尤其是在此尺寸上)。

// 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/[email protected]/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>

I deleted the extra code in the resize function and limit the maximum containerWidth value to 1000 and i change the class name of the canvas wrapper div to avoid confusion with Fabric.js code.

@Daniele Ricci : thank you for showing me that the canvas bugs when resizing exceeds 1000px. About your solution : the canvas does not take the full width (I should have specified it in my comment but I was talking about the responsive rule of boostrap) of 540px when the snippet is executed. It's 200px, you cant get the object control buttons in the smallest window size.

@the Hutt : thank you for showing me that Fabric.js itself creates a div with the canvas-container class, i hadn't paid attention to it. About your solution: The problem is that the text does not adapt to the right size (especially on the height of this one) when the canvas is in full page.

// 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/[email protected]/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>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文