如何更改fabricjs中的旋转图标

How can i change the rotation icon in fabricjs

本文关键字:旋转 图标 何更改 fabricjs      更新时间:2023-09-26

请指导我修改Fabricjs,为Rotation添加自定义图标。

我得到了一些答案,但效果不佳。

请让我知道只更改特定旋转图标的代码。

像这样更改结构对象原型"drawControls"。

下面是一个例子和JSFiddle:

fabric.Object.prototype.drawControls = function (ctx) {
    if (!this.hasControls) return this;

    var size = this.cornerSize,
        size2 = size / 2,
        strokeWidth2 = ~~(this.strokeWidth / 2), // half strokeWidth rounded down
        left = -(this.width / 2),
        top = -(this.height / 2),
        paddingX = this.padding / this.scaleX,
        paddingY = this.padding / this.scaleY,
        scaleOffsetY = size2 / this.scaleY,
        scaleOffsetX = size2 / this.scaleX,
        scaleOffsetSizeX = (size2 - size) / this.scaleX,
        scaleOffsetSizeY = (size2 - size) / this.scaleY,
        height = this.height,
        width = this.width,
        methodName = this.transparentCorners ? 'strokeRect' : 'fillRect';
    ctx.save();
    ctx.lineWidth = 1 / Math.max(this.scaleX, this.scaleY);
    ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
    ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
    // top-left
    this._drawControl('tl', ctx, methodName,
        left - scaleOffsetX - strokeWidth2 - paddingX,
        top - scaleOffsetY - strokeWidth2 - paddingY);
    // top-right
    this._drawControl('tr', ctx, methodName,
        left + width - scaleOffsetX + strokeWidth2 + paddingX,
        top - scaleOffsetY - strokeWidth2 - paddingY);
    // bottom-left
    this._drawControl('bl', ctx, methodName,
        left - scaleOffsetX - strokeWidth2 - paddingX,
        top + height + scaleOffsetSizeY + strokeWidth2 + paddingY);
    // bottom-right
    this._drawControl('br', ctx, methodName,
        left + width + scaleOffsetSizeX + strokeWidth2 + paddingX,
        top + height + scaleOffsetSizeY + strokeWidth2 + paddingY);
    if (!this.get('lockUniScaling')) {
        // middle-top
        this._drawControl('mt', ctx, methodName,
            left + width / 2 - scaleOffsetX,
            top - scaleOffsetY - strokeWidth2 - paddingY);
        // middle-bottom
        this._drawControl('mb', ctx, methodName,
            left + width / 2 - scaleOffsetX,
            top + height + scaleOffsetSizeY + strokeWidth2 + paddingY);
        // middle-right
        this._drawControl('mr', ctx, methodName,
            left + width + scaleOffsetSizeX + strokeWidth2 + paddingX,
            top + height / 2 - scaleOffsetY);
        // middle-left
        this._drawControl('ml', ctx, methodName,
            left - scaleOffsetX - strokeWidth2 - paddingX,
            top + height / 2 - scaleOffsetY);
    }
    // middle-top-rotate
    if (this.hasRotatingPoint) {
        /*
         We dont need old corner for rotate :)
         this._drawControl('mtr', ctx, methodName,
         left + width/2 - scaleOffsetX,
         this.flipY
         ? (top + height + (this.rotatingPointOffset / this.scaleY) - this.cornerSize/this.scaleX/2 + strokeWidth2 + paddingY)
         : (top - (this.rotatingPointOffset / this.scaleY) - this.cornerSize/this.scaleY/2 - strokeWidth2 - paddingY));
         Draw rotate custom icon
         */
        var rotate = new Image(), rotateLeft, rotateTop;
        rotate.src = 'http://www.navifun.net/files/pins/tiny/Arrow-Rotate-Clockwise.png';
        rotateLeft = left + width / 2 - scaleOffsetX;
        rotateTop = this.flipY
            ? (top + height + (this.rotatingPointOffset / this.scaleY) - this.cornerSize / this.scaleX / 2 + strokeWidth2 + paddingY)
            : (top - (this.rotatingPointOffset / this.scaleY) - this.cornerSize / this.scaleY / 2 - strokeWidth2 - paddingY);
        ctx.drawImage(rotate, rotateLeft, rotateTop, size / this.scaleX, size / this.scaleY);

    }
    ctx.restore();
    return this;
};

