|
@@ -33,11 +33,13 @@ class TextAnnotation extends BaseAnnotation {
|
|
|
this.outerLineContainer = null
|
|
|
this.ratio = window.devicePixelRatio || 1
|
|
|
this.ctx = this.pageViewer.canvas.getContext('2d', { willReadFrequently: true })
|
|
|
+ this.baseImageData = this.pageViewer.baseImageData
|
|
|
this.lineWidth = 2 * this.scale * this.ratio
|
|
|
|
|
|
this.onHandleClick = this.handleClick.bind(this)
|
|
|
this.onDelete = this.handleDelete.bind(this)
|
|
|
this.onOpenReply = this.openReply.bind(this)
|
|
|
+ this.onUpdateMarkup = this.updateMarkup.bind(this)
|
|
|
|
|
|
this.render()
|
|
|
}
|
|
@@ -53,11 +55,12 @@ class TextAnnotation extends BaseAnnotation {
|
|
|
|
|
|
const rect = this.calculate(start, end)
|
|
|
this.rect = rect
|
|
|
- this.baseImageData = this.ctx.getImageData(rect.left * this.ratio, rect.top * this.ratio, Math.round(rect.width * this.ratio), Math.round(rect.height * this.ratio + this.lineWidth + 2))
|
|
|
|
|
|
const quadPoints = annotation.quadPoints
|
|
|
if (!quadPoints) return
|
|
|
|
|
|
+ this.eventBus._on('markupUpdate', this.onUpdateMarkup)
|
|
|
+
|
|
|
let positionArray = []
|
|
|
for (let i = 0; (i + 3) < quadPoints.length; i+=4) {
|
|
|
const x1 = parseInt(quadPoints[i].PointX * scale, 10),
|
|
@@ -77,13 +80,10 @@ class TextAnnotation extends BaseAnnotation {
|
|
|
height
|
|
|
})
|
|
|
}
|
|
|
+ this.positionArray = positionArray
|
|
|
|
|
|
this.ctx.globalCompositeOperation = 'multiply'
|
|
|
- if (['highlight', 'underline', 'strikeout'].includes(annotation.type)) {
|
|
|
- this.renderCanvansRect(positionArray)
|
|
|
- } else if (annotation.type === 'squiggly') {
|
|
|
- this.renderSquiggly(positionArray)
|
|
|
- }
|
|
|
+ this.renderCanvansRect(positionArray)
|
|
|
this.markupContainer.addEventListener('click', this.onHandleClick)
|
|
|
|
|
|
this.outerLineContainer = document.createElement('div')
|
|
@@ -258,9 +258,14 @@ class TextAnnotation extends BaseAnnotation {
|
|
|
this.handleOutside()
|
|
|
this.markupContainer.remove()
|
|
|
|
|
|
+ this.eventBus._off('markupUpdate', this.onUpdateMarkup)
|
|
|
this.ctx.clearRect(this.rect.left * this.ratio, this.rect.top * this.ratio, this.rect.width * this.ratio, this.rect.height * this.ratio)
|
|
|
- this.ctx.putImageData(this.baseImageData, this.rect.left * this.ratio, this.rect.top * this.ratio)
|
|
|
- this.baseImageData = null
|
|
|
+ this.ctx.putImageData(this.baseImageData, 0, 0, this.rect.left * this.ratio, this.rect.top * this.ratio, Math.round(this.rect.width * this.ratio + this.lineWidth + 2), Math.round(this.rect.height * this.ratio + this.lineWidth + 2))
|
|
|
+ this.eventBus.dispatch('markupUpdate', {
|
|
|
+ name: this.annotation.name,
|
|
|
+ pageIndex: this.page,
|
|
|
+ rect: this.rect
|
|
|
+ })
|
|
|
|
|
|
this.annotation.isDelete = true
|
|
|
const annotationData = {
|
|
@@ -288,10 +293,6 @@ class TextAnnotation extends BaseAnnotation {
|
|
|
}
|
|
|
|
|
|
renderCanvansRect (positionArray) {
|
|
|
- const annotation = this.annotation
|
|
|
- const { R, G, B } = convertColorToRGB(annotation.color)
|
|
|
- this.ctx.fillStyle = `rgba(${R}, ${G}, ${B}, ${annotation.opacity || 1})`
|
|
|
-
|
|
|
const markupContainer = document.createElement('div')
|
|
|
markupContainer.className = 'markup'
|
|
|
|
|
@@ -306,58 +307,79 @@ class TextAnnotation extends BaseAnnotation {
|
|
|
height: position.height + 'px'
|
|
|
})
|
|
|
markupContainer.append(container)
|
|
|
-
|
|
|
- if (annotation.type === 'highlight') {
|
|
|
- this.ctx.fillRect(position.left * this.ratio, position.top * this.ratio, position.width * this.ratio, position.height * this.ratio)
|
|
|
- } else if (annotation.type === 'underline') {
|
|
|
- this.ctx.fillRect(position.left * this.ratio, (position.top + position.height) * this.ratio, position.width * this.ratio, this.lineWidth)
|
|
|
- } else if (annotation.type === 'strikeout') {
|
|
|
- this.ctx.fillRect(position.left * this.ratio, (position.top + (position.height / 2)) * this.ratio, position.width * this.ratio, this.lineWidth)
|
|
|
- }
|
|
|
}
|
|
|
-
|
|
|
+ this.drawCanvas(positionArray)
|
|
|
this.container.append(markupContainer)
|
|
|
this.markupContainer = markupContainer
|
|
|
}
|
|
|
+
|
|
|
+ openReply () {
|
|
|
+ this.eventBus.dispatch('openAnnotationReply', this.annotation)
|
|
|
+ }
|
|
|
|
|
|
- renderSquiggly (positionArray) {
|
|
|
- const annotation = this.annotation
|
|
|
- const markupContainer = document.createElement('div')
|
|
|
- markupContainer.className = 'markup'
|
|
|
+ updateMarkup (data) {
|
|
|
+ if (data.pageIndex !== this.page || data.name === this.annotation.name) return
|
|
|
|
|
|
- const amplitude = 4 * this.scale // 波动幅度
|
|
|
- const wavelength = 42 * this.scale // 波长
|
|
|
- const { R, G, B } = convertColorToRGB(annotation.color)
|
|
|
- this.ctx.strokeStyle = `rgba(${R}, ${G}, ${B}, ${annotation.opacity || 1})`
|
|
|
- this.ctx.lineWidth = this.lineWidth
|
|
|
+ const rect1 = this.rect
|
|
|
+ const rect2 = data.rect
|
|
|
|
|
|
- for (let i = 0; i < positionArray.length; i++) {
|
|
|
- const position = positionArray[i]
|
|
|
- const container = document.createElement('div')
|
|
|
- this.setCss(container, {
|
|
|
- position: 'absolute',
|
|
|
- overflow: 'hidden',
|
|
|
- opacity: annotation.opacity || 1,
|
|
|
- top: position.top + 'px',
|
|
|
- left: position.left + 'px',
|
|
|
- width: position.width + 'px',
|
|
|
- height: position.height + 'px',
|
|
|
- })
|
|
|
- markupContainer.append(container)
|
|
|
+ if (rect1.left > rect2.left + rect2.width ||
|
|
|
+ rect1.left + rect1.width < rect2.left ||
|
|
|
+ rect1.top > rect2.top + rect2.height ||
|
|
|
+ rect1.top + rect1.height < rect2.top
|
|
|
+ ) return
|
|
|
|
|
|
- this.ctx.beginPath()
|
|
|
- for (let x = position.left * this.ratio; x <= (position.left + position.width) * this.ratio; x++) {
|
|
|
- const y = (position.top + position.height) * this.ratio + amplitude * Math.sin((x / wavelength) * 2 * Math.PI)
|
|
|
- this.ctx.lineTo(x, y)
|
|
|
+ this.ctx.clearRect(this.rect.left * this.ratio, this.rect.top * this.ratio, this.rect.width * this.ratio, this.rect.height * this.ratio)
|
|
|
+ this.ctx.putImageData(this.baseImageData, 0, 0, this.rect.left * this.ratio, this.rect.top * this.ratio, Math.round(this.rect.width * this.ratio + this.lineWidth + 2), Math.round(this.rect.height * this.ratio + this.lineWidth + 2))
|
|
|
+ this.drawCanvas(this.positionArray)
|
|
|
+ }
|
|
|
+
|
|
|
+ drawCanvas(positionArray) {
|
|
|
+ const annotation = this.annotation
|
|
|
+ if (['highlight', 'underline', 'strikeout'].includes(annotation.type)) {
|
|
|
+ const { R, G, B } = convertColorToRGB(annotation.color)
|
|
|
+ this.ctx.fillStyle = `rgba(${R}, ${G}, ${B}, ${annotation.opacity || 1})`
|
|
|
+
|
|
|
+ const markupContainer = document.createElement('div')
|
|
|
+ markupContainer.className = 'markup'
|
|
|
+
|
|
|
+ for (let i = 0; i < positionArray.length; i++) {
|
|
|
+ const position = positionArray[i]
|
|
|
+ const container = document.createElement('div')
|
|
|
+ this.setCss(container, {
|
|
|
+ position: 'absolute',
|
|
|
+ top: position.top + 'px',
|
|
|
+ left: position.left + 'px',
|
|
|
+ width: position.width + 'px',
|
|
|
+ height: position.height + 'px'
|
|
|
+ })
|
|
|
+ markupContainer.append(container)
|
|
|
+
|
|
|
+ if (annotation.type === 'highlight') {
|
|
|
+ this.ctx.fillRect(position.left * this.ratio, position.top * this.ratio, position.width * this.ratio, position.height * this.ratio)
|
|
|
+ } else if (annotation.type === 'underline') {
|
|
|
+ this.ctx.fillRect(position.left * this.ratio, (position.top + position.height) * this.ratio, position.width * this.ratio, this.lineWidth)
|
|
|
+ } else if (annotation.type === 'strikeout') {
|
|
|
+ this.ctx.fillRect(position.left * this.ratio, (position.top + (position.height / 2)) * this.ratio, position.width * this.ratio, this.lineWidth)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (annotation.type === 'squiggly') {
|
|
|
+ const amplitude = 3 * this.scale // 波动幅度
|
|
|
+ const wavelength = 20 * this.scale // 波长
|
|
|
+ const { R, G, B } = convertColorToRGB(annotation.color)
|
|
|
+ this.ctx.strokeStyle = `rgba(${R}, ${G}, ${B}, ${annotation.opacity || 1})`
|
|
|
+ this.ctx.lineWidth = this.lineWidth
|
|
|
+
|
|
|
+ for (let i = 0; i < positionArray.length; i++) {
|
|
|
+ const position = positionArray[i]
|
|
|
+ this.ctx.beginPath()
|
|
|
+ for (let x = position.left * this.ratio; x <= (position.left + position.width) * this.ratio; x++) {
|
|
|
+ const y = (position.top + position.height) * this.ratio + amplitude * Math.sin((x / wavelength) * 2 * Math.PI)
|
|
|
+ this.ctx.lineTo(x, y)
|
|
|
+ }
|
|
|
+ this.ctx.stroke()
|
|
|
}
|
|
|
- this.ctx.stroke()
|
|
|
}
|
|
|
- this.container.append(markupContainer)
|
|
|
- this.markupContainer = markupContainer
|
|
|
- }
|
|
|
-
|
|
|
- openReply () {
|
|
|
- this.eventBus.dispatch('openAnnotationReply', this.annotation)
|
|
|
}
|
|
|
}
|
|
|
|