futranbg commited on
Commit
6b04035
·
verified ·
1 Parent(s): 332f20e

Update static/js/solar_animation.js

Browse files
Files changed (1) hide show
  1. static/js/solar_animation.js +63 -50
static/js/solar_animation.js CHANGED
@@ -6,13 +6,13 @@ const ctx = canvas.getContext('2d');
6
  let animationFrameId;
7
  let energyFlowOffset = 0; // Dịch chuyển để tạo hiệu ứng dòng chảy của mũi tên
8
 
9
- // Kích thước và vị trí các thành phần
10
  const solarPanel = { x: 50, y: 50, width: 120, height: 90 };
11
- const inverter = { x: 280, y: 150, width: 90, height: 70 };
12
- const battery = { x: 480, y: 250, width: 80, height: 110 };
13
- const homeLoad = { x: 650, y: 150, width: 80, height: 70 };
14
- const grid = { x: 400, y: 50, width: 100, height: 70 }; // Lưới điện
15
- const generator = { x: 100, y: 250, width: 100, height: 70 }; // Máy phát điện
16
 
17
  // Định nghĩa màu sắc và thuộc tính
18
  const colors = {
@@ -93,16 +93,18 @@ function drawInverterIcon(x, y, width, height) {
93
 
94
  // Các cổng kết nối
95
  ctx.fillStyle = colors.inverterAccent;
96
- ctx.fillRect(x - 5, y + height * 0.2, 5, 10); // Cổng vào DC
97
- ctx.fillRect(x + width, y + height * 0.7, 5, 10); // Cổng ra AC
 
 
98
 
99
  // Ký hiệu DC/AC
100
  ctx.fillStyle = '#FFF';
101
  ctx.font = 'bold 12px Arial';
102
  ctx.textAlign = 'center';
103
  ctx.textBaseline = 'middle';
104
- ctx.fillText('DC', x + width * 0.25, y + height / 2);
105
- ctx.fillText('AC', x + width * 0.75, y + height / 2);
106
 
107
  ctx.fillStyle = colors.text;
108
  ctx.fillText('Biến tần', x + width / 2, y + height + 20);
@@ -216,7 +218,7 @@ function drawGeneratorIcon(x, y, width, height) {
216
 
217
  // --- Hàm vẽ các đường thẳng/ngang và mũi tên di chuyển ---
218
 
219
- function drawLinearFlow(points, offset, arrowSize = 10) {
220
  ctx.strokeStyle = colors.flowPrimary;
221
  ctx.lineWidth = 4;
222
  ctx.beginPath();
@@ -232,49 +234,57 @@ function drawLinearFlow(points, offset, arrowSize = 10) {
232
 
233
  // Tính toán tổng chiều dài đường dẫn
234
  let totalLength = 0;
 
235
  for (let i = 0; i < points.length - 1; i++) {
236
- totalLength += Math.sqrt(
237
  Math.pow(points[i+1].x - points[i].x, 2) +
238
  Math.pow(points[i+1].y - points[i].y, 2)
239
  );
 
 
240
  }
241
 
242
  const numArrows = Math.floor(totalLength / (arrowSize * 2.5));
243
  const arrowSpacing = totalLength / numArrows;
244
 
245
  for (let i = 0; i < numArrows; i++) {
246
- let currentPathPos = (offset + i * arrowSpacing) % totalLength;
 
 
 
 
247
  if (currentPathPos < 0) currentPathPos += totalLength;
248
 
249
- let segmentLength = 0;
250
  let p1 = null, p2 = null;
251
  let segmentIndex = -1;
252
 
253
  // Tìm đoạn đường mà mũi tên đang ở trên
254
  for (let j = 0; j < points.length - 1; j++) {
255
- const segLen = Math.sqrt(
256
- Math.pow(points[j+1].x - points[j].x, 2) +
257
- Math.pow(points[j+1].y - points[j].y, 2)
258
- );
259
- if (currentPathPos >= segmentLength && currentPathPos <= segmentLength + segLen) {
260
  p1 = points[j];
261
  p2 = points[j+1];
262
  segmentIndex = j;
263
  break;
264
  }
265
- segmentLength += segLen;
266
  }
267
 
268
  if (p1 && p2) {
269
  const dx = p2.x - p1.x;
270
  const dy = p2.y - p1.y;
271
- const segmentRelativePos = currentPathPos - segmentLength;
272
  const ratio = segLen > 0 ? segmentRelativePos / segLen : 0;
273
 
274
  const arrowX = p1.x + dx * ratio;
275
  const arrowY = p1.y + dy * ratio;
276
 
277
- const angle = Math.atan2(dy, dx);
 
 
 
 
278
 
279
  ctx.save();
280
  ctx.translate(arrowX, arrowY);
@@ -303,57 +313,60 @@ function draw() {
303
  drawInverterIcon(inverter.x, inverter.y, inverter.width, inverter.height);
304
  drawBatteryIcon(battery.x, battery.y, battery.width, battery.height);
305
  drawHomeIcon(homeLoad.x, homeLoad.y, homeLoad.width, homeLoad.height);
306
- drawGridIcon(grid.x, grid.y, grid.width, grid.height); // Lưới điện
307
- drawGeneratorIcon(generator.x, generator.y, generator.width, generator.height); // Máy phát điện
308
 
309
  // Vẽ luồng năng lượng bằng đường thẳng/ngang
310
  // 1. Tấm pin -> Biến tần (DC)
311
  drawLinearFlow([
312
- { x: solarPanel.x + solarPanel.width / 2, y: solarPanel.y + solarPanel.height },
313
- { x: solarPanel.x + solarPanel.width / 2, y: inverter.y + inverter.height / 2 },
314
- { x: inverter.x, y: inverter.y + inverter.height / 2 }
315
  ], energyFlowOffset);
316
 
317
  // 2. Biến tần -> Tải nhà (AC)
318
  drawLinearFlow([
319
- { x: inverter.x + inverter.width, y: inverter.y + inverter.height / 2 },
320
- { x: homeLoad.x, y: homeLoad.y + homeLoad.height / 2 }
321
  ], energyFlowOffset);
322
 
323
  // 3. Biến tần <-> Lưới điện (AC)
 
324
  drawLinearFlow([
325
- { x: inverter.x + inverter.width / 2, y: inverter.y },
326
- { x: inverter.x + inverter.width / 2, y: grid.y + grid.height / 2 },
327
- { x: grid.x, y: grid.y + grid.height / 2 }
328
- ], energyFlowOffset); // Biến tần -> Lưới
329
 
 
330
  drawLinearFlow([
331
- { x: grid.x, y: grid.y + grid.height / 2 }, // Điểm này phải đúng
332
- { x: inverter.x + inverter.width / 2, y: grid.y + grid.height / 2 },
333
- { x: inverter.x + inverter.width / 2, y: inverter.y }
334
- ], -energyFlowOffset); // Lưới -> Biến tần (ngược chiều)
335
-
336
 
337
  // 4. Biến tần <-> Pin lưu trữ (AC/DC)
 
338
  drawLinearFlow([
339
- { x: inverter.x + inverter.width / 2, y: inverter.y + inverter.height },
340
- { x: inverter.x + inverter.width / 2, y: battery.y + battery.height / 2 },
341
- { x: battery.x + battery.width, y: battery.y + battery.height / 2 } // Vị trí kết nối bên phải pin
342
- ], energyFlowOffset); // Biến tần -> Pin
343
 
 
344
  drawLinearFlow([
345
- { x: battery.x + battery.width, y: battery.y + battery.height / 2 },
346
- { x: inverter.x + inverter.width / 2, y: battery.y + battery.height / 2 },
347
- { x: inverter.x + inverter.width / 2, y: inverter.y + inverter.height }
348
- ], -energyFlowOffset); // Pin -> Biến tần (ngược chiều)
349
 
350
- // 5. Máy phát điện -> Biến tần (hoặc thẳng vào nhà nếu không có biến tần, nhưng ở đây kết nối qua biến tần)
 
351
  drawLinearFlow([
352
- { x: generator.x + generator.width, y: generator.y + generator.height / 2 },
353
- { x: inverter.x, y: inverter.y + inverter.height / 2 } // Nối vào biến tần
354
  ], energyFlowOffset);
355
 
356
-
357
  // Cập nhật offset để tạo hoạt hình dòng chảy
358
  energyFlowOffset = (energyFlowOffset + 2) % 100; // Thay đổi tốc độ và khoảng cách mũi tên
359
 
 
6
  let animationFrameId;
7
  let energyFlowOffset = 0; // Dịch chuyển để tạo hiệu ứng dòng chảy của mũi tên
8
 
9
+ // Kích thước và vị trí các thành phần (đã điều chỉnh để có chỗ cho các luồng mới)
10
  const solarPanel = { x: 50, y: 50, width: 120, height: 90 };
11
+ const inverter = { x: 280, y: 150, width: 90, height: 70 }; // Biến tần là trung tâm
12
+ const battery = { x: 50, y: 280, width: 80, height: 110 }; // Pin ở dưới bên trái
13
+ const homeLoad = { x: 650, y: 150, width: 80, height: 70 }; // Tải nhà bên phải
14
+ const grid = { x: 480, y: 50, width: 100, height: 70 }; // Lưới điện ở trên bên phải
15
+ const generator = { x: 280, y: 320, width: 100, height: 70 }; // Máy phát điện ở dưới biến tần
16
 
17
  // Định nghĩa màu sắc và thuộc tính
18
  const colors = {
 
93
 
94
  // Các cổng kết nối
95
  ctx.fillStyle = colors.inverterAccent;
96
+ ctx.fillRect(x - 5, y + height * 0.2, 5, 10); // Cổng vào DC (từ Solar)
97
+ ctx.fillRect(x + width, y + height * 0.7, 5, 10); // Cổng ra AC (tới Home Load)
98
+ ctx.fillRect(x + width * 0.25, y - 5, 10, 5); // Cổng lên Grid
99
+ ctx.fillRect(x + width * 0.75, y + height, 10, 5); // Cổng xuống Battery/Generator
100
 
101
  // Ký hiệu DC/AC
102
  ctx.fillStyle = '#FFF';
103
  ctx.font = 'bold 12px Arial';
104
  ctx.textAlign = 'center';
105
  ctx.textBaseline = 'middle';
106
+ ctx.fillText('DC', x + width * 0.15, y + height / 2); // gần cổng vào DC
107
+ ctx.fillText('AC', x + width * 0.85, y + height / 2); // gần cổng ra AC
108
 
109
  ctx.fillStyle = colors.text;
110
  ctx.fillText('Biến tần', x + width / 2, y + height + 20);
 
218
 
219
  // --- Hàm vẽ các đường thẳng/ngang và mũi tên di chuyển ---
220
 
221
+ function drawLinearFlow(points, offset, arrowSize = 10, reverse = false) {
222
  ctx.strokeStyle = colors.flowPrimary;
223
  ctx.lineWidth = 4;
224
  ctx.beginPath();
 
234
 
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) +
241
  Math.pow(points[i+1].y - points[i].y, 2)
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
+ if (reverse) {
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
+ let segmentLengthAccumulated = 0;
259
  let p1 = null, p2 = null;
260
  let segmentIndex = -1;
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
+ const segLen = segmentLengths[j];
265
+ if (currentPathPos >= segmentLengthAccumulated && currentPathPos <= segmentLengthAccumulated + segLen) {
 
 
 
266
  p1 = points[j];
267
  p2 = points[j+1];
268
  segmentIndex = j;
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 segmentRelativePos = currentPathPos - segmentLengthAccumulated;
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
+ if (reverse) {
285
+ angle += Math.PI; // Xoay mũi tên 180 độ nếu ngược chiều
286
+ }
287
+
288
 
289
  ctx.save();
290
  ctx.translate(arrowX, arrowY);
 
313
  drawInverterIcon(inverter.x, inverter.y, inverter.width, inverter.height);
314
  drawBatteryIcon(battery.x, battery.y, battery.width, battery.height);
315
  drawHomeIcon(homeLoad.x, homeLoad.y, homeLoad.width, homeLoad.height);
316
+ drawGridIcon(grid.x, grid.y, grid.width, grid.height);
317
+ drawGeneratorIcon(generator.x, generator.y, generator.width, generator.height);
318
 
319
  // Vẽ luồng năng lượng bằng đường thẳng/ngang
320
  // 1. Tấm pin -> Biến tần (DC)
321
  drawLinearFlow([
322
+ { x: solarPanel.x + solarPanel.width / 2, y: solarPanel.y + solarPanel.height }, // Dưới pin
323
+ { x: solarPanel.x + solarPanel.width / 2, y: inverter.y + inverter.height * 0.2 }, // Điểm uốn ngang
324
+ { x: inverter.x, y: inverter.y + inverter.height * 0.2 } // Vào biến tần (cổng DC)
325
  ], energyFlowOffset);
326
 
327
  // 2. Biến tần -> Tải nhà (AC)
328
  drawLinearFlow([
329
+ { x: inverter.x + inverter.width, y: inverter.y + inverter.height * 0.7 }, // Ra biến tần (cổng AC)
330
+ { x: homeLoad.x, y: homeLoad.y + homeLoad.height / 2 } // Vào tải nhà
331
  ], energyFlowOffset);
332
 
333
  // 3. Biến tần <-> Lưới điện (AC)
334
+ // Biến tần -> Lưới (Xuất điện)
335
  drawLinearFlow([
336
+ { x: inverter.x + inverter.width * 0.25, y: inverter.y }, // Từ biến tần (cổng lên Grid)
337
+ { x: inverter.x + inverter.width * 0.25, y: grid.y + grid.height / 2 }, // Điểm uốn ngang
338
+ { x: grid.x, y: grid.y + grid.height / 2 } // Vào lưới
339
+ ], energyFlowOffset);
340
 
341
+ // Lưới -> Biến tần (Nhập điện)
342
  drawLinearFlow([
343
+ { x: grid.x, y: grid.y + grid.height / 2 }, // Từ lưới
344
+ { x: inverter.x + inverter.width * 0.25, y: grid.y + grid.height / 2 }, // Điểm uốn ngang
345
+ { x: inverter.x + inverter.width * 0.25, y: inverter.y } // Vào biến tần (cổng lên Grid)
346
+ ], energyFlowOffset, 10, true); // true để đảo ngược hướng mũi tên
 
347
 
348
  // 4. Biến tần <-> Pin lưu trữ (AC/DC)
349
+ // Biến tần -> Pin (Sạc)
350
  drawLinearFlow([
351
+ { x: inverter.x + inverter.width * 0.75, y: inverter.y + inverter.height }, // Từ biến tần (cổng xuống Battery)
352
+ { x: inverter.x + inverter.width * 0.75, y: battery.y + battery.height / 2 }, // Điểm uốn ngang
353
+ { x: battery.x + battery.width, y: battery.y + battery.height / 2 } // Vào pin
354
+ ], energyFlowOffset);
355
 
356
+ // Pin -> Biến tần (Xả)
357
  drawLinearFlow([
358
+ { x: battery.x + battery.width, y: battery.y + battery.height / 2 }, // Từ pin
359
+ { x: inverter.x + inverter.width * 0.75, y: battery.y + battery.height / 2 }, // Điểm uốn ngang
360
+ { x: inverter.x + inverter.width * 0.75, y: inverter.y + inverter.height } // Vào biến tần (cổng xuống Battery)
361
+ ], energyFlowOffset, 10, true); // true để đảo ngược hướng mũi tên
362
 
363
+
364
+ // 5. Máy phát điện -> Biến tần (AC)
365
  drawLinearFlow([
366
+ { x: generator.x + generator.width, y: generator.y + generator.height / 2 }, // Từ máy phát
367
+ { x: inverter.x, y: inverter.y + inverter.height * 0.7 } // Vào biến tần (cổng AC)
368
  ], energyFlowOffset);
369
 
 
370
  // Cập nhật offset để tạo hoạt hình dòng chảy
371
  energyFlowOffset = (energyFlowOffset + 2) % 100; // Thay đổi tốc độ và khoảng cách mũi tên
372