@hlozancic的答案覆盖了原型的一个重要部分。社区维护的Monkey补丁库对我来说不太好,因为这些方法中的代码可能会在我不知情的情况下发生更改(事实上,drawControls自7月2日以来已经发生了更改)。这里有一个我更喜欢的替代方案:

var _original = fabric.Object.prototype._drawControl;
fabric.Object.prototype._drawControl = function(control, ctx, methodName, left, top) {
  var size = this.cornerSize;
  if (this.canvas.hasControlCallback && this.canvas.hasControlCallback[control]) {
    this.canvas.controlCallback[control](ctx, left, top, size);
  } else {
    _original.call(this, control, ctx, methodName, left, top);
  }
};
/* then, when instantiating your fabric canvas  */
var canvas = new fabric.Canvas();
/* callbacks for drawing the controls */
canvas.hasControlCallback = {
    mtr: true
};
canvas.controlCallback = {
    mtr: function mtrControlCallback (ctx, left, top, size) {
        var image = new Image(), x, y;
        image.src = 'http://www.navifun.net/files/pins/tiny/Arrow-Rotate-Clockwise.png';
        x = left - image.width/2 + size/2;
        y = top - image.height/2 + size/2;
        ctx.drawImage(image, x, y);
    }
};

很抱歉没有提供小提琴,请注意写这篇文章的日期。

随着v4.0于2020年8月发布,Fabric.js现在包含了一个完整的控件自定义系统,这使得旋转控件的样式设计变得非常容易。

var canvas = new fabric.Canvas('c');
// set your icon here as a base64 string
var rotateIcon = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+PHBhdGggZD0iTTEyIDZ2M2w0LTQtNC00djNjLTQuNDIgMC04IDMuNTgtOCA4IDAgMS41Ny40NiAzLjAzIDEuMjQgNC4yNkw2LjcgMTQuOGMtLjQ1LS44My0uNy0xLjc5LS43LTIuOCAwLTMuMzEgMi42OS02IDYtNnptNi43NiAxLjc0TDE3LjMgOS4yYy40NC44NC43IDEuNzkuNyAyLjggMCAzLjMxLTIuNjkgNi02IDZ2LTNsLTQgNCA0IDR2LTNjNC40MiAwIDgtMy41OCA4LTggMC0xLjU3LS40Ni0zLjAzLTEuMjQtNC4yNnoiLz48L3N2Zz4=";
var img = document.createElement('img');
img.src = rotateIcon;
// here's where your custom rotation control is defined
// by changing the values you can customize the location, size, look, and behavior of the control
fabric.Object.prototype.controls.mtr = new fabric.Control({
  x: 0,
  y: -0.5,
  offsetY: -40,
  cursorStyle: 'crosshair',
  actionHandler: fabric.controlsUtils.rotationWithSnapping,
  actionName: 'rotate',
  render: renderIcon,
  cornerSize: 28,
  withConnection: true
});
// here's where the render action for the control is defined
function renderIcon(ctx, left, top, styleOverride, fabricObject) {
  var size = this.cornerSize;
  ctx.save();
  ctx.translate(left, top);
  ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
  ctx.drawImage(img, -size / 2, -size / 2, size, size);
  ctx.restore();
}
var rect = new fabric.Rect({
  left: 50,
  top: 70,
  fill: 'red',
  width: 200,
  height: 100,
  objectCaching: false,
  stroke: 'blue',
  strokeWidth: 4,
});
canvas.add(rect);
canvas.setActiveObject(rect);
<script src="https://unpkg.com/fabric@4.0.0/dist/fabric.js"></script>
<canvas id="c" width="400" height="250" style="border:1px solid #ccc"></canvas>

对于1.6.6以上的fabricjs更改函数对象原型drawControls,hasRotation条件的微小更改,结果可以看到这个JSFidle

