@konfuzio/document-validation-ui 0.1.59-dev.3 → 0.1.60-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/cypress.config.js +6 -6
  2. package/dist/css/app.css +1 -1
  3. package/dist/index.html +1 -1
  4. package/dist/js/app.js +1 -1
  5. package/dist/js/app.js.map +1 -1
  6. package/dist/js/chunk-vendors.js +23 -66
  7. package/dist/js/chunk-vendors.js.map +1 -1
  8. package/jest.config.js +2 -22
  9. package/package.json +38 -32
  10. package/src/api.js +12 -0
  11. package/src/assets/scss/ann_set_table_options.scss +4 -4
  12. package/src/assets/scss/annotation_action_buttons.scss +7 -7
  13. package/src/assets/scss/annotation_details.scss +9 -9
  14. package/src/assets/scss/choose_label_set_modal.scss +5 -5
  15. package/src/assets/scss/document_action_bar.scss +3 -3
  16. package/src/assets/scss/document_annotations.scss +43 -45
  17. package/src/assets/scss/document_category.scss +8 -8
  18. package/src/assets/scss/document_dashboard.scss +1 -1
  19. package/src/assets/scss/document_edit.scss +30 -30
  20. package/src/assets/scss/document_error.scss +6 -6
  21. package/src/assets/scss/document_name.scss +6 -6
  22. package/src/assets/scss/document_page.scss +3 -3
  23. package/src/assets/scss/document_search_bar.scss +7 -7
  24. package/src/assets/scss/document_set_chooser.scss +3 -3
  25. package/src/assets/scss/document_thumbnails.scss +7 -7
  26. package/src/assets/scss/document_toolbar.scss +10 -10
  27. package/src/assets/scss/document_top_bar.scss +11 -11
  28. package/src/assets/scss/document_viewport_modal.scss +3 -3
  29. package/src/assets/scss/documents_list.scss +12 -11
  30. package/src/assets/scss/edit_page_thumbnail.scss +6 -6
  31. package/src/assets/scss/empty_state.scss +4 -4
  32. package/src/assets/scss/error_page.scss +2 -2
  33. package/src/assets/scss/extracting_data.scss +3 -3
  34. package/src/assets/scss/imports.scss +1 -0
  35. package/src/assets/scss/multi_ann_table_overlay.scss +3 -3
  36. package/src/assets/scss/multi_ann_table_popup.scss +1 -1
  37. package/src/assets/scss/new_annotation.scss +19 -25
  38. package/src/assets/scss/scrolling_document.scss +1 -1
  39. package/src/assets/scss/theme.scss +52 -64
  40. package/src/assets/scss/variables.scss +0 -2
  41. package/src/components/App.vue +14 -9
  42. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +6 -4
  43. package/src/components/DocumentAnnotations/AnnotationContent.vue +52 -25
  44. package/src/components/DocumentAnnotations/AnnotationRow.vue +50 -106
  45. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +6 -12
  46. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +70 -31
  47. package/src/components/DocumentDashboard.vue +17 -12
  48. package/src/components/DocumentEdit/EditPages.vue +46 -51
  49. package/src/components/DocumentPage/BoxSelection.vue +49 -16
  50. package/src/components/DocumentPage/DocumentPage.vue +153 -56
  51. package/src/components/DocumentPage/DocumentToolbar.vue +15 -5
  52. package/src/components/DocumentPage/EditAnnotation.vue +372 -0
  53. package/src/components/DocumentPage/{AnnotationPopup.vue → NewAnnotation.vue} +94 -122
  54. package/src/components/DocumentPage/ScrollingPage.vue +10 -2
  55. package/src/components/DocumentThumbnails/LoadingThumbnail.vue +6 -3
  56. package/src/components/DocumentTopBar/DocumentTopBar.vue +2 -4
  57. package/src/constants.js +7 -1
  58. package/src/i18n.js +5 -2
  59. package/src/main.js +16 -14
  60. package/src/store/display.js +24 -38
  61. package/src/store/document.js +6 -1
  62. package/src/store/index.js +8 -5
  63. package/src/store/selection.js +76 -152
  64. package/src/components/DocumentPage/PlaceholderSelection.vue +0 -51
  65. package/src/components/DocumentPage/SpanSelection.vue +0 -259
@@ -3,19 +3,24 @@
3
3
  <DocumentTopBar />
