123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- <template>
- <div class="annotation-box"
- :style="style"
- :class="{
- draggable,
- deletable,
- taggable,
- confirmable,
- croppable,
- }"
- @contextmenu.prevent
- @mousedown.prevent="click" @touchstart.prevent="click">
- <template v-if="draggable">
- <div class="nw" @mousedown.prevent.stop="resize('nw')" @touchstart.prevent.stop="resize('nw')"/>
- <div class="nn" @mousedown.prevent.stop="resize('nn')" @touchstart.prevent.stop="resize('nn')"/>
- <div class="ne" @mousedown.prevent.stop="resize('ne')" @touchstart.prevent.stop="resize('ne')"/>
- <div class="ww" @mousedown.prevent.stop="resize('ww')" @touchstart.prevent.stop="resize('ww')"/>
- <div class="ee" @mousedown.prevent.stop="resize('ee')" @touchstart.prevent.stop="resize('ee')"/>
- <div class="sw" @mousedown.prevent.stop="resize('sw')" @touchstart.prevent.stop="resize('sw')"/>
- <div class="ss" @mousedown.prevent.stop="resize('ss')" @touchstart.prevent.stop="resize('ss')"/>
- <div class="se" @mousedown.prevent.stop="resize('se')" @touchstart.prevent.stop="resize('se')"/>
- </template>
- <div v-if="labelName" class="label">
- {{ labelName }}
- </div>
- </div>
- </template>
- <script>
- export default {
- name: "annotation-box",
- data: function(){
- return {
- clickCounter: 0,
- dblClickInterval: 200, // in ms
- colors: {
- default: '255, 255, 255',
- pipeline: '0, 0, 255',
- user: '255, 0, 0',
- other_user: '136, 0, 136',
- confirmed: '0, 180, 0',
- other_confirmed: '180, 180, 136',
- }
- };
- },
- props: [
- 'box',
- 'position',
- 'draggable',
- 'deletable',
- 'taggable',
- 'confirmable',
- 'zoomable',
- 'croppable',
- 'labels',
- 'shine'
- ],
- computed: {
- labelName: function () {
- if (!this.box || !this.box.label_id)
- return false;
- for (let label of this.labels) {
- if (label.identifier === this.box.label_id) {
- return label.name;
- }
- }
- return 'unknown';
- },
- style: function () {
- let color = this.color();
- return {
- backgroundColor: `rgba(${color}, ${this.shine ? 0.6 : 0.3})`,
- borderColor: `rgba(${color}, ${this.shine ? 0.8 : 0.4})`,
- top: this.position.y * 100 + '%',
- left: this.position.x * 100 + '%',
- width: this.position.w * 100 + '%',
- height: this.position.h * 100 + '%'
- }
- },
- },
- methods: {
- color: function() {
- let box = this.box;
- let current_user = this.$root.socket.username
- if(!box)
- return this.colors.default;
- switch(box.origin) {
- case 'user':
- for (let confirmer of box.confirmations)
- if (confirmer.confirming_user == current_user)
- return this.colors.confirmed;
- if (box.confirmations.length !== 0)
- return this.colors.other_confirmed;
- if (box.origin_user === current_user)
- return this.colors.user;
- return this.colors.other_user;
- case 'pipeline':
- return this.colors.pipeline;
- }
- },
- doubleLeftClick(event) {
- console.debug("double left click", event);
- this.$emit('interaction', "move-box");
- this.$emit('crop', this.box);
- },
- doubleRightClick(event) {
- console.debug("double right click", event);
- },
- singleLeftClick(event) {
- console.debug("single left click", event);
- if (this.deletable) {
- // TODO then / error
- this.$emit("remove", this.box.identifier)
- }
- else if (this.draggable) {
- // TODO then / error
- this.$emit('move', event, this.position, this.update);
- }
- else if (this.taggable) {
- // TODO then / error
- this.$emit("labelBox", this.box.identifier, this.taggable.identifier)
- this.selectMe();
- }
- else if (this.confirmable) {
- // TODO then / error
- this.$emit("confirm", this.box.identifier)
- }
- else if (this.zoomable) {
- this.$emit('zoom', this.position);
- }
- else if (this.croppable) {
- this.selectMe();
- }
- event.stopPropagation();
- },
- singleRightClick() {
- this.selectMe();
- this.$emit('labelSelector', this.box);
- },
- singleClick(event) {
- if (event.which == 1){
- this.singleLeftClick(event);
- }
- else if (event.which == 2){
- console.debug("single middle click");
- }
- else if (event.which == 3){
- this.singleRightClick(event);
- }
- },
- doubleClick(event) {
- if (event.which == 1){
- this.doubleLeftClick(event);
- }
- else if (event.which == 2){
- console.debug("double middle click");
- }
- else if (event.which == 3){
- this.doubleRightClick(event);
- }
- },
- selectMe(){
- this.$emit('crop', this.box);
- },
- click: function (event) {
- this.clickCounter++;
- event.stopPropagation();
- if (this.clickCounter == 1) {
- this.timer = setTimeout( () => {
- this.clickCounter = 0;
- this.singleClick(event);
- }, this.dblClickInterval);
- return;
- }
- clearTimeout(this.timer);
- this.clickCounter = 0;
- this.doubleClick(event);
- },
- resize: function (mode) {
- this.$emit('resize', mode, this.position, this.update);
- },
- update: function (value) {
- this.$emit("updateBox", this.box.identifier, value)
- }
- }
- }
- </script>
- <style scoped>
- .annotation-box {
- position: absolute;
- border: 1px solid transparent;
- }
- .label {
- position: absolute;
- bottom: 0.25rem;
- left: 50%;
- transform: translateX(-50%);
- font-size: 80%;
- color: whitesmoke;
- text-shadow: 0 0 1px #000000;
- }
- .nw {
- position: absolute;
- top: -0.3rem;
- left: -0.3rem;
- width: 0.6rem;
- height: 0.6rem;
- cursor: nwse-resize;
- /* background-color: blue; */
- }
- .nn {
- position: absolute;
- top: -0.3rem;
- left: 0.3rem;
- right: 0;
- height: 0.6rem;
- cursor: ns-resize;
- /* background-color: orangered; */
- }
- .ne {
- position: absolute;
- top: -0.3rem;
- right: -0.3rem;
- width: 0.6rem;
- height: 0.6rem;
- cursor: nesw-resize;
- /* background-color: cadetblue; */
- }
- .ww {
- position: absolute;
- top: 0.3rem;
- left: -0.3rem;
- width: 0.6rem;
- bottom: 0.3rem;
- cursor: ew-resize;
- /* background-color: fuchsia; */
- }
- .ee {
- position: absolute;
- top: 0.3rem;
- right: -0.3rem;
- width: 0.6rem;
- bottom: 0.3rem;
- cursor: ew-resize;
- /* background-color: midnightblue; */
- }
- .sw {
- position: absolute;
- bottom: -0.3rem;
- left: -0.3rem;
- width: 0.6rem;
- height: 0.6rem;
- cursor: nesw-resize;
- /* background-color: aqua; */
- }
- .ss {
- position: absolute;
- bottom: -0.3rem;
- left: 0.3rem;
- right: 0.3rem;
- height: 0.6rem;
- cursor: ns-resize;
- /* background-color: gold; */
- }
- .se {
- position: absolute;
- bottom: -0.3rem;
- right: -0.3rem;
- width: 0.6rem;
- height: 0.6rem;
- cursor: nwse-resize;
- /* background-color: brown; */
- }
- .draggable {
- cursor: url('~@/assets/icons/four-directions.svg') 8 8, move;
- }
- .deletable {
- cursor: url('~@/assets/icons/trash.svg') 8 8, not-allowed;
- }
- .taggable {
- cursor: url('~@/assets/icons/tag.svg') 8 8, alias;
- }
- .confirmable {
- cursor: url('~@/assets/icons/check.svg') 8 8, pointer;
- }
- .croppable {
- cursor: url('~@/assets/icons/info.svg') 8 8, move;
- }
- </style>
|