Spaces:
Running
Running
| <template> | |
| <div class="labeling-view"> | |
| <div class="labels-container" v-if="selectedObject"> | |
| <div class="label-options"> | |
| <div class="label-list"> | |
| <div | |
| v-for="label in predefinedLabels" | |
| :key="label.name" | |
| class="label-item" | |
| > | |
| <button | |
| class="label-btn" | |
| :class="{ active: selectedObject.label === label.name }" | |
| :style="{ | |
| backgroundColor: label.color, | |
| border: selectedObject.label === label.name ? '3px solid #fff' : '3px solid transparent' | |
| }" | |
| @click="assignLabel(label.name)" | |
| > | |
| <span class="label-text">{{ label.name }}</span> | |
| <span class="shortcut-key">{{ getShortcutKey(label.name) }}</span> | |
| </button> | |
| <input | |
| type="color" | |
| :value="label.color" | |
| @input="updateLabelColor(label.name, $event.target.value)" | |
| class="color-picker" | |
| :title="`Changer la couleur de ${label.name}`" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div v-else class="no-object-message"> | |
| <p>Sélectionnez un objet dans la timeline pour lui attribuer un label</p> | |
| </div> | |
| </div> | |
| </template> | |
| <script> | |
| import { useAnnotationStore } from '@/stores/annotationStore' | |
| export default { | |
| name: 'LabelingView', | |
| data() { | |
| return { | |
| predefinedLabels: [ | |
| { name: 'Player Team 1', color: '#dc3545' }, | |
| { name: 'Player Team 2', color: '#000000' }, | |
| { name: 'Ball', color: '#28a745' } | |
| ] | |
| } | |
| }, | |
| setup() { | |
| const annotationStore = useAnnotationStore() | |
| return { | |
| annotationStore | |
| } | |
| }, | |
| mounted() { | |
| // Ajouter l'écouteur d'événement clavier | |
| window.addEventListener('keydown', this.handleKeyPress) | |
| }, | |
| beforeUnmount() { | |
| // Supprimer l'écouteur d'événement clavier | |
| window.removeEventListener('keydown', this.handleKeyPress) | |
| }, | |
| computed: { | |
| selectedObject() { | |
| if (!this.annotationStore.selectedObjectId) return null | |
| return this.annotationStore.objects[this.annotationStore.selectedObjectId] | |
| } | |
| }, | |
| methods: { | |
| assignLabel(labelName) { | |
| if (!this.selectedObject) return | |
| // Mettre à jour l'objet avec le nouveau label | |
| this.annotationStore.objects[this.selectedObject.id] = { | |
| ...this.selectedObject, | |
| label: labelName | |
| } | |
| console.log(`Label "${labelName}" assigné à l'objet ${this.selectedObject.name}`) | |
| }, | |
| updateLabelColor(labelName, newColor) { | |
| const labelIndex = this.predefinedLabels.findIndex(label => label.name === labelName) | |
| if (labelIndex !== -1) { | |
| this.predefinedLabels[labelIndex].color = newColor | |
| } | |
| }, | |
| removeLabel() { | |
| if (!this.selectedObject) return | |
| // Supprimer le label de l'objet | |
| const updatedObject = { ...this.selectedObject } | |
| delete updatedObject.label | |
| this.annotationStore.objects[this.selectedObject.id] = updatedObject | |
| console.log(`Label supprimé de l'objet ${this.selectedObject.name}`) | |
| }, | |
| getLabelColor(labelName) { | |
| const predefinedLabel = this.predefinedLabels.find(label => label.name === labelName) | |
| return predefinedLabel ? predefinedLabel.color : '#6c757d' | |
| }, | |
| getShortcutKey(labelName) { | |
| const shortcuts = { | |
| 'Player Team 1': '1', | |
| 'Player Team 2': '2', | |
| 'Ball': '3' | |
| } | |
| return shortcuts[labelName] || '' | |
| }, | |
| handleKeyPress(event) { | |
| // Vérifier que nous ne sommes pas dans un champ de saisie | |
| if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') { | |
| return | |
| } | |
| // Vérifier qu'un objet est sélectionné | |
| if (!this.selectedObject) { | |
| return | |
| } | |
| // Gérer les raccourcis clavier | |
| switch(event.key) { | |
| case '1': | |
| event.preventDefault() | |
| this.assignLabel('Player Team 1') | |
| break | |
| case '2': | |
| event.preventDefault() | |
| this.assignLabel('Player Team 2') | |
| break | |
| case '3': | |
| event.preventDefault() | |
| this.assignLabel('Ball') | |
| break | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <style scoped> | |
| .labeling-view { | |
| height: 100%; | |
| padding: 16px; | |
| color: white; | |
| overflow-y: auto; | |
| } | |
| .labels-container { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| } | |
| .label-list { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 8px; | |
| } | |
| .label-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .label-btn { | |
| flex: 1; | |
| padding: 8px 12px; | |
| border-radius: 4px; | |
| color: white; | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 8px; | |
| } | |
| .label-btn:hover { | |
| opacity: 0.8; | |
| transform: translateY(-1px); | |
| } | |
| .label-btn.active { | |
| box-shadow: 0 0 0 1px #fff; | |
| } | |
| .color-picker { | |
| width: 32px; | |
| height: 32px; | |
| border: none; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| background: none; | |
| padding: 0; | |
| } | |
| .color-picker::-webkit-color-swatch-wrapper { | |
| padding: 0; | |
| border-radius: 4px; | |
| } | |
| .color-picker::-webkit-color-swatch { | |
| border: none; | |
| border-radius: 4px; | |
| } | |
| .label-text { | |
| flex: 1; | |
| text-align: left; | |
| } | |
| .shortcut-key { | |
| background-color: rgba(255, 255, 255, 0.2); | |
| border-radius: 3px; | |
| padding: 2px 6px; | |
| font-size: 11px; | |
| font-weight: bold; | |
| min-width: 16px; | |
| text-align: center; | |
| } | |
| .no-object-message { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| text-align: center; | |
| } | |
| .no-object-message p { | |
| color: #999; | |
| font-style: italic; | |
| } | |
| </style> |