4
4
  <div :class="['dashboard-viewer', renameAndCategorize ? 'edit-mode' : '']">
5
5
  <DocumentThumbnails v-if="!editMode" ref="documentPages" />
6
- <splitpanes class="default-theme">
7
- <pane :size="50" :min-size="10">
6
+ <Split>
7
+ <SplitArea :size="50" :min-size="350">
8
8
  <ScrollingDocument
9
9
  ref="scrollingDocument"
10
10
  class="dashboard-document"
11
11
  />
12
- </pane>
13
- <pane :size="50">
12
+ </SplitArea>
13
+ <SplitArea :size="50" style="overflow-y: auto">
14
14
  <DocumentAnnotations v-if="!editMode" ref="annotations" />
15
15
  <DocumentEdit v-else ref="editView" />
16
- </pane>
17
- </splitpanes>
16
+ </SplitArea>
17
+ </Split>
18
18
 
19
+ <MultiAnnotationTableOverlay
20
+ v-if="showAnnSetTable"
21
+ :left="documentContainerLeftPadding"
22
+ :width="documentContainerWidth"
23
+ />
19
24
  <ChooseLabelSetModal
20
25
  v-if="showChooseLabelSetModal && showChooseLabelSetModal.show"
21
26
  :is-multiple-annotations="showChooseLabelSetModal.isMultipleAnnotations"
@@ -54,15 +59,16 @@ import { mapGetters, mapState } from "vuex";
54
59
  import { DocumentTopBar } from "./DocumentTopBar";
55
60
  import { ScrollingDocument } from "./DocumentPage";
56
61
  import { DocumentThumbnails } from "./DocumentThumbnails";
57
- import { DocumentAnnotations } from "./DocumentAnnotations";
62
+ import {
63
+ DocumentAnnotations,
64
+ MultiAnnotationTableOverlay,
65
+ } from "./DocumentAnnotations";
58
66
  import { DocumentEdit } from "./DocumentEdit";
59
67
  import ErrorMessage from "./ErrorMessage";
60
68
  import NotOptimizedViewportModal from "../components/DocumentModals/NotOptimizedViewportModal";
61
69
  import AnnotationDeletedModal from "../components/DocumentModals/AnnotationDeletedModal";
62
70
  import DocumentErrorModal from "../components/DocumentModals/DocumentErrorModal";
63
71
  import ChooseLabelSetModal from "../components/DocumentAnnotations/ChooseLabelSetModal";
64
- import { Splitpanes, Pane } from "splitpanes";
65
- import "splitpanes/dist/splitpanes.css";
66
72
 
