Update static/js/solar_animation.js
Browse files- static/js/solar_animation.js +30 -16
static/js/solar_animation.js
CHANGED
@@ -235,6 +235,7 @@ function drawLinearFlow(points, offset, arrowSize = 10, reverse = false) {
|
|
235 |
// Tính toán tổng chiều dài đường dẫn
|
236 |
let totalLength = 0;
|
237 |
const segmentLengths = [];
|
|
|
238 |
for (let i = 0; i < points.length - 1; i++) {
|
239 |
const segLen = Math.sqrt(
|
240 |
Math.pow(points[i+1].x - points[i].x, 2) +
|
@@ -242,49 +243,62 @@ function drawLinearFlow(points, offset, arrowSize = 10, reverse = false) {
|
|
242 |
);
|
243 |
segmentLengths.push(segLen);
|
244 |
totalLength += segLen;
|
|
|
245 |
}
|
246 |
|
247 |
const numArrows = Math.floor(totalLength / (arrowSize * 2.5));
|
|
|
248 |
const arrowSpacing = totalLength / numArrows;
|
249 |
|
250 |
for (let i = 0; i < numArrows; i++) {
|
251 |
let currentPathPos = (offset + i * arrowSpacing);
|
252 |
-
|
253 |
-
currentPathPos = totalLength - currentPathPos; // Đảo ngược hướng cho mũi tên
|
254 |
-
}
|
255 |
currentPathPos = currentPathPos % totalLength;
|
256 |
if (currentPathPos < 0) currentPathPos += totalLength;
|
257 |
|
258 |
-
|
|
|
|
|
|
|
|
|
|
|
259 |
let p1 = null, p2 = null;
|
260 |
-
let
|
|
|
261 |
|
262 |
// Tìm đoạn đường mà mũi tên đang ở trên
|
263 |
for (let j = 0; j < points.length - 1; j++) {
|
264 |
-
|
265 |
-
if (currentPathPos >= segmentLengthAccumulated && currentPathPos <= segmentLengthAccumulated + segLen) {
|
266 |
p1 = points[j];
|
267 |
p2 = points[j+1];
|
268 |
-
|
|
|
269 |
break;
|
270 |
}
|
271 |
-
segmentLengthAccumulated += segLen;
|
272 |
}
|
273 |
|
274 |
-
if (p1 && p2) {
|
275 |
const dx = p2.x - p1.x;
|
276 |
const dy = p2.y - p1.y;
|
277 |
-
const
|
278 |
-
const ratio = segLen > 0 ? segmentRelativePos / segLen : 0;
|
279 |
|
280 |
const arrowX = p1.x + dx * ratio;
|
281 |
const arrowY = p1.y + dy * ratio;
|
282 |
|
283 |
let angle = Math.atan2(dy, dx);
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
|
289 |
ctx.save();
|
290 |
ctx.translate(arrowX, arrowY);
|
|
|
235 |
// Tính toán tổng chiều dài đường dẫn
|
236 |
let totalLength = 0;
|
237 |
const segmentLengths = [];
|
238 |
+
const segmentStartLengths = [0]; // Lưu trữ điểm bắt đầu của mỗi đoạn
|
239 |
for (let i = 0; i < points.length - 1; i++) {
|
240 |
const segLen = Math.sqrt(
|
241 |
Math.pow(points[i+1].x - points[i].x, 2) +
|
|
|
243 |
);
|
244 |
segmentLengths.push(segLen);
|
245 |
totalLength += segLen;
|
246 |
+
segmentStartLengths.push(totalLength);
|
247 |
}
|
248 |
|
249 |
const numArrows = Math.floor(totalLength / (arrowSize * 2.5));
|
250 |
+
if (numArrows === 0) return; // Không vẽ mũi tên nếu đường quá ngắn
|
251 |
const arrowSpacing = totalLength / numArrows;
|
252 |
|
253 |
for (let i = 0; i < numArrows; i++) {
|
254 |
let currentPathPos = (offset + i * arrowSpacing);
|
255 |
+
// Đảm bảo currentPathPos luôn dương và nằm trong phạm vi totalLength
|
|
|
|
|
256 |
currentPathPos = currentPathPos % totalLength;
|
257 |
if (currentPathPos < 0) currentPathPos += totalLength;
|
258 |
|
259 |
+
// Nếu reverse, thì bắt đầu từ cuối đường và đi ngược lại
|
260 |
+
if (reverse) {
|
261 |
+
currentPathPos = totalLength - currentPathPos;
|
262 |
+
if (currentPathPos < 0) currentPathPos += totalLength; // Đảm bảo vẫn dương
|
263 |
+
}
|
264 |
+
|
265 |
let p1 = null, p2 = null;
|
266 |
+
let segmentRelativePos = 0;
|
267 |
+
let segLen = 0;
|
268 |
|
269 |
// Tìm đoạn đường mà mũi tên đang ở trên
|
270 |
for (let j = 0; j < points.length - 1; j++) {
|
271 |
+
if (currentPathPos >= segmentStartLengths[j] && currentPathPos <= segmentStartLengths[j+1]) {
|
|
|
272 |
p1 = points[j];
|
273 |
p2 = points[j+1];
|
274 |
+
segLen = segmentLengths[j];
|
275 |
+
segmentRelativePos = currentPathPos - segmentStartLengths[j];
|
276 |
break;
|
277 |
}
|
|
|
278 |
}
|
279 |
|
280 |
+
if (p1 && p2 && segLen > 0) { // Đảm bảo tìm thấy đoạn đường và không phải đoạn có chiều dài 0
|
281 |
const dx = p2.x - p1.x;
|
282 |
const dy = p2.y - p1.y;
|
283 |
+
const ratio = segmentRelativePos / segLen;
|
|
|
284 |
|
285 |
const arrowX = p1.x + dx * ratio;
|
286 |
const arrowY = p1.y + dy * ratio;
|
287 |
|
288 |
let angle = Math.atan2(dy, dx);
|
289 |
+
// Angle is naturally set by dx, dy. If 'reverse' means arrow points opposite to path creation,
|
290 |
+
// then we should just use Math.atan2(p1.y - p2.y, p1.x - p2.x) if we need specific visual reverse.
|
291 |
+
// But with currentPathPos handled for reverse, the angle should be naturally correct from p1 to p2.
|
292 |
+
// If the arrow visually needs to point back, add Math.PI.
|
293 |
+
// My current reverse logic handles the *position* of the arrow, not its intrinsic direction.
|
294 |
+
// So if you *still* want the arrow symbol to point backward when reverse=true, you add Math.PI.
|
295 |
+
// For now, let's keep it consistent: the arrow's head points in the direction of path (p1 to p2).
|
296 |
+
// The 'reverse' parameter just makes it *move* against that direction on the path.
|
297 |
+
|
298 |
+
// If the desired visual effect for 'reverse' is for the arrow HEAD to point backwards, uncomment this:
|
299 |
+
// if (reverse) {
|
300 |
+
// angle += Math.PI;
|
301 |
+
// }
|
302 |
|
303 |
ctx.save();
|
304 |
ctx.translate(arrowX, arrowY);
|