15

注意:我已经提交了SO question,但这对我的情况没有用,因为

1)我试图保持以前的边界,但到目前为止它在缩放时重新计算边界。

我在下面添加了代码以在缩放对象时停止自动增加边框。现在的问题是我为对象添加了一个 5px 的边框,但是当缩放对象时,它并没有保持我之前添加的边框。

canvas.on('object:scaling', (e) => {
  var o = e.target;
  if (!o.strokeWidthUnscaled && o.strokeWidth) {
    o.strokeWidthUnscaled = o.strokeWidth;
  }

  if (o.strokeWidthUnscaled) {
    o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
  }
});

现在我想要的是在缩放对象时防止边框增加。边界应保持原样。

这是片段/ Codepen

var canvas = new fabric.Canvas('canvas1');

$('.add_shape').click(function() {
  var cur_value = $(this).attr('data-rel');
  if (cur_value != '') {
    switch (cur_value) {
      case 'rectangle':
        var rect = new fabric.Rect({
          left: 50,
          top: 50,
          fill: '#aaa',
          width: 50,
          height: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: 1
        });
        canvas.add(rect);
        canvas.setActiveObject(rect);
        break;
      case 'circle':
        var circle = new fabric.Circle({
          left: 50,
          top: 50,
          fill: '#aaa',
          radius: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: 1
        });
        canvas.add(circle);
        canvas.setActiveObject(circle);
        break;
    }
  }
});

canvas.on('object:scaling', (e) => {
  var o = e.target;
  if (!o.strokeWidthUnscaled && o.strokeWidth) {
    o.strokeWidthUnscaled = o.strokeWidth;
  }
  if (o.strokeWidthUnscaled) {
    o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
  }
});

/* Control the border  */
$('#control_border').change(function() {
  var cur_value = parseInt($(this).val());
  var activeObj = canvas.getActiveObject();
  if (activeObj == undefined) {
    alert('Please select the Object');
    return false;
  }
  activeObj.set({
    strokeWidth: cur_value
  });
  canvas.renderAll();
});
button {
  max-resolution: 10px;
  height: 30px;
}

div {
  margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.js"></script>

<div>
  <button class="add_shape" data-rel="circle">Add Circle</button>

  <button class="add_shape" data-rel="rectangle">Add Rectangle</button>

  <label class="control-label">Border</label>
  <input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>

<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>

脚步

1)添加矩形
2)应用边框(比如说 5)
3)缩放该对象

现在您可以看到应用的边框消失了。那么如何解决呢?

更新

我尝试了以下选项,但它不起作用,基本上我试图为矩形、圆形、三角形、线条、多边形等对象维护 strokeWidth/Border

到目前为止我已经尝试过:

//1st try
canvas.on('object:scaling', (e) => {
    var o = e.target;
    o.strokeWidth = o.strokeWidth / ((o.scaleX + o.scaleY) / 2);
    var activeObject = canvas.getActiveObject();
    activeObject.set('strokeWidth',o.strokeWidth);
});

//2nd try
canvas.on('object:scaling', (e) => {
    if (!o.strokeWidthUnscaled && o.strokeWidth) {
        o.strokeWidthUnscaled = o.strokeWidth;
    }
    if (o.strokeWidthUnscaled) {
        o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
    }
});

//3rd try
fabric.Object.prototype._renderStroke = function(ctx) {
    if (!this.stroke || this.strokeWidth === 0) {
        return;
    }
    if (this.shadow && !this.shadow.affectStroke) {
        this._removeShadow(ctx);
    }
    ctx.save();
    ctx.scale(1 / this.scaleX, 1 / this.scaleY);
    this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
    this._applyPatternGradientTransform(ctx, this.stroke);
    ctx.stroke();
    ctx.restore();
};

我参考过的问题:

https://github.com/kangax/fabric.js/issues/66

在 Fabricjs 中的 Groups 的情况下,在调整大小时无法保持 strokeWidth 的厚度

Fabricjs如何缩放对象但保持边框(笔触)宽度固定

调整fabricjs rect的大小以保持边框大小

https://github.com/kangax/fabric.js/issues/2012

但无法找到解决方案。

4

5 回答 5

12

