Anonymous
Треугольники JavaScript неправильно масштабируются
Сообщение
Anonymous » 29 апр 2024, 04:27
Я работаю над эффектом, который создает множество точек и триангулирует их для создания простой фоновой анимации. Однако когда я пытаюсь их уменьшить, не все строки масштабируются соответствующим образом и часто не совпадают.
Вот код, который создает все
Код: Выделить всё
const numNodes = 40;
let ac = [];
let moveAC = [];
const gradient = {
len: 6,
gradients: [
[225, 238, 88],
[0, 188, 212],
[229, 115, 115],
[74, 20, 140],
[129, 199, 132],
[255, 255, 255]
]
}
let grad1 = Math.round(Math.random() * (gradient.len - 1));
let grad2 = Math.round(Math.random() * (gradient.len - 1));
while (grad1 == grad2) {
grad2 = Math.round(Math.random() * (gradient.len - 1));
}
console.log(grad1, grad2);
grad1 = gradient.gradients[grad1];
grad2 = gradient.gradients[grad2];
function initialize_background() {
for (let i = 0; i < numNodes; i++) {
let posX = Math.random() * 100;
let posY = Math.random() * 100;
let coord = [posX, posY]
ac.push(coord);
let vecX = Math.random() * 2 - 1;
let vecY = Math.random() * 2 - 1;
let vector = [vecX, vecY];
moveAC.push(vector);
}
let edgeSmooth = 10;
for (let i = 1; i < edgeSmooth; i++) {
let pos = (i / edgeSmooth) * 100;
ac.push([pos, 0]);
ac.push([pos, 100]);
ac.push([0, pos]);
ac.push([100, pos]);
moveAC.push([0, 0]);
moveAC.push([0, 0]);
moveAC.push([0, 0]);
moveAC.push([0, 0]);
}
ac.push([0, 0]);
ac.push([0, 100]);
ac.push([100, 0]);
ac.push([100, 100]);
moveAC.push([0, 0]);
moveAC.push([0, 0]);
moveAC.push([0, 0]);
moveAC.push([0, 0]);
updateBackground();
}
function updateElementPosition(element, index) {
let speed = 0.1;
let newX = element[0] + moveAC[index][0]*speed;
let newY = element[1] + moveAC[index][1]*speed;
newX = (newX < 0)? 100 : ((newX > 100)? 0 : newX);
newY = (newY < 0)? 100 : ((newY > 100)? 0 : newY);
ac[index] = [newX, newY];
}
async function updateBackground() {
document.querySelectorAll(".triangle").forEach((element) => {
element.remove();
});
for (let i = 0; i < ac.length; i++) {
updateElementPosition(ac[i], i);
}
let triangles = orderCoordinatesToTriangles();
const docFrag = document.createDocumentFragment();
triangles.forEach((element) => {
let child = createTriangle(ac[element[0]], ac[element[1]], ac[element[2]], element[4]);
if (child != null) docFrag.appendChild(child);
});
document.getElementById("background-container").appendChild(docFrag);
await delay(25);
updateBackground();
}
function orderCoordinatesToTriangles() {
let triangles = [];
for (let e1 = 0; e1 < ac.length; e1 ++) {
for (let e2 = e1+1; e2 < ac.length; e2 ++) {
for (let e3 = e2+1; e3 < ac.length; e3 ++) {
let coord = sortToCounterClockwise(e1, e2, e3, ac);
let anyPointsWithin = false;
for (let e4 = 0; e4 < ac.length; e4 ++) {
if (e1 == e4 || e2 == e4 || e3 == e4) {
continue;
}
if (calculateDeterminant3x3(coord, e4)) {
anyPointsWithin = true;
break;
}
}
if (!anyPointsWithin) {
triangles.push(coord);
}
}
}
}
return triangles;
}
function calculateDeterminant3x3(coord, e4) {
const ax = ac[(coord[0])][0];
const ay = ac[coord[0]][1];
const bx = ac[coord[1]][0];
const by = ac[coord[1]][1];
const cx = ac[coord[2]][0];
const cy = ac[coord[2]][1];
const dx = ac[e4][0];
const dy = ac[e4][1];
const det1 = (ax-dx) * calculateDeterminant2x2((by-dy), calcDifferentDet(bx, dx, by, dy), (cy-dy), calcDifferentDet(cx, dx, cy, dy));
const det2 = (ay-dy) * calculateDeterminant2x2((bx-dx), calcDifferentDet(bx, dx, by, dy), (cx-dx), calcDifferentDet(cx, dx, cy, dy));
const det3 = calcDifferentDet(ax, dx, ay, dy) * calculateDeterminant2x2((bx-dx), (by-dy), (cx-dx), (cy-dy));
const result = det1 - det2 + det3;
return (result > 0);
}
// returns (e1 - e2)^2 + (e3 - e4)^2
function calcDifferentDet(e1, e2, e3, e4) {
return Math.pow(e1 - e2, 2) + Math.pow(e3 - e4, 2);
}
// | e1, e2 |
// | e3, e4 |
function calculateDeterminant2x2(e1, e2, e3, e4) {
return ((e1 * e4) - (e2*e3));
}
function sortToCounterClockwise(e1, e2, e3, ac) {
let coord = [];
const centerX = (ac[e1][0] + ac[e2][0] + ac[e3][0])/3;
const centerY = (ac[e1][1] + ac[e2][1] + ac[e3][1])/3;
let angle1 = get_angle([ac[e1][0] - centerX, ac[e1][1] - centerY]);
let angle2 = get_angle([ac[e2][0] - centerX, ac[e2][1] - centerY]);
let angle3 = get_angle([ac[e3][0] - centerX, ac[e3][1] - centerY]);
if (angle1 < 90) angle1 += 360;
if (angle2 < 90) angle2 += 360;
if (angle3 < 90) angle3 += 360;
if (angle1 < angle2 && angle1 < angle3) {
coord.push(e1);
if (angle2 < angle3) {coord.push(e2); coord.push(e3);}
else {coord.push(e3); coord.push(e2);}
}
else if (angle2 < angle1 && angle2 < angle3) {
coord.push(e2);
if (angle1 < angle3) {coord.push(e1); coord.push(e3);}
else {coord.push(e3); coord.push(e1);}
}
else {
coord.push(e3);
if (angle1 < angle2) {coord.push(e1); coord.push(e2);}
else {coord.push(e2); coord.push(e1);}
}
coord.push(centerX);
coord.push(centerY);
return coord;
}
const getScale = (cX, cY, pX, pY, s) => {
sSx = window.innerWidth;
sSy = window.innerHeight;
v = make_vector([pX, pY], [cX, cY]);
u = unit_vector(v);
return (pX + s*u[0])*sSx/100 + "px " + (pY+ s*u[1])*sSy/100 + "px";
}
function createTriangle(p1, p2, p3, centerY) {
const newTriangle = document.createElement("div");
newTriangle.className = "triangle";
let cX = (p1[0] + p2[0] + p3[0]) / 3;
let cY = ((p1[1]) + (p2[1]) + (p3[1])) / 3;
let scale = 0.2;
coord1 = getScale(cX, cY, p1[0], (p1[1]), scale);
coord2 = getScale(cX, cY, p2[0], (p2[1]), scale);
coord3 = getScale(cX, cY, p3[0], (p3[1]), scale);
newTriangle.style.backgroundColor = "rgb(" + colourFunction(0, centerY) + ", " + colourFunction(1, centerY) + ", " + colourFunction(2, centerY) + ")";
newTriangle.style.clipPath = "polygon(" + coord1 + ", " + coord2 + ", " + coord3 + ")";
if (!newTriangle.style.clipPath) {
return null;
}
return newTriangle;
}
function colourFunction(i, cY) {
return (grad1[i] + ((grad2[i] - grad1[i]) * (1 - (cY / 100))));
}
А код векторов следующий
Код: Выделить всё
//Turn current position into a vector given a vector matrix
const get_vector = (e1, e2, a) => {
const wa = a[e2][1] - a[e1][1];
const wb = a[e2][0] - a[e1][0];
return [wb, wa];
};
//make a vector given arrays
const make_vector = (e1, e2) => {
const wa = e2[1] - e1[1];
const wb = e2[0] - e1[0];
return [wb, wa];
};
//Get current width of a vector
const get_width = (v) => {
const wa = Math.pow(v[0], 2);
const wb = Math.pow(v[1], 2);
return Math.sqrt(wa + wb);
};
//Get current angle of a vector with the line
const get_angle = (v) => {
let angle = Math.acos((v[0] / get_width(v)))*180/Math.PI;
if (v[1] < 0) {angle = 360 - angle;}
return angle;
};
//get unit vector
const unit_vector= (v) => {
let width = get_width(v);
return [v[0]/width, v[1]/width];
};
Однако я получаю нечто похожее на следующий результат:
Один кадр анимации
Некоторые границы толще других, и я не уверен, в чем проблема
Подробнее здесь:
https://stackoverflow.com/questions/784 ... -correctly
1714354042
Anonymous
Я работаю над эффектом, который создает множество точек и триангулирует их для создания простой фоновой анимации. Однако когда я пытаюсь их уменьшить, не все строки масштабируются соответствующим образом и часто не совпадают. Вот код, который создает все [code]const numNodes = 40; let ac = []; let moveAC = []; const gradient = { len: 6, gradients: [ [225, 238, 88], [0, 188, 212], [229, 115, 115], [74, 20, 140], [129, 199, 132], [255, 255, 255] ] } let grad1 = Math.round(Math.random() * (gradient.len - 1)); let grad2 = Math.round(Math.random() * (gradient.len - 1)); while (grad1 == grad2) { grad2 = Math.round(Math.random() * (gradient.len - 1)); } console.log(grad1, grad2); grad1 = gradient.gradients[grad1]; grad2 = gradient.gradients[grad2]; function initialize_background() { for (let i = 0; i < numNodes; i++) { let posX = Math.random() * 100; let posY = Math.random() * 100; let coord = [posX, posY] ac.push(coord); let vecX = Math.random() * 2 - 1; let vecY = Math.random() * 2 - 1; let vector = [vecX, vecY]; moveAC.push(vector); } let edgeSmooth = 10; for (let i = 1; i < edgeSmooth; i++) { let pos = (i / edgeSmooth) * 100; ac.push([pos, 0]); ac.push([pos, 100]); ac.push([0, pos]); ac.push([100, pos]); moveAC.push([0, 0]); moveAC.push([0, 0]); moveAC.push([0, 0]); moveAC.push([0, 0]); } ac.push([0, 0]); ac.push([0, 100]); ac.push([100, 0]); ac.push([100, 100]); moveAC.push([0, 0]); moveAC.push([0, 0]); moveAC.push([0, 0]); moveAC.push([0, 0]); updateBackground(); } function updateElementPosition(element, index) { let speed = 0.1; let newX = element[0] + moveAC[index][0]*speed; let newY = element[1] + moveAC[index][1]*speed; newX = (newX < 0)? 100 : ((newX > 100)? 0 : newX); newY = (newY < 0)? 100 : ((newY > 100)? 0 : newY); ac[index] = [newX, newY]; } async function updateBackground() { document.querySelectorAll(".triangle").forEach((element) => { element.remove(); }); for (let i = 0; i < ac.length; i++) { updateElementPosition(ac[i], i); } let triangles = orderCoordinatesToTriangles(); const docFrag = document.createDocumentFragment(); triangles.forEach((element) => { let child = createTriangle(ac[element[0]], ac[element[1]], ac[element[2]], element[4]); if (child != null) docFrag.appendChild(child); }); document.getElementById("background-container").appendChild(docFrag); await delay(25); updateBackground(); } function orderCoordinatesToTriangles() { let triangles = []; for (let e1 = 0; e1 < ac.length; e1 ++) { for (let e2 = e1+1; e2 < ac.length; e2 ++) { for (let e3 = e2+1; e3 < ac.length; e3 ++) { let coord = sortToCounterClockwise(e1, e2, e3, ac); let anyPointsWithin = false; for (let e4 = 0; e4 < ac.length; e4 ++) { if (e1 == e4 || e2 == e4 || e3 == e4) { continue; } if (calculateDeterminant3x3(coord, e4)) { anyPointsWithin = true; break; } } if (!anyPointsWithin) { triangles.push(coord); } } } } return triangles; } function calculateDeterminant3x3(coord, e4) { const ax = ac[(coord[0])][0]; const ay = ac[coord[0]][1]; const bx = ac[coord[1]][0]; const by = ac[coord[1]][1]; const cx = ac[coord[2]][0]; const cy = ac[coord[2]][1]; const dx = ac[e4][0]; const dy = ac[e4][1]; const det1 = (ax-dx) * calculateDeterminant2x2((by-dy), calcDifferentDet(bx, dx, by, dy), (cy-dy), calcDifferentDet(cx, dx, cy, dy)); const det2 = (ay-dy) * calculateDeterminant2x2((bx-dx), calcDifferentDet(bx, dx, by, dy), (cx-dx), calcDifferentDet(cx, dx, cy, dy)); const det3 = calcDifferentDet(ax, dx, ay, dy) * calculateDeterminant2x2((bx-dx), (by-dy), (cx-dx), (cy-dy)); const result = det1 - det2 + det3; return (result > 0); } // returns (e1 - e2)^2 + (e3 - e4)^2 function calcDifferentDet(e1, e2, e3, e4) { return Math.pow(e1 - e2, 2) + Math.pow(e3 - e4, 2); } // | e1, e2 | // | e3, e4 | function calculateDeterminant2x2(e1, e2, e3, e4) { return ((e1 * e4) - (e2*e3)); } function sortToCounterClockwise(e1, e2, e3, ac) { let coord = []; const centerX = (ac[e1][0] + ac[e2][0] + ac[e3][0])/3; const centerY = (ac[e1][1] + ac[e2][1] + ac[e3][1])/3; let angle1 = get_angle([ac[e1][0] - centerX, ac[e1][1] - centerY]); let angle2 = get_angle([ac[e2][0] - centerX, ac[e2][1] - centerY]); let angle3 = get_angle([ac[e3][0] - centerX, ac[e3][1] - centerY]); if (angle1 < 90) angle1 += 360; if (angle2 < 90) angle2 += 360; if (angle3 < 90) angle3 += 360; if (angle1 < angle2 && angle1 < angle3) { coord.push(e1); if (angle2 < angle3) {coord.push(e2); coord.push(e3);} else {coord.push(e3); coord.push(e2);} } else if (angle2 < angle1 && angle2 < angle3) { coord.push(e2); if (angle1 < angle3) {coord.push(e1); coord.push(e3);} else {coord.push(e3); coord.push(e1);} } else { coord.push(e3); if (angle1 < angle2) {coord.push(e1); coord.push(e2);} else {coord.push(e2); coord.push(e1);} } coord.push(centerX); coord.push(centerY); return coord; } const getScale = (cX, cY, pX, pY, s) => { sSx = window.innerWidth; sSy = window.innerHeight; v = make_vector([pX, pY], [cX, cY]); u = unit_vector(v); return (pX + s*u[0])*sSx/100 + "px " + (pY+ s*u[1])*sSy/100 + "px"; } function createTriangle(p1, p2, p3, centerY) { const newTriangle = document.createElement("div"); newTriangle.className = "triangle"; let cX = (p1[0] + p2[0] + p3[0]) / 3; let cY = ((p1[1]) + (p2[1]) + (p3[1])) / 3; let scale = 0.2; coord1 = getScale(cX, cY, p1[0], (p1[1]), scale); coord2 = getScale(cX, cY, p2[0], (p2[1]), scale); coord3 = getScale(cX, cY, p3[0], (p3[1]), scale); newTriangle.style.backgroundColor = "rgb(" + colourFunction(0, centerY) + ", " + colourFunction(1, centerY) + ", " + colourFunction(2, centerY) + ")"; newTriangle.style.clipPath = "polygon(" + coord1 + ", " + coord2 + ", " + coord3 + ")"; if (!newTriangle.style.clipPath) { return null; } return newTriangle; } function colourFunction(i, cY) { return (grad1[i] + ((grad2[i] - grad1[i]) * (1 - (cY / 100)))); } [/code] А код векторов следующий [code]//Turn current position into a vector given a vector matrix const get_vector = (e1, e2, a) => { const wa = a[e2][1] - a[e1][1]; const wb = a[e2][0] - a[e1][0]; return [wb, wa]; }; //make a vector given arrays const make_vector = (e1, e2) => { const wa = e2[1] - e1[1]; const wb = e2[0] - e1[0]; return [wb, wa]; }; //Get current width of a vector const get_width = (v) => { const wa = Math.pow(v[0], 2); const wb = Math.pow(v[1], 2); return Math.sqrt(wa + wb); }; //Get current angle of a vector with the line const get_angle = (v) => { let angle = Math.acos((v[0] / get_width(v)))*180/Math.PI; if (v[1] < 0) {angle = 360 - angle;} return angle; }; //get unit vector const unit_vector= (v) => { let width = get_width(v); return [v[0]/width, v[1]/width]; }; [/code] Однако я получаю нечто похожее на следующий результат: Один кадр анимации Некоторые границы толще других, и я не уверен, в чем проблема Подробнее здесь: [url]https://stackoverflow.com/questions/78400124/javascript-triangles-not-scaling-correctly[/url]