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> |