从 Fabric.js 版本 2.7.0 开始,这变得更加容易。现在有一个strokeUniform属性,当启用时,可以防止笔触宽度受到对象缩放值的影响。

obj.set('strokeUniform', true);

https://github.com/fabricjs/fabric.js/pull/5546

var canvas = new fabric.Canvas('canvas1');

$('.add_shape').click(function() {
  var cur_value = $(this).attr('data-rel');
  if (cur_value != '') {
    switch (cur_value) {
      case 'rectangle':
        var rect = new fabric.Rect({
          left: 50,
          top: 50,
          fill: '#aaa',
          width: 50,
          height: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: 1,
          noScaleCache: false,
          strokeUniform: true,
        });
        canvas.add(rect);
        canvas.setActiveObject(rect);
        break;
      case 'circle':
        var circle = new fabric.Circle({
          left: 50,
          top: 50,
          fill: '#aaa',
          radius: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: 1,
          noScaleCache: false,
          strokeUniform: true
        });
        canvas.add(circle);
        canvas.setActiveObject(circle);
        break;
    }
  }
});

/* Control the border  */
$('#control_border').change(function() {
  var cur_value = parseInt($(this).val());
  var activeObj = canvas.getActiveObject();
  if (activeObj == undefined) {
    alert('Please select the Object');
    return false;
  }
  activeObj.set({
    strokeWidth: cur_value
  });
  canvas.renderAll();
});
button {
  max-resolution: 10px;
  height: 30px;
}

