Я пытаюсь создать функцию, которая использует Css matrix3d для преобразования элементов при прокрутке. Я использую библиотеку rematrix, найденную здесь ReMatrix , чтобы вычислить матрицу, а затем использовать прогресс в процентах в функции прокрутки, чтобы вычислить процент перемещения элемента по сцене. Все это прекрасно работает.
Проблема заключается в том, что при повороте элемента кажется, что он сжимается, а затем возвращается к нормальному размеру по мере развития сцены. Это ожидаемое поведение matrix3d?
Некоторые из начальных значений в 3dmatrix равны 1, поэтому я учитываю это, прибавляя 1, затем вычитая 1. Он отлично работает для всего, кроме вращения.
Я упускаю что-то в математике, что я слишком глуп, чтобы понять, что оно начинается и заканчивается на правильном значении, но сжимается и растет по всей сцене.
Вот пример скрипты и фрагмента Fiddle Демо
Примечание: я просто использую 700px для продвижения сцены в демо. Вы можете игнорировать эффекты после прокрутки 700px или когда коробка поворачивается на 90 градусов, это просто демонстрация.
let matrix;
const el = document.querySelector('.box');
const updateScroll = () => {
const scrollPos = window.scrollY;
const progress = scrollPos / 700;
let m = [...matrix];
m[0] = progress * (matrix[0] - 1) + 1;
m[1] = progress * matrix[1];
m[2] = progress * matrix[2];
m[3] = progress * matrix[3];
m[4] = progress * matrix[4];
m[5] = progress * (matrix[5] - 1) + 1;
m[6] = progress * matrix[6];
m[7] = progress * matrix[7];
m[8] = progress * matrix[8];
m[9] = progress * matrix[9];
m[10] = progress * (matrix[10] - 1) + 1;
m[11] = progress * matrix[11];
m[12] = progress * (matrix[12] / 100) * 100;
m[13] = progress * (matrix[13] / 100) * 100;
m[14] = progress * (matrix[14] / 100) * 100;
m[15] = progress * (matrix[15] - 1) + 1;
setTransform(el, toString(m));
}
const init = () => {
const r1 = rotateZ(90);
const t1 = translateY(700);
matrix = multiply(t1,r1);
window.addEventListener('scroll', updateScroll);
}
const setTransform = (el, transform) => {
el.style.transform = transform;
el.style.WebkitTransform = transform;
};
/*
*
* REMATRIX Functions
* https://github.com/jlmakes/rematrix
*
*/
function translateY(distance) {
const matrix = identity();
matrix[13] = distance;
return matrix;
}
function toString(source) {
return `matrix3d(${format(source).join(', ')})`;
}
function rotateZ(angle) {
const theta = (Math.PI / 180) * angle;
const matrix = identity();
matrix[0] = matrix[5] = Math.cos(theta).toFixed(6);
matrix[1] = matrix[4] = Math.sin(theta).toFixed(6);
matrix[4] *= -1;
return matrix;
}
function format(source) {
if (source.constructor !== Array) {
throw new TypeError('Expected array.');
}
if (source.length === 16) {
return source;
}
if (source.length === 6) {
const matrix = identity();
matrix[0] = source[0];
matrix[1] = source[1];
matrix[4] = source[2];
matrix[5] = source[3];
matrix[12] = source[4];
matrix[13] = source[5];
return matrix;
}
throw new RangeError('Expected array with either 6 or 16 values.');
}
function identity() {
const matrix = [];
for (let i = 0; i < 16; i++) {
i % 5 == 0 ? matrix.push(1) : matrix.push(0);
}
return matrix;
}
function multiply(m, x) {
const fm = format(m);
const fx = format(x);
const product = [];
for (let i = 0; i < 4; i++) {
const row = [fm[i], fm[i + 4], fm[i + 8], fm[i + 12]];
for (let j = 0; j < 4; j++) {
const k = j * 4;
const col = [fx[k], fx[k + 1], fx[k + 2], fx[k + 3]];
const result =
row[0] * col[0] + row[1] * col[1] + row[2] * col[2] + row[3] * col[3];
product[i + k] = result;
}
}
return product;
}
init();
body{
min-height: 400vh;
}
.box{
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
margin: auto;
width: 100px;
height: 100px;
background: green;
}
<div class="box"></div>
Любая помощь здесь будет оценена. Спасибо.