【问题标题】:Maintain strokeWidth while scaling in fabric js在织物 js 中缩放时保持 strokeWidth
【发布时间】:2018-08-06 21:32:17
【问题描述】:

注意:我已经推荐了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;
  }
});

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

这里是sn-p/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

Unable to maintain thickness of strokeWidth while resizing in case of Groups in Fabricjs

Fabricjs How to scale object but keep the border (stroke) width fixed

Resize a fabricjs rect to maintain border size

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

但无法找到解决方案。

【问题讨论】:

  • 其实我用过那个代码。但是使用该代码,它会重新计算边界,因此出现了我添加的问题。
  • @BrettDeWoody 如您所见,我使用了您已标记为重复的已接受答案。但是使用该答案问题发生了我已经添加的问题。所以它不是重复的。
  • activeObj.set({strokeWidth:cur_value,strokeWidthUnscaled:null}); 使 strokeWidthUnscaled 对象为空,所以在缩放时它会重置
  • @Durga,有没有办法确定我们选择的是否是组?我的意思是,如果我们选择单个对象,那么它不是组,但如果它有多个元素,那么它的组。

标签: javascript canvas fabricjs fabricjs2


【解决方案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>

【讨论】:

  • 这不是答案,因为它根本不保持strokeWidth。
  • 检查开发者工具。如果将笔画宽度设置为 4 然后调整大小,笔画宽度将保持在 4。它不会重置为 1 的一小部分。除非我误解了所要求的内容,否则会保持设置的笔画宽度。
  • 在您的情况下,在缩放时检查对象的 strokeWidth,它会发生变化。 OP 希望保持与缩放之前相同。不仅仅是 strokeWidth 的值。
【解决方案2】:

第一次将strokeWidth设置为strokeWidthUnscaled,然后在缩放时设置@,对于缓存,只有在修改后的缩放时才将其设置为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>

【讨论】:

  • 它适用于除这种情况外的所有情况:添加对象,然后使用(上/下/左/右)标记缩放对象(表示使用非按比例缩放(即从正方形))。在那种情况下,边界搞砸了。
  • @DS9 我知道了,必须等待 Andrea 的回答;)
  • 当然,会等待:)。
【解决方案3】:

在处理这个问题时,我注意到在调整对象的宽度和高度值后,它不会改变,它只会改变 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/

【讨论】:

    【解决方案4】:

    从 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>

    【讨论】:

      【解决方案5】:

      如果您的对象在组内,则 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();
       
      }
      

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

      【讨论】:

        猜你喜欢
        • 2018-07-12
        • 2021-08-08
        • 2020-11-04
        • 2017-11-14
        • 2019-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多