【问题标题】:Adding grid over Fabric.js canvas在 Fabric.js 画布上添加网格
【发布时间】:2013-06-19 19:15:30
【问题描述】:

我刚开始使用 Fabric.js(不得不说,我印象深刻)。

我想在织物对象上添加一个网格。在下面的代码中,我将网格画布放在 Fabric 画布上。这里的问题是,我现在无法移动我的织物对象!

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">

  <script type='text/javascript' src='http://code.jquery.com/jquery-1.7.1.js'></script>
  <script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.2.0/fabric.all.min.js'></script>

</head>
<body>

<div style="height:480px;width:640px;border:1px solid #ccc;position:relative;font:16px/26px Georgia, Garamond, Serif;overflow:auto;">

 <canvas id="rubber" width="800" height="800" 
   style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
 <canvas id="myCanvas" width="800" height="800" 
   style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</div>

<script>
//<![CDATA[ 
$(window).load(function(){
$(document).ready(function () {

    function renderGrid(x_size,y_size, color)
    {
        var canvas = $("#myCanvas").get(0);
        var context = canvas.getContext("2d");

        context.save();
        context.lineWidth = 0.5;
        context.strokeStyle = color;

        // horizontal grid lines
        for(var i = 0; i <= canvas.height; i = i + x_size)
        {
            context.beginPath();
            context.moveTo(0, i);
            context.lineTo(canvas.width, i);
            context.closePath();
            context.stroke();
        }

        // vertical grid lines
        for(var j = 0; j <= canvas.width; j = j + y_size)
        {
            context.beginPath();
            context.moveTo(j, 0);
            context.lineTo(j, canvas.height);
            context.closePath();
            context.stroke();
        }

        context.restore();
    }

    renderGrid(10,15, "gray");
});

});//]]>  

  var canvas = new fabric.Canvas('rubber');
  canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));

  canvas.selectionColor = 'rgba(0,255,0,0.3)';
  canvas.selectionBorderColor = 'red';
  canvas.selectionLineWidth = 5;
</script>


</body>
</html>

我希望有一种方法可以在 Fabric 本身中做到这一点。

任何帮助都会很棒,谢谢!

【问题讨论】:

  • 我的回答能解决吗?

标签: javascript jquery html fabricjs


【解决方案1】:

这两行代码可以工作:

var gridsize = 5;
for(var x=1;x<(canvas.width/gridsize);x++)
                        {
                            canvas.add(new fabric.Line([100*x, 0, 100*x, 600],{ stroke: "#000000", strokeWidth: 1, selectable:false, strokeDashArray: [5, 5]}));
                            canvas.add(new fabric.Line([0, 100*x, 600, 100*x],{ stroke: "#000000", strokeWidth: 1, selectable:false, strokeDashArray: [5, 5]}));
                    }

【讨论】:

  • 我刚刚添加了一个变量来控制单元格大小:var gridsize = 10, cellWidth=30; for(var x=1;x&lt;(canvas.width/gridsize);x++){ canvas.add(new fabric.Line([cellWidth*x, 0, cellWidth*x, 600],{ stroke: "#000000", strokeWidth: 1, selectable:false})); canvas.add(new fabric.Line([0, cellWidth*x, 600, cellWidth*x],{ stroke: "#000000", strokeWidth: 1, selectable:false})); }
【解决方案2】:

一个更短的版本,更通用的复制/粘贴:

var oCanvas; // must be your canvas object
var gridWidth; // <= you must define this with final grid width
var gridHeight; // <= you must define this with final grid height

// to manipulate grid after creation
var oGridGroup = new fabric.Group([], {left: 0, top: 0});

var gridSize = 20; // define grid size

// define presentation option of grid
var lineOption = {stroke: 'rgba(0,0,0,.4)', strokeWidth: 1, selectable:false, strokeDashArray: [3, 3]};

// do in two steps to limit the calculations
// first loop for vertical line
for(var i = Math.ceil(gridWidth/gridSize); i--;){
    oGridGroup.add( new fabric.Line([gridSize*i, 0, gridSize*i, gridHeight], lineOption) );
}
// second loop for horizontal line
for(var i = Math.ceil(gridHeight/gridSize); i--;){
    oGridGroup.add( new fabric.Line([0, gridSize*i, gridWidth, gridSize*i], lineOption) );
}
// Group add to canvas
oCanvas.add(oGridGroup);

