与转换矩阵相关的方法
与变换矩阵相关的方法
// @return 该特定时刻的对象变换的矩阵(受top, left, scale...的影响)
fabric.Object.prototype.calcTransformMatrix() => matrix
// @retrun 矩阵 A 乘以矩阵 B 进行嵌套变换后的矩阵
fabric.util.multiplyTransformMatrices(matrix, matrix) => matrix
// @return 反向矩阵,用来进行反向计算
fabric.util.invertTransform(matrix) => matrix
// @return 解码后的矩阵,返回一个包含(angle, scale, skew, translate)的选项对象
fabric.util.qrDecompose(matrix) => options
fabric.util.qrDecompose(matrix) 返回的选项
{
angle: number, // in degree
scaleX: number,
scaleY: number,
skewX: number, // in degree
skewY: 0, // always 0! in degree.
translateX: number,
translateY: number,
}
使用示例
场景
girl
牵着cat
出门,cat
可以随意走动,但是一旦girl
走动,cat
就会跟着girl
走。
fabric 实现的逻辑分析
cat
跟着girl
走的行为,需要以girl
为主,记录下girl
走动的变换矩阵,再将变换矩阵同步到cat
的变换上。以下是步骤的逐步分析:
- 鼠标按下记录
girl
和cat
的初始变换矩阵 cat
的初始变换矩阵减去girl
的初始变换矩阵,目的是只同步之后的变换矩阵,并不同步girl
的初始变换- 鼠标移动,记录
girl
的变换矩阵,同时将girl
的变换矩阵同步到cat
上
代码实现
/**
* @param { bossUrl } 女孩svg图片地址
* @param { bossUrl } 猫咪svg图片地址
* @param { canvasDom } canvas id
*/
function Minions(bossUrl, minionUrl, canvasDom) {
let boss, minion, canvas; // girl cat object, canvas
let startMatrix;
function init() {
canvas = new fabric.Canvas(canvasDom, {
width: 500,
height: 500,
backgroundColor: "#fafafa",
});
fabric.loadSVGFromURL(bossUrl, function (objects, options) {
boss = fabric.util.groupSVGElements(objects, {
...options,
top: 100,
left: 50,
});
canvas.add(boss);
});
fabric.loadSVGFromURL(minionUrl, function (objects, options) {
minion = fabric.util.groupSVGElements(objects, {
...options,
top: 240,
left: 250,
});
minion.scale(0.3);
canvas.add(minion);
// 鼠标点击画布时,初始化转换矩阵
canvas.on("mouse:down", initMatrix);
// 女孩移动时,猫咪跟随女孩移动
boss.on("moving", updateMinions);
boss.on("rotating", updateMinions);
boss.on("scaling", updateMinions);
});
}
function initMatrix() {
// cat 当前的变换矩阵
const minionMatrix = minion.calcTransformMatrix();
// girl 当前的变换矩阵
const bossMatrix = boss.calcTransformMatrix();
// girl 当前的反转变换矩阵, 也就是girl经过什么样的转换矩阵能变成初始状态
const invertBossMatrix = fabric.util.invertTransform(bossMatrix);
// cat 的初始变换矩阵需要减去girl的初始变换值,避免后续girl移动时, cat的变换不同步
startMatrix = fabric.util.multiplyTransformMatrices(
invertBossMatrix,
minionMatrix
);
}
function updateMinions() {
// 每次移动时都需要获取girl当前的变换矩阵
const bossMatrix = boss.calcTransformMatrix();
// cat同步girl的变换矩阵
const multiplyMatrix = fabric.util.multiplyTransformMatrices(
bossMatrix,
startMatrix
);
const opt = fabric.util.qrDecompose(multiplyMatrix);
minion.set({
flipX: false,
flipY: false,
});
minion.setPositionByOrigin(
{ x: opt.translateX, y: opt.translateY },
"center",
"center"
);
minion.set(opt);
minion.setCoords();
}
return init();
}