mirror of https://github.com/doccano/doccano.git
Hironsan
6 years ago
4 changed files with 151 additions and 135 deletions
Unified View
Diff Options
-
BINapp/db.sqlite3
-
2app/server/static/bundle/sequence_labeling.js
-
276app/server/static/js/sequence_labeling.js
-
8app/server/templates/annotation/sequence_labeling.html
2
app/server/static/bundle/sequence_labeling.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,142 +1,158 @@ |
|||||
import Vue from 'vue'; |
import Vue from 'vue'; |
||||
Vue.use(require('vue-shortkey'), { prevent: ['input', 'textarea'] }); |
|
||||
import annotationMixin from './mixin.js'; |
|
||||
import HTTP from './http.js'; |
|
||||
|
import annotationMixin from './mixin'; |
||||
|
import HTTP from './http'; |
||||
|
|
||||
|
Vue.use(require('vue-shortkey'), { |
||||
|
prevent: ['input', 'textarea'], |
||||
|
}); |
||||
|
|
||||
Vue.component('annotator', { |
Vue.component('annotator', { |
||||
template: '<div @click="setSelectedRange">\ |
|
||||
|
template: '<div @click="setSelectedRange">\ |
||||
<span v-for="r in chunks"\ |
<span v-for="r in chunks"\ |
||||
v-bind:class="{tag: r.label.text_color}"\ |
|
||||
v-bind:style="{ color: r.label.text_color, backgroundColor: r.label.background_color }"\ |
|
||||
|
v-bind:class="{tag: id2label[r.label].text_color}"\ |
||||
|
v-bind:style="{ color: id2label[r.label].text_color, backgroundColor: id2label[r.label].background_color }"\ |
||||
>{{ text.slice(r.start_offset, r.end_offset) }}<button class="delete is-small"\ |
>{{ text.slice(r.start_offset, r.end_offset) }}<button class="delete is-small"\ |
||||
v-if="r.label.text_color"\ |
|
||||
@click="deleteLabel(r)"></button></span>\ |
|
||||
|
v-if="id2label[r.label].text_color"\ |
||||
|
@click="removeLabel(r)"></button></span>\ |
||||
</div>', |
</div>', |
||||
props: { |
|
||||
'labels': Array, // [{id: Integer, color: String, text: String}]
|
|
||||
'text': String, |
|
||||
'entityPositions': Array, //[{'startOffset': 10, 'endOffset': 15, 'label_id': 1}]
|
|
||||
|
props: { |
||||
|
labels: Array, // [{id: Integer, color: String, text: String}]
|
||||
|
text: String, |
||||
|
entityPositions: Array, // [{'startOffset': 10, 'endOffset': 15, 'label_id': 1}]
|
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
startOffset: 0, |
||||
|
endOffset: 0, |
||||
|
}; |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
setSelectedRange(e) { |
||||
|
let start; |
||||
|
let end; |
||||
|
if (window.getSelection) { |
||||
|
const range = window.getSelection().getRangeAt(0); |
||||
|
const preSelectionRange = range.cloneRange(); |
||||
|
preSelectionRange.selectNodeContents(this.$el); |
||||
|
preSelectionRange.setEnd(range.startContainer, range.startOffset); |
||||
|
start = preSelectionRange.toString().length; |
||||
|
end = start + range.toString().length; |
||||
|
} else if (document.selection && document.selection.type !== 'Control') { |
||||
|
const selectedTextRange = document.selection.createRange(); |
||||
|
const preSelectionTextRange = document.body.createTextRange(); |
||||
|
preSelectionTextRange.moveToElementText(this.$el); |
||||
|
preSelectionTextRange.setEndPoint('EndToStart', selectedTextRange); |
||||
|
start = preSelectionTextRange.text.length; |
||||
|
end = start + selectedTextRange.text.length; |
||||
|
} |
||||
|
this.startOffset = start; |
||||
|
this.endOffset = end; |
||||
|
console.log(start, end); |
||||
|
}, |
||||
|
|
||||
|
validRange() { |
||||
|
if (this.startOffset === this.endOffset) { |
||||
|
return false; |
||||
|
} |
||||
|
if (this.startOffset > this.text.length || this.endOffset > this.text.length) { |
||||
|
return false; |
||||
|
} |
||||
|
if (this.startOffset < 0 || this.endOffset < 0) { |
||||
|
return false; |
||||
|
} |
||||
|
return true; |
||||
|
}, |
||||
|
|
||||
|
resetRange() { |
||||
|
this.startOffset = 0; |
||||
|
this.endOffset = 0; |
||||
|
}, |
||||
|
|
||||
|
addLabel(labelId) { |
||||
|
if (this.validRange()) { |
||||
|
const label = { |
||||
|
start_offset: this.startOffset, |
||||
|
end_offset: this.endOffset, |
||||
|
label: labelId, |
||||
|
}; |
||||
|
this.$emit('add-label', label); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
removeLabel(index) { |
||||
|
this.$emit('remove-label', index); |
||||
}, |
}, |
||||
data() { |
|
||||
return { |
|
||||
startOffset: 0, |
|
||||
endOffset: 0, |
|
||||
} |
|
||||
|
|
||||
|
makeLabel(startOffset, endOffset) { |
||||
|
const label = { |
||||
|
id: 0, |
||||
|
label: -1, |
||||
|
start_offset: startOffset, |
||||
|
end_offset: endOffset, |
||||
|
}; |
||||
|
return label; |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
watch: { |
||||
|
entityPositions() { |
||||
|
this.resetRange(); |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
computed: { |
||||
|
sortedEntityPositions() { |
||||
|
this.entityPositions = this.entityPositions.sort((a, b) => a.start_offset - b.start_offset); |
||||
|
return this.entityPositions; |
||||
}, |
}, |
||||
methods: { |
|
||||
setSelectedRange: function (e) { |
|
||||
if (window.getSelection) { |
|
||||
var range = window.getSelection().getRangeAt(0); |
|
||||
var preSelectionRange = range.cloneRange(); |
|
||||
preSelectionRange.selectNodeContents(this.$el); |
|
||||
preSelectionRange.setEnd(range.startContainer, range.startOffset); |
|
||||
var start = preSelectionRange.toString().length; |
|
||||
var end = start + range.toString().length; |
|
||||
} else if (document.selection && document.selection.type != 'Control') { |
|
||||
var selectedTextRange = document.selection.createRange(); |
|
||||
var preSelectionTextRange = document.body.createTextRange(); |
|
||||
preSelectionTextRange.moveToElementText(this.$el); |
|
||||
preSelectionTextRange.setEndPoint('EndToStart', selectedTextRange); |
|
||||
var start = preSelectionTextRange.text.length; |
|
||||
var end = start + selectedTextRange.text.length; |
|
||||
} |
|
||||
this.startOffset = start; |
|
||||
this.endOffset = end; |
|
||||
console.log(start, end); |
|
||||
}, |
|
||||
validRange: function () { |
|
||||
if (this.startOffset == this.endOffset) { |
|
||||
return false |
|
||||
} else if (this.startOffset > this.text.length || this.endOffset > this.text.length) { |
|
||||
return false |
|
||||
} else if (this.startOffset < 0 || this.endOffset < 0) { |
|
||||
return false |
|
||||
} else { |
|
||||
return true |
|
||||
} |
|
||||
}, |
|
||||
resetRange: function () { |
|
||||
this.startOffset = 0; |
|
||||
this.endOffset = 0 |
|
||||
}, |
|
||||
addLabel: function (label_id) { |
|
||||
if (this.validRange()) { |
|
||||
var label = { |
|
||||
start_offset: this.startOffset, |
|
||||
end_offset: this.endOffset, |
|
||||
label_id: label_id |
|
||||
}; |
|
||||
this.$emit('add-label', label); |
|
||||
} |
|
||||
}, |
|
||||
deleteLabel: function (index) { |
|
||||
this.$emit('delete-label', index); |
|
||||
}, |
|
||||
makeLabel: function (start_offset, end_offset) { |
|
||||
var label = { |
|
||||
id: 0, |
|
||||
label: { |
|
||||
id: -1, |
|
||||
text: '', |
|
||||
shortcut: '', |
|
||||
background_color: '', |
|
||||
text_color: '' |
|
||||
}, |
|
||||
start_offset: start_offset, |
|
||||
end_offset: end_offset |
|
||||
} |
|
||||
return label |
|
||||
} |
|
||||
|
|
||||
|
chunks() { |
||||
|
const res = []; |
||||
|
let left = 0; |
||||
|
for (let i = 0; i < this.sortedEntityPositions.length; i++) { |
||||
|
const e = this.sortedEntityPositions[i]; |
||||
|
const l = this.makeLabel(left, e.start_offset); |
||||
|
res.push(l); |
||||
|
res.push(e); |
||||
|
left = e.end_offset; |
||||
|
} |
||||
|
const l = this.makeLabel(left, this.text.length); |
||||
|
res.push(l); |
||||
|
|
||||
|
return res; |
||||
}, |
}, |
||||
watch: { |
|
||||
entityPositions: function () { |
|
||||
this.resetRange() |
|
||||
} |
|
||||
|
|
||||
|
id2label() { |
||||
|
let id2label = {}; |
||||
|
// default value;
|
||||
|
id2label[-1] = { |
||||
|
text_color: '', |
||||
|
background_color: '', |
||||
|
}; |
||||
|
for (let i = 0; i < this.labels.length; i++) { |
||||
|
const label = this.labels[i]; |
||||
|
id2label[label.id] = label; |
||||
|
} |
||||
|
return id2label; |
||||
}, |
}, |
||||
computed: { |
|
||||
sortedEntityPositions: function () { |
|
||||
this.entityPositions = this.entityPositions.sort((a, b) => a.start_offset - b.start_offset); |
|
||||
return this.entityPositions |
|
||||
}, |
|
||||
chunks: function () { |
|
||||
var res = []; |
|
||||
var left = 0; |
|
||||
for (let i in this.sortedEntityPositions) { |
|
||||
var e = this.sortedEntityPositions[i]; |
|
||||
var l = this.makeLabel(left, e['start_offset']) |
|
||||
res.push(l); |
|
||||
res.push(e); |
|
||||
left = e['end_offset']; |
|
||||
} |
|
||||
var l = this.makeLabel(left, this.text.length) |
|
||||
res.push(l) |
|
||||
|
}, |
||||
|
}); |
||||
|
|
||||
return res |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
|
const vm = new Vue({ |
||||
|
el: '#mail-app', |
||||
|
delimiters: ['[[', ']]'], |
||||
|
mixins: [annotationMixin], |
||||
|
methods: { |
||||
|
annotate(labelId) { |
||||
|
this.$refs.annotator.addLabel(labelId); |
||||
|
}, |
||||
|
|
||||
var vm = new Vue({ |
|
||||
el: '#mail-app', |
|
||||
delimiters: ['[[', ']]'], |
|
||||
mixins: [annotationMixin], |
|
||||
methods: { |
|
||||
annotate: function (label_id) { |
|
||||
var payload = this.$refs.annotator.addLabel(label_id); |
|
||||
}, |
|
||||
addLabel: function (label) { |
|
||||
var payload = label; |
|
||||
var doc_id = this.items[this.cur].id; |
|
||||
payload['label'] = label.label_id; |
|
||||
HTTP.post(`docs/${doc_id}/annotations/`, payload).then(response => { |
|
||||
this.items[this.cur]['labels'].push(response.data); |
|
||||
}) |
|
||||
}, |
|
||||
deleteLabel: function (label) { |
|
||||
var doc_id = this.items[this.cur].id; |
|
||||
HTTP.delete(`docs/${doc_id}/annotations/${label.id}`).then(response => { |
|
||||
this.items[this.cur]['labels'].splice(this.items[this.cur]['labels'].indexOf(label), 1) |
|
||||
}); |
|
||||
}, |
|
||||
} |
|
||||
}); |
|
||||
|
addLabel(annotation) { |
||||
|
const docId = this.docs[this.pageNumber].id; |
||||
|
HTTP.post(`docs/${docId}/annotations/`, annotation).then((response) => { |
||||
|
this.annotations[this.pageNumber].push(response.data); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}); |
Write
Preview
Loading…
Cancel
Save