div {
  margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>

<div>
  <button class="add_shape" data-rel="circle">Add Circle</button>
  <button class="add_shape" data-rel="rectangle">Add Rectangle</button>
  <label class="control-label">Border</label>
  <input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>

<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>

于 2019-04-18T05:34:16.927 回答
6

第一次设置strokeWidthstrokeWidthUnscaled然后在缩放时设置@,对于缓存,只有在修改后的缩放时才将其设置为false。

object.strokeWidth = object.strokeWidthUnscaled/((object.scaleX+object.scaleY)/2);

对于选择新的笔划宽度,请执行此操作

var newStrokeWidth = cur_value / ((activeObj.scaleX + activeObj.scaleY) / 2)
activeObj.set({
  strokeWidth: newStrokeWidth,
  strokeWidthUnscaled : cur_value
});

例子

var canvas = new fabric.Canvas('canvas1');
var globalStrokeWidth = 1;

$('.add_shape').click(function() {
  var cur_value = $(this).attr('data-rel');
  if (cur_value != '') {
    switch (cur_value) {
      case 'rectangle':
        var rect = new fabric.Rect({
          left: 50,
          top: 50,
          fill: '#aaa',
          width: 50,
          height: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: globalStrokeWidth
        });
        canvas.add(rect);
        canvas.setActiveObject(rect);
        break;
      case 'circle':
        var circle = new fabric.Circle({
          left: 50,
          top: 50,
          fill: '#aaa',
          radius: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: globalStrokeWidth
        });
        canvas.add(circle);
        canvas.setActiveObject(circle);
        break;
    }
  }
});

canvas.on('object:scaling', (e) => {
  var o = e.target;
  if (!o.strokeWidthUnscaled && o.strokeWidth) {
    o.strokeWidthUnscaled = o.strokeWidth;
  }
  if (o.strokeWidthUnscaled) {
    if(o.objectCaching) o.objectCaching = false;
    o.strokeWidth = o.strokeWidthUnscaled / ((o.scaleX + o.scaleY) / 2);
  }
});

canvas.on('object:modified', (e) => {
  var o = e.target;
  if(!o.objectCaching) o.objectCaching = true;
  canvas.renderAll();
});

/* Control the border  */
$('#control_border').change(function() {
  var cur_value = parseInt($(this).val());
  globalStrokeWidth = cur_value;
  var activeObj = canvas.getActiveObject();
  if (activeObj == undefined) {
    alert('Please select the Object');
    return false;
  }
  var newStrokeWidth = cur_value / ((activeObj.scaleX + activeObj.scaleY) / 2)
  activeObj.set({
    strokeWidth: newStrokeWidth,
    strokeWidthUnscaled : cur_value
  });
  activeObj.setCoords();
  canvas.renderAll();
});
button {
  max-resolution: 10px;
  height: 30px;
}

div {
  margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.js"></script>

<div>
  <button class="add_shape" data-rel="circle">Add Circle</button>

  <button class="add_shape" data-rel="rectangle">Add Rectangle</button>

  <label class="control-label">Border</label>
  <input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>

<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>

于 2018-03-02T07:42:40.613 回答
2

在处理这个问题时,我注意到在调整对象的宽度和高度值后不会改变,它只会改变 scaleX 和 scaleY。要保持笔触宽度,您需要将 scaleX 和 scalyY 重置为 1,并使用新值更新宽度和高度。

对于矩形:

var currObj = canvas.getActiveObject();
if (currObj.type === 'rect') {
  var newWidth = currObj.width * currObj.scaleX,
      newHeight = currObj.height * currObj.scaleY;

    currObj.set({
      'width': newWidth,
      'height': newHeight,
      scaleX: 1,
      scaleY: 1
    });
}

对于椭圆:

var currObj = canvas.getActiveObject();
if (currObj.type === 'ellipse') {
  var newRX = currObj.rx * currObj.scaleX,
      newRY = currObj.ry * currObj.scaleY;

  currObj.set({
    'rx': newRX,
    'ry': newRY,
    scaleX: 1,
    scaleY: 1
    });
}

不要忘记稍后调用 canvas.renderAll();

http://jsfiddle.net/eLoamgrq/5/

于 2019-04-16T11:03:45.653 回答
1

在 object:scaling 中,我注释掉了基于 scale 的计算。由于未缩放 = 1 并且通过缩放来划分它总是导致边界等于分数(而不是保持不变)。

var canvas = new fabric.Canvas('canvas1');

$('.add_shape').click(function() {
  var cur_value = $(this).attr('data-rel');
  if (cur_value != '') {
    switch (cur_value) {
      case 'rectangle':
        var rect = new fabric.Rect({
          left: 50,
          top: 50,
          fill: '#aaa',
          width: 50,
          height: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: 1
        });
        canvas.add(rect);
        canvas.setActiveObject(rect);
        break;
      case 'circle':
        var circle = new fabric.Circle({
          left: 50,
          top: 50,
          fill: '#aaa',
          radius: 50,
          opacity: 1,
          stroke: '#000',
          strokeWidth: 1
        });
        canvas.add(circle);
        canvas.setActiveObject(circle);
        break;
    }
  }
});

canvas.on('object:scaling', (e) => {
  var o = e.target;
  if (!o.strokeWidthUnscaled && o.strokeWidth) {
    o.strokeWidthUnscaled = o.strokeWidth;
  }
  if (o.strokeWidthUnscaled) {
    //o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
  }
});

/* Control the border  */
$('#control_border').change(function() {
  var cur_value = parseInt($(this).val());
  var activeObj = canvas.getActiveObject();
  if (activeObj == undefined) {
    alert('Please select the Object');
    return false;
  }
  activeObj.set({
    strokeWidth: cur_value
  });
  canvas.renderAll();
});
button {
  max-resolution: 10px;
  height: 30px;
}

div {
  margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.js"></script>

<div>
  <button class="add_shape" data-rel="circle">Add Circle</button>

  <button class="add_shape" data-rel="rectangle">Add Rectangle</button>

  <label class="control-label">Border</label>
  <input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>

<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>

于 2018-03-01T21:03:31.417 回答
0

如果您的对象在组内,则 strokeUniform 属性不起作用。在这种情况下,您可以减少内部对象的缩放并在缩放时更新其宽度和高度属性。例子:

object.on('scaling', function() {
     
    object.item(0).set('scaleX', 1/object.scaleX);
    object.item(0).set('scaleY', 1/object.scaleY);
    var newobjwidth = Math.round(object.width * object.scaleX);
    var newobjheight = Math.round(object.height * object.scaleY);
    object.item(0).set('width', newobjwidth);
    object.item(0).set('height', newobjheight);
    object.item(0).setCoords();
 
}

如果您的对象模糊,请删除它并在缩放后再次添加。

于 2020-10-05T14:36:43.823 回答