fabric.Object.prototype.drawControls = function (ctx) {
  if (!this.hasControls) {
    return this;
  }
  var wh = this._calculateCurrentDimensions(),
  width = wh.x,
  height = wh.y,
  scaleOffset = this.cornerSize,
  left = -(width + scaleOffset) / 2,
  top = -(height + scaleOffset) / 2,
  methodName = this.transparentCorners ? 'stroke' : 'fill';
  ctx.save();
  ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
  if (!this.transparentCorners) {
    ctx.strokeStyle = this.cornerStrokeColor;
  }
 this._setLineDash(ctx, this.cornerDashArray, null);
  // top-left
 this._drawControl('tl', ctx, methodName,left,top);
 // top-right
this._drawControl('tr', ctx, methodName, left + width,top);
// bottom-left
this._drawControl('bl', ctx, methodName,left, top + height);
// bottom-right
this._drawControl('br', ctx, methodName,left + width,top + height);
if (!this.get('lockUniScaling')) {
// middle-top
this._drawControl('mt', ctx, methodName,
  left + width / 2,
  top);
// middle-bottom
this._drawControl('mb', ctx, methodName,
  left + width / 2,
  top + height);
// middle-right
this._drawControl('mr', ctx, methodName,
  left + width,
  top + height / 2);
// middle-left
this._drawControl('ml', ctx, methodName,
  left,
  top + height / 2);
}
// middle-top-rotate
if (this.hasRotatingPoint) {
  var rotate = new Image(), rotateLeft, rotateTop;
  rotate.src = 'http://localhost:8000/images/toolbar/close.svg';
  rotateLeft = left + width / 2;
  rotateTop = top - this.rotatingPointOffset;
  ctx.drawImage(rotate, rotateLeft, rotateTop, 10, 15);
}
ctx.restore();
return this;
}

此代码适用于Edge、Chrome、FireFox、Try This或您可以从core js库文件中复制该函数,然后可以替换ctx.drawImage函数

 fabric.Object.prototype.drawControls = function (ctx) {
            if (!this.hasControls) {
                return this;
            }
            var wh = this._calculateCurrentDimensions(), width = wh.x, height = wh.y, scaleOffset = this.cornerSize, left = -(width + scaleOffset) / 2, top = -(height + scaleOffset) / 2, methodName = this.transparentCorners ? "stroke" : "fill";
            ctx.save();
            ctx.strokeStyle = ctx.fillStyle = this.cornerColor;
            if (!this.transparentCorners) {
                ctx.strokeStyle = this.cornerStrokeColor;
            }
            this._setLineDash(ctx, this.cornerDashArray, null);
            this._drawControl("tl", ctx, methodName, left, top);
            this._drawControl("tr", ctx, methodName, left + width, top);
            this._drawControl("bl", ctx, methodName, left, top + height);
            this._drawControl("br", ctx, methodName, left + width, top + height);
            if (!this.get("lockUniScaling")) {
                this._drawControl("mt", ctx, methodName, left + width / 2, top);
                this._drawControl("mb", ctx, methodName, left + width / 2, top + height);
                this._drawControl("mr", ctx, methodName, left + width, top + height / 2);
                this._drawControl("ml", ctx, methodName, left, top + height / 2);
            }
            if (this.hasRotatingPoint) {
                this._drawControl("mtr", ctx, methodName, left + width / 2, top - this.rotatingPointOffset);
                var rotate = new Image(), rotateLeft, rotateTop;
                rotate.src = rotate_icon;
                rotateLeft = left + width / 2;
                rotateTop = top - this.rotatingPointOffset;
                ctx.drawImage(rotate, rotateLeft-3, rotateTop-1, 18, 18);
            }
            ctx.restore();
            return this;
        };

我知道这是一个很老的问题,但对于任何寻求更简单解决方案的人来说:

https://github.com/pixolith/fabricjs-customise-controls-extension

这个插件是最新的,非常适合我。你不必重写fabric-js的内部逻辑,因此使用起来更安全。

在移动之前不显示图像的问题是因为图像加载是异步的。将其与数据url:内联

image.src = 'data:image/png;base64 .... ';