67
73
  /**
68
74
  * This component shows the PDF pages in a scrolling component and
@@ -71,8 +77,6 @@ import "splitpanes/dist/splitpanes.css";
71
77
  export default {
72
78
  name: "DocumentDashboard",
73
79
  components: {
74
- Splitpanes,
75
- Pane,
76
80
  DocumentTopBar,
77
81
  ScrollingDocument,
78
82
  DocumentThumbnails,
@@ -81,6 +85,7 @@ export default {
81
85
  ErrorMessage,
82
86
  NotOptimizedViewportModal,
83
87
  DocumentErrorModal,
88
+ MultiAnnotationTableOverlay,
84
89
  ChooseLabelSetModal,
85
90
  AnnotationDeletedModal,
86
91
  },
@@ -131,7 +136,7 @@ export default {
131
136
  mounted() {
132
137
  this.resizeObserver = new ResizeObserver(this.onDocumentResize);
133
138
  },
134
- unmounted() {
139
+ destroyed() {
135
140
  if (this.$refs.scrollingDocument) {
136
141
  this.resizeObserver.unobserve(this.$refs.scrollingDocument.$el);
137
142
  }
@@ -7,64 +7,60 @@
7
7
  v-model="editPages"
8
8
  class="document-grid"
9
9
  easing="cubic-bezier(0.37, 0, 0.63, 1)"
10
- item-key="id"
11
- :move="checkMove"
12
10
  @start="dragging = true"
13
11
  @end="handleDragEnd"
12
+ @move="checkMove"
14
13
  >
15
- <template #item="{ element, index }">
16
- <div
17
- :id="element.id"
18
- :key="element.id"
19
- class="image-section"
20
- tabindex="0"
21
- >
22
- <div class="top-section">
23
- <EditPageThumbnail
24
- :page="element"
25
- :index="index"
26
- :rotation="getRotation(element.id)"
27
- />
14
+ <div
15
+ v-for="(page, index) in editPages"
16
+ :key="page.id"
17
+ class="image-section"
18
+ tabindex="0"
19
+ >
20
+ <div class="top-section">
21
+ <EditPageThumbnail
22
+ :page="page"
23
+ :index="index"
24
+ :rotation="getRotation(page.id)"
25
+ />
26
+ <div
27
+ :class="[
28
+ 'splitting-lines',
29
+ splittingLines &&
30
+ splittingLines[index].page === page.number &&
31
+ 'active-split',
32
+ ]"
33
+ @click="handleSplittingLines(page.number, 'manual')"
34
+ >
35
+ <div class="scissors-icon">
36
+ <b-icon icon="scissors" class="is-small" />
37
+ </div>
28
38
  <div
29
- :class="[
30
- 'splitting-lines',
31
- splittingLines &&
32
- splittingLines[index].page === element.number &&
33
- 'active-split',
34
- ]"
35
- @click="handleSplittingLines(element.number, 'manual')"
39
+ v-if="
40
+ splittingLines && splittingLines[index].page === page.number
41
+ "
42
+ class="lines active-split"
36
43
  >
37
- <div class="scissors-icon">
38
- <b-icon icon="scissors" class="is-small" />
39
- </div>
40
- <div
41
- v-if="
44
+ <SplitZigZag
45
+ :color="
42
46
  splittingLines &&
43
- splittingLines[index].page === element.number
47
+ splittingLines[index].origin &&
48
+ splittingLines[index].origin === 'AI' &&
49
+ splitSuggestionsEnabled
50
+ ? 'green'
51
+ : 'dark'
44
52
  "
45
- class="lines active-split"
46
- >
47
- <SplitZigZag
48
- :color="
49
- splittingLines &&
50
- splittingLines[index].origin &&
51
- splittingLines[index].origin === 'AI' &&
52
- splitSuggestionsEnabled
53
- ? 'green'
54
- : 'dark'
55
- "
56
- />
57
- </div>
58
- <div v-else class="lines not-active-split">
59
- <SplitLines />
60
- </div>
53
+ />
54
+ </div>
55
+ <div v-else class="lines not-active-split">
56
+ <SplitLines />
61
57
  </div>
62
- </div>
63
- <div class="bottom-section">
64
- <span class="page-number">{{ element.number }}</span>
65
58
  </div>
66
59
  </div>
67
- </template>
60
+ <div class="bottom-section">
61
+ <span class="page-number">{{ page.number }}</span>
62
+ </div>
63
+ </div>
68
64
  </draggable>
69
65
  </div>
70
66
  </template>
@@ -79,6 +75,7 @@ import { mapState } from "vuex";
79
75
  import SplitLines from "../../assets/images/SplitLines";
80
76
  import SplitZigZag from "../../assets/images/SplitZigZag";
81
77
  import EditPageThumbnail from "./EditPageThumbnail";
78
+
82
79
  import draggable from "vuedraggable";
83
80
 
84
81
  export default {
@@ -136,9 +133,7 @@ export default {
136
133
  },
137
134
  },
138
135
  mounted() {
139
- if (this.pagesForPostprocess.length > 0) {
140
- this.editPages = this.pagesForPostprocess;
141
- }
136
+ this.editPages = this.pagesForPostprocess;
142
137
  },
143
138
  methods: {
144
139
  deselect() {
@@ -13,6 +13,11 @@
13
13
  ref="boxTransformer"
14
14
  :config="transformerConfig"
15
15
  />
16
+ <v-rect
17
+ v-if="selection.placeholderBox"
18
+ ref="placeholderSelection"
19
+ :config="placeholderConfig"
20
+ />
16
21
  </v-group>
17
22
  </template>
18
23
 
@@ -51,7 +56,21 @@ export default {
51
56
  draggable: true,
52
57
  };
53
58
  },
54
-
59
+ placeholderConfig() {
60
+ return {
61
+ x: this.selection.placeholderBox.x,
62
+ y: this.selection.placeholderBox.y,
63
+ width: this.selection.placeholderBox.width,
64
+ height: this.selection.placeholderBox.height,
65
+ fill: "transparent",
66
+ stroke: "#41af85",
67
+ strokeWidth: 3,
68
+ globalCompositeOperation: "multiply",
69
+ shadowForStrokeEnabled: false,
70
+ name: "placeholderSelection",
71
+ draggable: false,
72
+ };
73
+ },
55
74
  transformerConfig() {
56
75
  return {
57
76
  borderEnabled: false,
@@ -68,8 +87,7 @@ export default {
68
87
  "elementSelected",
69
88
  "spanSelection",
70
89
  ]),
71
- ...mapState("document", ["editAnnotation"]),
72
- ...mapGetters("display", ["clientToBbox", "scaledEntities"]),
90
+ ...mapGetters("display", ["clientToBbox"]),
73
91
  ...mapGetters("selection", ["isSelectionValid", "entitiesOnSelection"]),
74
92
  },
75
93
  watch: {
@@ -88,19 +106,19 @@ export default {
88
106
  },
89
107
  methods: {
90
108
  handleSelection() {
91
- const box = this.clientToBbox(
92
- this.page,
93
- this.selection.start,
94
- this.selection.end
95
- );
96
-
97
- this.$store.dispatch("selection/entitySelection", {
98
- entities: this.scaledEntities(
99
- this.entitiesOnSelection(box, this.page),
100
- this.page
101
- ),
102
- selection: box,
103
- });
109
+ if (!this.elementSelected) {
110
+ const box = this.clientToBbox(
111
+ this.page,
112
+ this.selection.start,
113
+ this.selection.end
114
+ );
115
+ this.$emit(
116
+ "createAnnotations",
117
+ this.entitiesOnSelection(box, this.page)
118
+ );
119
+ } else {
120
+ this.getBoxSelectionContent();
121
+ }
104
122
  },
105
123
  updateTransformer() {
106
124
  // here we need to manually attach or detach Transformer node
@@ -134,6 +152,21 @@ export default {
134
152
  transformerNode.getLayer().batchDraw();
135
153
  },
136
154
 
155
+ getBoxSelectionContent() {
156
+ if (!this.isSelecting) {
157
+ const box = this.clientToBbox(
158
+ this.page,
159
+ this.selection.start,
160
+ this.selection.end
161
+ );
162
+ this.$emit("selectEntities", this.entitiesOnSelection(box, this.page));
163
+ this.$store.dispatch("selection/getTextFromBboxes", {
164
+ box,
165
+ entities: false,
166
+ });
167
+ }
168
+ },
169
+
137
170
  /**
138
171
  * This method is used for both transforms and drags since it just
139
172
  * retrieves the rect's new attributes from the event and uses those
@@ -11,14 +11,26 @@
11
11
  page.number === currentPage && 'current-page',
12
12
  ]"
13
13
  >
14
- <AnnotationPopup
15
- v-if="!isSelecting && spanSelectionsForPage(page).length > 0"
16
- :spans="spanSelectionsForPage(page)"
14
+ <NewAnnotation
15
+ v-if="newAnnotation && newAnnotation.length && !editAnnotation"
16
+ :new-annotation="newAnnotation"
17
17
  :container-width="scaledViewport.width"
18
18
  :container-height="scaledViewport.height"
19
19
  :page="page"
20
20
  @close="closePopups"
21
21
  />
22
+ <EditAnnotation
23
+ v-if="
24
+ editAnnotation &&
25
+ editAnnotation.pageNumber &&
26
+ editAnnotation.pageNumber === currentPage &&
27
+ selection
28
+ "
29
+ :edit-annotation="editAnnotation"
30
+ :page="page"
31
+ :container-width="scaledViewport.width"
32
+ :container-height="scaledViewport.height"
33
+ />
22
34
 
23
35
  <div
24
36
  v-if="showAnnotationLabel"
@@ -58,12 +70,7 @@
58
70
  }"
59
71
  ></v-rect>
60
72
  </template>
61
- <v-group
62
- v-if="
63
- !categorizeModalIsActive || !publicView || !isDocumentReviewed
64
- "
65
- ref="entities"
66
- >
73
+ <v-group v-if="!publicView || !isDocumentReviewed" ref="entities">
67
74
  <v-rect
68
75
  v-for="(entity, index) in scaledEntities(page.entities, page)"
69
76
  :key="index"
@@ -79,7 +86,7 @@
79
86
  (bbox) => bbox.page_index + 1 == page.number
80
87
  )"
81
88
  >
82
- <v-group>
89
+ <v-group :key="'ann' + annotation.id + '-' + index">
83
90
  <v-rect
84
91
  v-if="!isAnnotationInEditMode(annotation.id)"
85
92
  :config="annotationRect(bbox, annotation.id)"
@@ -92,7 +99,7 @@
92
99
  <template
93
100
  v-if="annotation.metadata && annotation.metadata.checkbox"
94
101
  >
95
- <v-group>
102
+ <v-group :key="'ann' + annotation.id + '-checkbox'">
96
103
  <v-rect
97
104
  v-if="!isAnnotationInEditMode(annotation.id)"
98
105
  :config="
@@ -115,22 +122,12 @@
115
122
  </template>
116
123
  </template>
117
124
  </v-layer>
118
- <v-layer>
119
- <template
120
- v-for="(span, index) in spanSelectionsForPage(page)"
121
- :key="index"
122
- >
123
- <span-selection :id="index" :span="span" :page="page" />
124
- </template>
125
- <template
126
- v-for="(span, index) in placeholderSelectionForPage(page)"
127
- :key="`${index}_placeholder`"
128
- >
129
- <placeholder-selection :span="span" :page="page" />
130
- </template>
131
- <template v-if="page.number === selectionPage">
132
- <box-selection :page="page" />
133
- </template>
125
+ <v-layer v-if="page.number === selectionPage">
126
+ <box-selection
127
+ :page="page"
128
+ @createAnnotations="handleCreateAnnotationsFromSelection"
129
+ @selectEntities="handleEntitiesFromSelection"
130
+ />
134
131
  </v-layer>
135
132
  </v-stage>
136
133
  <b-skeleton
@@ -146,18 +143,16 @@ import { mapState, mapGetters, mapActions } from "vuex";
146
143
  import { PIXEL_RATIO } from "../../constants";
147
144
  import api from "../../api";
148
145
  import BoxSelection from "./BoxSelection";
149
- import SpanSelection from "./SpanSelection";
150
- import PlaceholderSelection from "./PlaceholderSelection";
151
- import AnnotationPopup from "./AnnotationPopup";
146
+ import NewAnnotation from "./NewAnnotation";
147
+ import EditAnnotation from "./EditAnnotation";
152
148
  import AnnSetTableOptions from "./AnnSetTableOptions";
153
149
 
154
150
  export default {
155
151
  name: "DocumentPage",
156
152
  components: {
157
153
  BoxSelection,
158
- SpanSelection,
159
- PlaceholderSelection,
160
- AnnotationPopup,
154
+ NewAnnotation,
155
+ EditAnnotation,
161
156
  AnnSetTableOptions,
162
157
  },
163
158
 
@@ -176,15 +171,12 @@ export default {
176
171
  data() {
177
172
  return {
178
173
  image: null,
174
+ newAnnotation: [],
179
175
  };
180
176
  },
181
177
 
182
178
  computed: {
183
- ...mapState("selection", [
184
- "selectedEntities",
185
- "spanSelection",
186
- "isSelecting",
187
- ]),
179
+ ...mapState("selection", ["isSelecting", "selectedEntities"]),
188
180
  ...mapState("display", [
189
181
  "scale",
190
182
  "categorizeModalIsActive",
@@ -195,6 +187,7 @@ export default {
195
187
  ...mapState("document", [
196
188
  "documentAnnotationSelected",
197
189
  "recalculatingAnnotations",
190
+ "editAnnotation",
198
191
  "selectedDocument",
199
192
  "publicView",
200
193
  "annotationId",
@@ -205,11 +198,7 @@ export default {
205
198
  "bboxToRect",
206
199
  "scaledEntities",
207
200
  ]),
208
- ...mapGetters("selection", [
209
- "isSelectionValid",
210
- "spanSelectionsForPage",
211
- "placeholderSelectionForPage",
212
- ]),
201
+ ...mapGetters("selection", ["isSelectionValid", "isElementSelected"]),
213
202
  ...mapGetters("document", [
214
203
  "getAnnotationsFiltered",
215
204
  "isAnnotationInEditMode",
@@ -314,7 +303,12 @@ export default {
314
303
  scale() {
315
304
  this.closePopups();
316
305
  },
317
-
306
+ selectedEntities(newValue) {
307
+ if (!newValue) {
308
+ this.$store.dispatch("selection/setSpanSelection", null);
309
+ this.closePopups();
310
+ }
311
+ },
318
312
  page(newValue, oldValue) {
319
313
  if (newValue.image_url !== oldValue.image_url) {
320
314
  this.drawPage(true);
@@ -343,6 +337,7 @@ export default {
343
337
  isAnnotationFocused(annotationId) {
344
338
  return (
345
339
  this.documentAnnotationSelected &&
340
+ !this.isElementSelected &&
346
341
  annotationId === this.documentAnnotationSelected.id
347
342
  );
348
343
  },
@@ -358,8 +353,7 @@ export default {
358
353
 
359
354
  if (
360
355
  event.target.getParent() &&
361
- event.target.getParent().className === "Transformer" &&
362
- !event.target.name().includes("anchor")
356
+ event.target.getParent().className === "Transformer"
363
357
  ) {
364
358
  // if we are editing a box then close popups
365
359
  this.closePopups();
@@ -375,10 +369,7 @@ export default {
375
369
  event.target.name() === "multiAnnBoxTransformer" ||
376
370
  event.target.name() === "multiAnnButton" ||
377
371
  event.target.name() === "boxSelection" ||
378
- event.target.name() === "boxTransformer" ||
379
- event.target.name().includes("spanSelection") ||
380
- event.target.name().includes("spanTransformer") ||
381
- event.target.name().includes("anchor")
372
+ event.target.name() === "boxTransformer"
382
373
  ) {
383
374
  return;
384
375
  }
@@ -427,8 +418,104 @@ export default {
427
418
  this.closePopups();
428
419
  },
429
420
 
421
+ handleCreateAnnotationsFromSelection(entities) {
422
+ if (
423
+ this.categorizeModalIsActive ||
424
+ this.publicView ||
425
+ this.isDocumentReviewed
426
+ )
427
+ return;
428
+ this.newAnnotation = [];
429
+
430
+ const normalizedEntities = this.scaledEntities(entities, this.page);
431
+ if (normalizedEntities) {
432
+ this.newAnnotation.push(...normalizedEntities);
433
+ }
434
+
435
+ if (this.newAnnotation.length > 0) {
436
+ this.$store.dispatch(
437
+ "selection/setSelectedEntities",
438
+ this.newAnnotation
439
+ );
440
+ this.$store.dispatch(
441
+ "selection/getTextFromEntities",
442
+ this.newAnnotation
443
+ );
444
+ } else {
445
+ this.$store.dispatch("selection/setSelectedEntities", null);
446
+ }
447
+ },
448
+
449
+ handleEntitiesFromSelection(entities) {
450
+ if (
451
+ this.categorizeModalIsActive ||
452
+ this.publicView ||
453
+ this.isDocumentReviewed
454
+ )
455
+ return;
456
+
457
+ const normalizedEntities = this.scaledEntities(entities, this.page);
458
+ if (normalizedEntities.length > 0) {
459
+ this.$store.dispatch(
460
+ "selection/setSelectedEntities",
461
+ normalizedEntities
462
+ );
463
+ this.$store.dispatch(
464
+ "selection/getTextFromEntities",
465
+ normalizedEntities
466
+ );
467
+ } else {
468
+ this.$store.dispatch("selection/setSelectedEntities", null);
469
+ }
470
+ },
471
+
430
472
  handleClickedEntity(entity) {
431
- this.$store.dispatch("selection/entityClick", entity);
473
+ if (
474
+ !entity ||
475
+ this.categorizeModalIsActive ||
476
+ this.publicView ||
477
+ this.isDocumentReviewed
478
+ )
479
+ return;
480
+
481
+ // Check if we are creating a new Annotation
482
+ // or if we are removing a previously selected entity
483
+ // or editing empty one
484
+ const entityToAdd = entity;
485
+
486
+ const found = this.newAnnotation.find(
487
+ (ann) =>
488
+ ann.scaled.width === entityToAdd.scaled.width &&
489
+ ann.original.offset_string === entityToAdd.original.offset_string
490
+ );
491
+
492
+ // reset the selection so that we don't have a drawn rectangle when editing based on entities
493
+ this.endSelection();
494
+
495
+ if (found) {
496
+ this.newAnnotation = [
497
+ ...this.newAnnotation.filter(
498
+ (ann) =>
499
+ ann.scaled.width !== entityToAdd.scaled.width &&
500
+ ann.original.offset_string !== entityToAdd.original.offset_string
501
+ ),
502
+ ];
503
+ } else {
504
+ this.newAnnotation.push(entityToAdd);
505
+ }
506
+
507
+ if (this.newAnnotation.length > 0) {
508
+ this.$store.dispatch(
509
+ "selection/setSelectedEntities",
510
+ this.newAnnotation
511
+ );
512
+ this.$store.dispatch(
513
+ "selection/getTextFromEntities",
514
+ this.newAnnotation
515
+ );
516
+ } else {
517
+ this.$store.dispatch("selection/setSelectedEntities", null);
518
+ }
432
519
  },
433
520
 
434
521
  onElementEnter(annotation = null, span = null) {
@@ -506,11 +593,24 @@ export default {
506
593
  * Builds the konva config object for the entity.
507
594
  */