【讨论】:

  • 最佳答案。您可能希望将“evented:false”添加到行选项。这将禁止触发所有鼠标交互事件。
  • 嗨,我的画布上没有显示网格线。你能帮我吗?
  • 是的,没有添加网格,因为该组在这里没有维度,因为它是之前创建的。可能是因为版本不同。根据这个answer,您可以重写,以便将这些行构建在一个数组中,然后简单地创建一个组。你可以在下面看到我的答案。
【解决方案3】:

希望对你有帮助----

function draw_grid(grid_size) {

  grid_size || (grid_size = 25);
  currentCanvasWidth = canvas.getWidth();
  currentcanvasHeight = canvas.getHeight();


  // Drawing vertical lines
  var x;
  for (x = 0; x <= currentCanvasWidth; x += grid_size) {
      this.grid_context.moveTo(x + 0.5, 0);
      this.grid_context.lineTo(x + 0.5, currentCanvasHeight);
  }

  // Drawing horizontal lines
  var y;
  for (y = 0; y <= currentCanvasHeight; y += grid_size) {
      this.grid_context.moveTo(0, y + 0.5);
      this.grid_context.lineTo(currentCanvasWidth, y + 0.5);
  }

  grid_size = grid_size;
  this.grid_context.strokeStyle = "black";
  this.grid_context.stroke();
}

【讨论】:

  • 如何在其中添加织物文本字段?
  • 你能分享一下小提琴吗?我没有得到 this.grid_context 是什么。
  • @UmeshPatadiya 对不起,我没有代码了,好久了
【解决方案4】:

我的解决办法是——

var width = canvas.width;
var height = canvas.height;

var j = 0;
var line = null;
var rect = [];
var size = 20;

console.log(width + ":" + height);

for (var i = 0; i < Math.ceil(width / 20); ++i) {
    rect[0] = i * size;
    rect[1] = 0;

    rect[2] = i * size;
    rect[3] = height;

    line = null;
    line = new fabric.Line(rect, {
        stroke: '#999',
        opacity: 0.5,
    });

    line.selectable = false;
    canvas.add(line);
    line.sendToBack();

}

for (i = 0; i < Math.ceil(height / 20); ++i) {
    rect[0] = 0;
    rect[1] = i * size;

    rect[2] = width;
    rect[3] = i * size;

    line = null;
    line = new fabric.Line(rect, {
        stroke: '#999',
        opacity: 0.5,
    });
    line.selectable = false;
    canvas.add(line);
    line.sendToBack();

}

canvas.renderAll();

您必须保存所有线对象以删除网格,或者您可以将所有线对象添加到一个组中,您可以删除组以删除网格,我认为这不是优雅的,但有效。

【讨论】:

  • Tom,这些行作为对象添加,因此当您想要向前或向后发送对象时,这些行也被视为有效对象。如何避免这种情况?
【解决方案5】:

如果您不坚持动态生成网格,您可能需要考虑使用 fabric.js 提供的原生叠加图像功能。

var canvas = new fabric.Canvas('rubber');
canvas.setOverlayImage('grid.png', canvas.renderAll.bind(canvas));

它根本不会妨碍与画布上的对象的交互。

【讨论】:

  • 其实我需要动态生成网格。 :O
  • @n2Code 如何将叠加层设置为背景。
  • 有两种方式 1) canvas.setBackgroundImage('../assets/pug.jpg', canvas.renderAll.bind(canvas)); 2)在您实例化画布后立即添加覆盖图像并将可选标记为 false
【解决方案6】:

我真的很喜欢@Draeli 的回答,但它似乎不适用于最新的面料版本。修复了旧的,并添加了一个我自己需要的微调 - 使网格居中。

不管怎样,也许别人觉得它有用:

const gridSize = 100;
const width = this.canvas.getWidth();
const height = this.canvas.getHeight();
const left = (width % gridSize) / 2;
const top = (height % gridSize) / 2;
const lines = [];
const lineOption = {stroke: 'rgba(0,0,0,1)', strokeWidth: 1, selectable: false};
for (let i = Math.ceil(width / gridSize); i--;) {
  lines.push(new fabric.Line([gridSize * i, -top, gridSize * i, height], lineOption));
}
for (let i = Math.ceil(height / gridSize); i--;) {
  lines.push(new fabric.Line([-left, gridSize * i, width, gridSize * i], lineOption));
}
const oGridGroup = new fabric.Group(lines, {left: 0, top: 0});

this.canvas.add(oGridGroup);

this.canvas - 这应该是织物实例。

【讨论】:

    【解决方案7】:

    这是我的解决方案,适用于 Fabric Js 4。 最后有 2 个事件侦听器,它们在对象移动时附加网格,并在对象移动结束时移除网格。 (改进@draeli 答案https://stackoverflow.com/a/35936606/1727357

    (function () {
        const gcd = (a, b) => {
            if (!b) {
                return a;
            }
            return gcd(b, a % b);
        }
        const gridWidth = canvas.getWidth();
        const gridHeight = canvas.getHeight();
    
        const oGridGroup = [];
        console.log(gcd(gridWidth, gridHeight));
    
        const gridRows = gcd(gridWidth, gridHeight);
        const gridCols = gcd(gridWidth, gridHeight);
    
        const lineOption = { stroke: 'rgba(0,0,0,.1)', strokeWidth: 1, selectable: false, evented: false };
    
        for (let i = 0; i <= gridWidth; i += gridCols) {
            oGridGroup.push(new fabric.Line([i, 0, i, gridHeight], lineOption));
        }
        for (let i = 0; i <= gridHeight; i += gridRows) {
            oGridGroup.push(new fabric.Line([0, i, gridWidth, i], lineOption));
        }
    
        const theGorup = new fabric.Group(oGridGroup);
        theGorup.set({
            selectable: false,
            evented: false
        })
    
        canvas.on('mouse:down', function (event) {
            if (event.target) {
                canvas.add(theGorup);
            }
        });
    
        canvas.on('mouse:up', function (event) {
            canvas.remove(theGorup);
    
        });
    
    }())
    

    【讨论】:

      【解决方案8】:

      更新:

      答案基于 rafi 发布的代码:

      1. 我已经更新了缺失的 grid_context。

      2. 请用字符串中的画布 ID 替换“”。例如“我的画布”。

      3. 通常,您在画布上所做的任何操作都会清除画布上的网格,在 fabric.js 画布上注册 after:render 事件以重新绘制它。所以你总是可以看到它。

         var canvas = new fabric.Canvas(<your canvas Id>);
         canvas.on('after:render',function(ctx){
               draw_grid(25);
         });
        
         function draw_grid(grid_size) {
            grid_size || (grid_size = 25);
            var currentCanvas = document.getElementById(<your canvas Id>); 
            var grid_context = currentCanvas.getContext("2d"); 
        
            var currentCanvasWidth = canvas.getWidth();
            var currentCanvasHeight = canvas.getHeight();
        
            // Drawing vertical lines
            var x;
            for (x = 0; x <= currentCanvasWidth; x += grid_size) {
               grid_context.moveTo(x + 0.5, 0);
               grid_context.lineTo(x + 0.5, currentCanvasHeight);
            }
        
            // Drawing horizontal lines
            var y;
            for (y = 0; y <= currentCanvasHeight; y += grid_size) {
              grid_context.moveTo(0, y + 0.5);
              grid_context.lineTo(currentCanvasWidth, y + 0.5);
            }
           grid_context.strokeStyle = "#0000002b";
           grid_context.stroke();
         }
        

      【讨论】:

      • 你的答案对我来说非常有用......但我的额外要求是在鼠标滚轮缩放时缩放网格。如果可以的话,请指导我。我是 fabric.js 的新手
      猜你喜欢
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      • 2015-03-19
      • 1970-01-01
      • 2017-05-17
      • 1970-01-01
      • 2018-03-15
      相关资源
      最近更新 更多