图片标注编辑平台搭建系列教程(5)——线宽不居中问题

背景

fabric中的polyline和polygon(继承自polyline),有一个普遍问题,就是如果设置了left和top后,同时设置了线宽,会发现线宽并不是沿着坐标序列居中渲染,而是以坐标最小外接矩形的左上角为原点,整体往右和下渲染。本期从源码内容详细分析成因。

现象

fabric中有一个选中框的概念,有几个控制的锚点,途中的矩形是500px,同时线宽20,从右下角绿色点(500,500)的位置可以看出,这个选中框的宽度=500+20=520,即width+strokeWidth。

如果画一条(0,0)到(500,500)的线,在不添加left和top的情况下,如左图,可以看到线的中心线是符合要求的。但如果你添加了left=0,top=0,那么渲染效果如右图。可以看出,线的端点有一定的偏移,具体来看,整体偏移了strokeWidth/2。

如果是(0,0)到(0,500)的线,在不设置left和top的效果如左图,设置left=0,top=0是,效果如右图。

原因

造成上述的原因是:在polyline的初始化方法中,调用了_setPositionDimensions方法,该方法中对于left和top没有赋值的情况,源代码自身进行了赋值(calcDim.left - strokeWidth / 2);一旦你设置了left和top,就会采用你设置的left和top,从而导致渲染上的偏移。(注意,这里的偏移程度取决于strokeWidth,对于线而言,strokeWidth的设置不可避免,因此只要设置了left和top多少都会有一定的偏移)。

由于每个object的ctx原点是基于ctx transform后,再一次进行偏移到object中心点,其偏移量为:

javascript 复制代码
x = this.left + 0.5 * (width + strokeWidth) = calcDim.left + 0.5 * width
y = this.top + 0.5 * (height + strokeWidth) = calcDim.top + 0.5 * height

在this.left 赋值的情况下,偏移量为:

javascript 复制代码
x = this.left + 0.5 * (width + strokeWidth) = calcDim.left + 0.5 * (width + strokeWidth);
y = this.top + 0.5 * (height + strokeWidth) = calcDim.top + 0.5 * (height + strokeWidth);

而绘制时每个点的坐标的偏移量this.pathOffset始终等于

javascript 复制代码
{
    x: calcDim.left + width / 2,
    y: calcDim.top + height / 2
}

因此,最终后者的坐标整体会比前者往x、y正方向偏移0.5 * strokeWidth。

而由于_setPositionDimensions只在canvas.add(object)时才调用,因此,在后续缩放整个画布的过程中,this.left、this.top的值始终是定值,但是strokeWidth为了维持缩放后的绝对像素宽度,始终在动态变化,此时,ctx的偏移量x、y在变化,而pathOffset没有变,最终相对于图片的位置还是在变化。

解决方案

为了解决这个问题,需要在子类覆写的_render方法内,写以下代码:

确保偏移量x、y计算正确。

预告

下一章简单讲讲fabric的渲染原理。

相关推荐
JIngJaneIL15 分钟前
基于java+ vue农产投入线上管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
天外天-亮42 分钟前
v-if、v-show、display: none、visibility: hidden区别
前端·javascript·html
jump_jump43 分钟前
手写一个 Askama 模板压缩工具
前端·性能优化·rust
be or not to be1 小时前
HTML入门系列:从图片到表单,再到音视频的完整实践
前端·html·音视频
90后的晨仔2 小时前
在macOS上无缝整合:为Claude Code配置魔搭社区免费API完全指南
前端
沿着路走到底2 小时前
JS事件循环
java·前端·javascript
子春一22 小时前
Flutter 2025 可访问性(Accessibility)工程体系:从合规达标到包容设计,打造人人可用的数字产品
前端·javascript·flutter
白兰地空瓶2 小时前
别再只会调 API 了!LangChain.js 才是前端 AI 工程化的真正起点
前端·langchain
jlspcsdn3 小时前
20251222项目练习
前端·javascript·html
行走的陀螺仪4 小时前
Sass 详细指南
前端·css·rust·sass