508
595
  entityRect(entity) {
596
+ let entityIsSelected = false;
597
+ if (this.selectedEntities && this.selectedEntities.length > 0) {
598
+ entityIsSelected = this.selectedEntities.find((selectedEntity) => {
599
+ return (
600
+ selectedEntity.original &&
601
+ selectedEntity.original.offset_string ===
602
+ entity.original.offset_string &&
603
+ selectedEntity.original.x0 === entity.original.x0 &&
604
+ selectedEntity.original.y0 === entity.original.y0
605
+ );
606
+ });
607
+ }
608
+
509
609
  return {
510
610
  stroke: "#ccc",
511
611
  strokeWidth: 1,
512
612
  dash: [5, 2],
513
- fill: "transparent",
613
+ fill: entityIsSelected ? "#67E9B7" : "transparent",
514
614
  globalCompositeOperation: "multiply",
515
615
  transformsEnabled: "position",
516
616
  hitStrokeWidth: 0,
@@ -576,10 +676,7 @@ export default {
576
676
  }
577
677
  },
578
678
  closePopups() {
579
- this.$store.dispatch("selection/entitySelection", {
580
- entities: [],
581
- selection: null,
582
- });
679
+ this.newAnnotation = [];
583
680
  },
584
681
  },
585
682
  };
