最近开发遇到一个问题,app 端的线条和 web 端的线条不一致,产品的需求是要实现一致。
差异
具体的差异如下:
app 端
app 端的线条上下有 5px 的内边距,原点在左上角(控制框的左上角)。
web 端
Fabric.js 自带的 Line 类实现的线条,设置 padding 属性为 5px 后,它的上下、左右内边距都是 5px。原点在线条的左上角。
期望
产品的期望是要和 app 端实现的一样:原点在控制框的左上角,上下有 5px 的内边距。左右内边距为 0。
实现
如果你熟悉 Fabric.js,你会如何实现,先不看我的实现,你可以自己想想实现方式。
第一版方案
第一版的方案证明是失败的,实现复杂,而且遇到旋转后,就变得混乱了。
它的思路是这样的:
1、自定义 CustomLine 类型,继承自 fabric.Group
2、组内由三部分组成:红色的 fabric.Rect、fabric.Line 和绿色的 fabric.Rect
坑点
1、改变线条宽高时,需要同时改变两个矩形的位置和宽高。
2、addWithUpdate 很神奇,会改变组的 left 和 top
3、旋转后,在放大缩小会很复杂,因为要考虑矩形的旋转、宽高、位置的计算(我放弃了)。
第二版方案
这个方案,目前看起来是符合要求的,可能有些场景我还没考虑到。
思路是这样:
1、自定义 CustomLine 类型,继承自 fabric.Line
2、覆盖掉原 Line 类的 _setWidthHeight, _render, _getNonTransformedDimensions
具体代码如下:
fabric.CustomLine = fabric.util.createClass(fabric.Line, {
type: "CustomLine",
_fixedPadding: 5,
initialize: function (points, options) {
options || (options = {});
this.callSuper("initialize", points, options);
},
_setWidthHeight: function (options) {
options || (options = {});
this.width = Math.abs(this.x2 - this.x1);
this.height = Math.abs(this.y2 - this.y1) + this._fixedPadding * 2; // 增加高度,为内边距留空间
this.left = "left" in options ? options.left : this._getLeftToOriginX();
this.top = "top" in options ? options.top : this._getTopToOriginY();
},
_render: function (ctx) {
ctx.beginPath();
let p = this.calcLinePoints();
ctx.moveTo(p.x1, p.y1 + this._fixedPadding); // 开始点,y 移动到控制框的中间
ctx.lineTo(p.x2, p.y2 - this._fixedPadding); // 结束点,y 移动到控制框的中间
ctx.lineWidth = this.strokeWidth;
// TODO: test this
// make sure setting "fill" changes color of a line
// (by copying fillStyle to strokeStyle, since line is stroked, not filled)
var origStrokeStyle = ctx.strokeStyle;
ctx.strokeStyle = this.stroke || ctx.fillStyle;
this.stroke && this._renderStroke(ctx);
ctx.strokeStyle = origStrokeStyle;
},
_getNonTransformedDimensions: function () {
let dim = this.callSuper("_getNonTransformedDimensions");
if (this.strokeLineCap === "butt") {
if (this.width === 0) {
dim.y -= this.strokeWidth;
}
dim.x -= this.strokeWidth; // 原本的 Line 是判断 height 为 0 再重新为 x 减去 strokeWidth 的值,这是关键点。
}
return dim;
},
});
总结
别问我是怎样总结出的。说多了都是泪。
如果这篇文章对你有用,请不吝点赞、收藏。