2nzi commited on
Commit
0c47455
·
verified ·
1 Parent(s): fdda46d

update home view

Browse files
Files changed (1) hide show
  1. src/views/HomeView.vue +258 -58
src/views/HomeView.vue CHANGED
@@ -7,6 +7,7 @@ import api from '../services/api'
7
  import CalibrationArea from '@/components/CalibrationArea.vue'
8
  import FootballField from '@/components/FootballField.vue'
9
  import PlotlyChart from '@/components/PlotlyChart.vue'
 
10
 
11
  const router = useRouter()
12
  const calibrationStore = useCalibrationStore()
@@ -24,6 +25,16 @@ const manualSection = ref(null)
24
 
25
  // États locaux
26
  const dragActive = ref(false)
 
 
 
 
 
 
 
 
 
 
27
 
28
  // États pour la vue manuelle
29
  const thumbnail = ref(null)
@@ -137,6 +148,35 @@ const selectMode = (mode) => {
137
  calibrationStore.setMode(mode)
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  const resetToStart = () => {
141
  // Réinitialiser tous les stores
142
  calibrationStore.reset()
@@ -339,8 +379,19 @@ const restart = () => {
339
  }
340
 
341
  const exportResults = () => {
342
- const data = calibrationStore.results
343
- const filename = 'football_vision_results.json'
 
 
 
 
 
 
 
 
 
 
 
344
 
345
  const content = JSON.stringify(data, null, 2)
346
 
@@ -603,65 +654,86 @@ const onChartError = (error) => {
603
  </div>
604
  </section>
605
 
606
- <!-- Section 2: Upload de fichier -->
607
  <section v-if="showUpload" ref="uploadSection" class="section upload-section">
608
-
609
- <div
610
- class="drop-zone"
611
- :class="{
612
- active: dragActive,
613
- 'has-file': uploadStore.isFileSelected,
614
- 'processing': uploadStore.isUploading
615
- }"
616
- @drop="handleDrop"
617
- @dragover="handleDragOver"
618
- @dragleave="handleDragLeave"
619
- >
620
- <div v-if="!uploadStore.isFileSelected" class="drop-content">
621
- <div class="upload-icon">+</div>
622
- <h3>Glissez-déposez votre fichier ici</h3>
623
- <p class="or-text">ou</p>
624
- <label class="file-input-label">
625
- <input
626
- type="file"
627
- accept="image/*,video/*"
628
- @change="handleFileSelect"
629
- hidden
630
- >
631
- Choisir un fichier
632
- </label>
633
- <p class="format-info">Images: JPG, PNG | Vidéos: MP4, AVI, MOV</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
  </div>
635
 
636
- <div v-else class="file-preview">
637
- <div class="file-info">
638
- <h3>Fichier sélectionné</h3>
639
- <p class="file-name">{{ uploadStore.selectedFile.name }}</p>
640
- <p class="file-details">
641
- <span>Type: {{ uploadStore.fileType === 'image' ? 'Image' : 'Vidéo' }}</span>
642
- <span>Taille: {{ Math.round(uploadStore.selectedFile.size / 1024) }} KB</span>
643
- </p>
644
- </div>
645
-
646
- <div class="preview" v-if="uploadStore.filePreview">
647
- <img
648
- v-if="uploadStore.isImage"
649
- :src="uploadStore.filePreview"
650
- alt="Preview"
651
- class="preview-media"
652
- >
653
- <video
654
- v-else
655
- :src="uploadStore.filePreview"
656
- controls
657
- class="preview-media"
658
  >
659
- </video>
 
 
 
 
 
 
660
  </div>
661
-
662
- <button @click="uploadStore.clearFile()" class="btn-secondary">
663
- Changer de fichier
664
- </button>
665
  </div>
666
  </div>
667
  </section>
@@ -1142,6 +1214,36 @@ const onChartError = (error) => {
1142
  font-weight: 600;
1143
  }
1144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1145
  .drop-zone {
1146
  border: 3px dashed #555;
1147
  border-radius: 12px;
@@ -1172,13 +1274,111 @@ const onChartError = (error) => {
1172
  font-weight: 300;
1173
  }
1174
 
1175
- .drop-content h3 {
1176
  font-size: 1.25rem;
1177
  color: white;
1178
  margin-bottom: 1rem;
1179
  font-weight: 600;
1180
  }
1181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1182
  .or-text {
1183
  color: #888;
1184
  margin: 1.5rem 0;
@@ -1232,7 +1432,7 @@ const onChartError = (error) => {
1232
  text-align: center;
1233
  }
1234
 
1235
- .file-info h3 {
1236
  color: var(--color-primary);
1237
  margin-bottom: 1.5rem;
1238
  font-weight: 600;
 
7
  import CalibrationArea from '@/components/CalibrationArea.vue'
8
  import FootballField from '@/components/FootballField.vue'
9
  import PlotlyChart from '@/components/PlotlyChart.vue'
10
+ import fieldTestImage from '@/assets/field_test_thumb.jpg'
11
 
12
  const router = useRouter()
13
  const calibrationStore = useCalibrationStore()
 
25
 
26
  // États locaux
27
  const dragActive = ref(false)
28
+ const selectedTestImage = ref(null)
29
+
30
+ // Image de test
31
+ const testImage = ref({
32
+ id: 'field1',
33
+ name: 'Terrain de test',
34
+ description: 'Image d\'exemple pour tester l\'analyse',
35
+ thumbnail: fieldTestImage,
36
+ fullUrl: fieldTestImage
37
+ })
38
 
39
  // États pour la vue manuelle
40
  const thumbnail = ref(null)
 
148
  calibrationStore.setMode(mode)
149
  }
150
 
151
+ const selectTestImage = async (testImage) => {
152
+ try {
153
+ selectedTestImage.value = testImage.id
154
+
155
+ // Créer un objet File à partir de l'URL de l'image de test
156
+ const response = await fetch(testImage.fullUrl)
157
+ const blob = await response.blob()
158
+ const file = new File([blob], `${testImage.name}.jpg`, { type: 'image/jpeg' })
159
+
160
+ uploadStore.setFile(file)
161
+
162
+ if (calibrationStore.isManualMode) {
163
+ // En mode manuel avec image, charger la vue manuelle intégrée
164
+ await loadThumbnail()
165
+ await nextTick()
166
+ scrollToSection(manualSection.value)
167
+ } else if (calibrationStore.isAutoMode) {
168
+ // En mode auto, lancement automatique pour les images
169
+ startProcessing()
170
+ }
171
+ } catch (error) {
172
+ console.error('Erreur lors du chargement de l\'image de test:', error)
173
+ // Fallback: utiliser l'URL directement pour la preview
174
+ uploadStore.filePreview = testImage.fullUrl
175
+ uploadStore.selectedFile = { name: `${testImage.name}.jpg`, size: 0 }
176
+ uploadStore.fileType = 'image'
177
+ }
178
+ }
179
+
180
  const resetToStart = () => {
181
  // Réinitialiser tous les stores
182
  calibrationStore.reset()
 
379
  }
380
 
381
  const exportResults = () => {
382
+ // Encapsuler les données de calibration dans une clé "calibration"
383
+ const data = {
384
+ calibration: calibrationStore.results
385
+ }
386
+
387
+ // Générer le nom de fichier basé sur le fichier original
388
+ let filename = 'football_vision_config.json'
389
+ if (uploadStore.selectedFile && uploadStore.selectedFile.name) {
390
+ // Enlever l'extension du fichier original et ajouter .json
391
+ const originalName = uploadStore.selectedFile.name
392
+ const nameWithoutExtension = originalName.substring(0, originalName.lastIndexOf('.')) || originalName
393
+ filename = `${nameWithoutExtension}_config.json`
394
+ }
395
 
396
  const content = JSON.stringify(data, null, 2)
397
 
 
654
  </div>
655
  </section>
656
 
657
+ <!-- Section 2: Upload de fichier -->
658
  <section v-if="showUpload" ref="uploadSection" class="section upload-section">
659
+ <div class="upload-grid">
660
+ <!-- Côté gauche: Upload de fichier -->
661
+ <div class="upload-left">
662
+ <div
663
+ class="drop-zone"
664
+ :class="{
665
+ active: dragActive,
666
+ 'has-file': uploadStore.isFileSelected,
667
+ 'processing': uploadStore.isUploading
668
+ }"
669
+ @drop="handleDrop"
670
+ @dragover="handleDragOver"
671
+ @dragleave="handleDragLeave"
672
+ >
673
+ <div v-if="!uploadStore.isFileSelected" class="drop-content">
674
+ <div class="upload-icon">+</div>
675
+ <h4>Glissez-déposez votre fichier ici</h4>
676
+ <p class="or-text">ou</p>
677
+ <label class="file-input-label">
678
+ <input
679
+ type="file"
680
+ accept="image/*,video/*"
681
+ @change="handleFileSelect"
682
+ hidden
683
+ >
684
+ Choisir un fichier
685
+ </label>
686
+ </div>
687
+
688
+ <div v-else class="file-preview">
689
+ <div class="file-info">
690
+ <h4>Fichier sélectionné</h4>
691
+ <p class="file-name">{{ uploadStore.selectedFile.name }}</p>
692
+ <p class="file-details">
693
+ <span>Type: {{ uploadStore.fileType === 'image' ? 'Image' : 'Vidéo' }}</span>
694
+ <span>Taille: {{ Math.round(uploadStore.selectedFile.size / 1024) }} KB</span>
695
+ </p>
696
+ </div>
697
+
698
+ <div class="preview" v-if="uploadStore.filePreview">
699
+ <img
700
+ v-if="uploadStore.isImage"
701
+ :src="uploadStore.filePreview"
702
+ alt="Preview"
703
+ class="preview-media"
704
+ >
705
+ <video
706
+ v-else
707
+ :src="uploadStore.filePreview"
708
+ controls
709
+ class="preview-media"
710
+ >
711
+ </video>
712
+ </div>
713
+
714
+ <button @click="uploadStore.clearFile()" class="btn-secondary">
715
+ Changer de fichier
716
+ </button>
717
+ </div>
718
+ </div>
719
  </div>
720
 
721
+ <!-- Côté droit: Images de test -->
722
+ <div class="upload-right">
723
+ <div class="test-image-container">
724
+ <div
725
+ class="test-image-card single"
726
+ @click="selectTestImage(testImage)"
727
+ :class="{ selected: selectedTestImage === testImage.id }"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
728
  >
729
+ <img :src="testImage.thumbnail" :alt="testImage.name" class="test-image-thumb">
730
+ <div class="test-image-overlay">
731
+ <div class="overlay-content">
732
+ <p>Vue Drone</p>
733
+ </div>
734
+ </div>
735
+ </div>
736
  </div>
 
 
 
 
737
  </div>
738
  </div>
739
  </section>
 
1214
  font-weight: 600;
1215
  }
1216
 
1217
+ /* Grid Upload */
1218
+ .upload-grid {
1219
+ display: grid;
1220
+ grid-template-columns: 1fr 1fr;
1221
+ gap: 3rem;
1222
+ width: 100%;
1223
+ max-width: 1200px;
1224
+ align-items: start;
1225
+ padding: 2rem;
1226
+ }
1227
+
1228
+ .upload-left, .upload-right {
1229
+ display: flex;
1230
+ flex-direction: column;
1231
+ height: 100%;
1232
+ }
1233
+
1234
+ .upload-right {
1235
+ justify-content: center;
1236
+ align-items: center;
1237
+ }
1238
+
1239
+ .upload-title {
1240
+ font-size: 1.25rem;
1241
+ font-weight: 600;
1242
+ color: white;
1243
+ margin-bottom: 2rem;
1244
+ text-align: center;
1245
+ }
1246
+
1247
  .drop-zone {
1248
  border: 3px dashed #555;
1249
  border-radius: 12px;
 
1274
  font-weight: 300;
1275
  }
1276
 
1277
+ .drop-content h4 {
1278
  font-size: 1.25rem;
1279
  color: white;
1280
  margin-bottom: 1rem;
1281
  font-weight: 600;
1282
  }
1283
 
1284
+ /* Image de test */
1285
+ .test-image-container {
1286
+ display: flex;
1287
+ flex-direction: column;
1288
+ align-items: center;
1289
+ justify-content: center;
1290
+ width: 100%;
1291
+ height: 100%;
1292
+ }
1293
+
1294
+ .test-image-card.single {
1295
+ background: var(--color-secondary-soft);
1296
+ border-radius: 12px;
1297
+ overflow: hidden;
1298
+ cursor: pointer;
1299
+ transition: all 0.3s ease;
1300
+ border: 2px solid transparent;
1301
+ position: relative;
1302
+ width: 100%;
1303
+ height: 100%;
1304
+ display: flex;
1305
+ }
1306
+
1307
+ .test-image-card:hover {
1308
+ transform: translateY(-4px);
1309
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
1310
+ border-color: rgba(255, 255, 255, 0.2);
1311
+ }
1312
+
1313
+ .test-image-card.selected {
1314
+ border-color: var(--color-primary);
1315
+ box-shadow: 0 4px 20px rgba(217, 255, 4, 0.3);
1316
+ }
1317
+
1318
+ .test-image-card.selected::after {
1319
+ content: '✓';
1320
+ position: absolute;
1321
+ top: 8px;
1322
+ right: 8px;
1323
+ background: var(--color-primary);
1324
+ color: var(--color-secondary);
1325
+ width: 24px;
1326
+ height: 24px;
1327
+ border-radius: 50%;
1328
+ display: flex;
1329
+ align-items: center;
1330
+ justify-content: center;
1331
+ font-weight: bold;
1332
+ font-size: 0.8rem;
1333
+ }
1334
+
1335
+ .test-image-thumb {
1336
+ width: 100%;
1337
+ height: 100%;
1338
+ object-fit: cover;
1339
+ display: block;
1340
+ }
1341
+
1342
+ .test-image-overlay {
1343
+ position: absolute;
1344
+ top: 0;
1345
+ left: 0;
1346
+ right: 0;
1347
+ bottom: 0;
1348
+ background: rgba(0, 0, 0, 0.7);
1349
+ display: flex;
1350
+ align-items: center;
1351
+ justify-content: center;
1352
+ opacity: 1;
1353
+ transition: opacity 0.3s ease;
1354
+ backdrop-filter: blur(2px);
1355
+ }
1356
+
1357
+ .test-image-card.single:hover .test-image-overlay {
1358
+ opacity: 0;
1359
+ }
1360
+
1361
+ .overlay-content {
1362
+ text-align: center;
1363
+ color: white;
1364
+ }
1365
+
1366
+ .overlay-content h4 {
1367
+ font-size: 1.25rem;
1368
+ font-weight: 600;
1369
+ margin: 0 0 0.5rem 0;
1370
+ color: var(--color-primary);
1371
+ }
1372
+
1373
+ .overlay-content p {
1374
+ font-size: 0.9rem;
1375
+ margin: 0;
1376
+ color: #e0e0e0;
1377
+ font-weight: 500;
1378
+ }
1379
+
1380
+
1381
+
1382
  .or-text {
1383
  color: #888;
1384
  margin: 1.5rem 0;
 
1432
  text-align: center;
1433
  }
1434
 
1435
+ .file-info h4 {
1436
  color: var(--color-primary);
1437
  margin-bottom: 1.5rem;
1438
  font-weight: 600;