@@ -105,6 +105,7 @@ export default {
105
105
  data() {
106
106
  return {
107
107
  currentPercentage: 100,
108
+ fitWidthScale: 1, // baseline for 100%
108
109
  maxPercentage: 500,
109
110
  defaultPercentage: 0.25,
110
111
  fitPercentage: 0.5,
@@ -136,6 +137,13 @@ export default {
136
137
  this.editModeDisabled = true;
137
138
  }
138
139
  },
140
+ scale(newScale) {
141
+ if (this.fitWidthScale > 0) {
142
+ this.currentPercentage = Math.round((newScale / this.fitWidthScale) * 100);
143
+ } else {
144
+ this.currentPercentage = Math.round(newScale * 100);
145
+ }
146
+ },
139
147
  },
140
148
  mounted() {
141
149
  if (this.selectedDocument) {
@@ -178,12 +186,13 @@ export default {
178
186
  this.updateScale(this.scale - this.defaultPercentage);
179
187
  },
180
188
  fitAuto() {
181
- // exit edit mode of Annotation if changing zoom during editing
182
189
  this.cancelAnnotationEditMode();
183
-
184
- // Always set to 50%
185
- this.currentPercentage = 50;
186
- this.$store.dispatch("display/updateFit", "all");
190
+ this.$store.dispatch("display/updateFit", "all").then(() => {
191
+ this.$nextTick(() => {
192
+ this.fitWidthScale = this.scale;
193
+ this.currentPercentage = 100;
194
+ });
195
+ });
187
196
  },
188
197
  updateScale(scale) {
189
198
  this.$store.dispatch("display/updateFit", "custom").then(() => {
@@ -225,6 +234,7 @@ export default {
225
234
  cancelAnnotationEditMode() {
226
235
  this.$store.dispatch("document/resetEditAnnotation");
227
236
  this.$store.dispatch("selection/disableSelection");
237
+ this.$store.dispatch("selection/setSelectedEntities", null);
228
238
  },
229
239
  },
230
240
  };