Maintain Image Stroke Width

by Steve Eberhardt

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.min.js"></script>
<button id="skew-selected">Skew Selected</button>
<canvas id="c" width="500" height="400" class="c"></canvas>

CSS

canvas {
  border: 1px solid grey;
}

JavaScript

var canvas = new fabric.Canvas('c');
var imageSrc = "http://fabricjs.com/assets/dragon.jpg";

fabric.Image.fromURL(imageSrc, function(img) {
  img.set({
    left: 40,
    scaleX: 0.18,
    scaleY: 0.18,
    top: 40,
    strokeWidth: 50,
    stroke: '#ccc',
    paintFirst: 'stroke'
  }, {
    crossOrigin: 'anonymous'
  });
  canvas.add(img);
});

//bounding box and control positions are incorrect when image is skewed
$('#skew-selected').on('click', function() {
	var obj = canvas.getActiveObject();
  obj.set('skewX', 10);
  obj.setCoords();
  canvas.renderAll();
});

//override stroke rendering for constant stroke width independent of scaling
fabric.Image.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();
};

//modify method for calculating control and bounding box positions
fabric.Image.prototype._getTransformedDimensions = function(skewX, skewY) {
  if (typeof skewX === 'undefined') {
    skewX = this.skewX;
  }
  if (typeof skewY === 'undefined') {
    skewY = this.skewY;
  }
  var dimensions = this._getNonTransformedDimensions();
  if (skewX === 0 && skewY === 0) {
    return {
      x: dimensions.x * this.scaleX + (this.strokeWidth * (1 - this.scaleX)),
      y: dimensions.y * this.scaleY + (this.strokeWidth * (1 - this.scaleY))
    };
  }
  var dimX = dimensions.x / 2,
    dimY = dimensions.y / 2,
    points = [{
        x: -dimX,
        y: -dimY
      },
      {
        x: dimX,
        y: -dimY
      },
      {
        x: -dimX,
        y: dimY
      },
      {
        x: dimX,
        y: dimY
      }
    ],
    i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false),
    bbox;
...