javascript - 有没有办法在应用 css 变换矩阵之前计算元素的结束位置?

标签 javascript css algorithm matrix transform

我需要在 css transform: matrix() 之前计算元素的结束边界矩形应用了变换。我真的不知道从哪里开始,也找不到任何好的文章来解决这个问题。
所以假设你有元素的原始位置 getBoundingClientRect()如果您有应该应用的矩阵,是否有可靠的方法来找到结束位置。
我已经构建了一个滚动 Controller ,我正在尝试通过屏幕映射元素进度,但我需要元素的开始和结束位置。所以我需要在应用 css 转换后元素的位置来确定元素何时离开屏幕。现在我只是应用矩阵然后运行getBoundingClientRect()再次。但这似乎有点骇人听闻。
所以假设你有原始和结束矩阵。然后运行 ​​getBoundingClientRect()在元素上找到它的位置。有没有一种数学方法来计算新的边界矩形?
所以对于这个例子,我们将只使用一个 6 值矩阵。但也可以将其应用于完整的 16 值矩阵:

const boundingRect = element.getBoundingClientRect();
const startingMatrix = [1, 0, 0, 1, 0, 0];
const endingMatrix = [2, 1, -1, 2, 200, 400];

// Now calculate the new bounding rect of element after ending matrix is applied.
我根据这篇文章尝试了以下 https://dev.opera.com/articles/understanding-the-css-transforms-matrix/由下面的评论推荐。有一些我显然遗漏或不理解的东西。这是我的尝试:

const applyToPoint = (matrix, point) => {
  const multiplied = [
    matrix[0] * point[0],
    matrix[1] * point[1],
    matrix[2] * point[0],
    matrix[3] * point[1],
    matrix[4] * point[0],
    matrix[5] * point[1]
  ]

  const result = [
    multiplied[0] + multiplied[2] + multiplied[4],
    multiplied[1] + multiplied[3] + multiplied[5]
  ]

  return result
}

const box = document.querySelector('.box')

const startingMatrix = [1, 0, 0, 1, 0, 0]
box.style.transform = `matrix(1,0,0,1,0,0)`
const startingRect = box.getBoundingClientRect()

const endingMatrix = [2, 1, -1, 2, 200, 400]
box.style.transform = `matrix(2,1,-1,2,200,400)`
const endingRect = box.getBoundingClientRect()

const newPoint = applyToPoint(endingMatrix, [startingRect.x, startingRect.y])

console.log(newPoint, endingRect)
.box {
  height: 50px;
  width: 50px;
  background: green;
  margin: 50px 0;
}
<div class="box"></div>

我也试过:
const applyToPoint = (matrix, point) => [
  matrix[0] * point[0] + matrix[2] * point[1] + matrix[4],
  matrix[1] * point[0] + matrix[3] * point[1] + matrix[5]
]
任何帮助,将不胜感激。或指向正确方向的指针。

最佳答案

问题是您正在混合两个不同的坐标系:

  • 客户端系统(由 getBoundingClientRect() 使用)
  • 本地系统(由 transform 使用)

  • linked article 中所述,
    本地系统的原点是元素的中心:

    When a transform is applied to an object, it creates a local coordinate system. By default, the origin — the (0,0) point — of the local coordinate system lies at the object's center


    让我们调用[xc, yc]元素的中心。
    要转换一个点(在客户端系统中表示),您需要执行以下操作:
  • 将坐标从客户端转换为本地系统(通过减去 xcyc )
  • 应用变换矩阵
  • 将结果坐标从本地转换回客户端(通过添加 xcyc )

  • 这是一个转换 4 个框 Angular 并计算相关边界框的代码:
    var matrix = [2, 1, -1, 2, 200, 400];
    
    var box = document.querySelector('.box');
    var startingRect = box.getBoundingClientRect();
    var xc = startingRect.left + startingRect.width/2;
    var yc = startingRect.top + startingRect.height/2;
    
    const applyMatrix = (matrix, point) => [
      matrix[0] * point[0] + matrix[2] * point[1] + matrix[4],
      matrix[1] * point[0] + matrix[3] * point[1] + matrix[5]
    ];
    const clientToLocal = (point) => [point[0] - xc, point[1] - yc];
    const localToClient = (point) => [point[0] + xc, point[1] + yc];
    const transformPoint = (point) => localToClient(applyMatrix(matrix, clientToLocal(point)));
    
    function getBoundingBox(pt1, pt2, pt3, pt4)
    {
        var x1 = Math.min(pt1[0], pt2[0], pt3[0], pt4[0]);
        var y1 = Math.min(pt1[1], pt2[1], pt3[1], pt4[1]);
        var x2 = Math.max(pt1[0], pt2[0], pt3[0], pt4[0]);
        var y2 = Math.max(pt1[1], pt2[1], pt3[1], pt4[1]);
        return {x: x1, y: y1, width: x2 - x1, height: y2 - y1};
    }
    
    var topLeft = [startingRect.left, startingRect.top];
    var topRight = [startingRect.right, startingRect.top];
    var bottomLeft = [startingRect.left, startingRect.bottom];
    var bottomRight = [startingRect.right, startingRect.bottom];
    var transformedBox = getBoundingBox(transformPoint(topLeft), transformPoint(topRight), transformPoint(bottomLeft), transformPoint(bottomRight));
    console.log(transformedBox);
    
    box.style.transform = 'matrix('+matrix.join()+')';
    var endingRect = box.getBoundingClientRect();
    console.log(endingRect);
    
    输出:
    {x: 158, y: 400, width: 150, height: 150}
    DOMRect {x: 158, y: 400, width: 150, height: 150, top: 400, …}
    

    关于javascript - 有没有办法在应用 css 变换矩阵之前计算元素的结束位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71050881/

    相关文章:

    javascript - ajax发布到php并没有真正写入mysql表

    CSS 动画辅助

    jquery - 如何为网格中的图像添加内部阴影?

    python - 在 Python 中挂载单词出现列表的有效方法

    javascript - 重复的 CSS 类?

    javascript - 使用 WEBGL 构建 3D 形状时,JS 数组是否有限制?

    java - 在我的案例中,我可以在不循环遍历所有前面元素的情况下计算一个元素吗(参见问题正文)?

    java - 绘制填充多维数组

    javascript - 为什么 Knex.js 返回 max ('value' ) 作为数组?

    css - 以透明背景居中 IE9 模态框,为什么需要相对位置?