浏览代码

add: 注释支持跨页移动

liutian 2 周之前
父节点
当前提交
ec1ff0fe93

+ 15 - 1
packages/core/src/annotation/base.js

@@ -6,11 +6,13 @@ export default class BaseAnnotation {
     annotation,
     viewport,
     page,
-    eventBus
+    eventBus,
+    layer,
   }) {
     if (!annotation.name) {
       annotation.name = uuidv4()
     }
+    this.layer = layer
     this.container = container
     this.annotation = annotation
     this.viewport = viewport
@@ -27,4 +29,16 @@ export default class BaseAnnotation {
 
     this.page = page
   }
+
+  getMouseLocation(e) {
+    const documentViewer = this.layer.documentViewer
+    const scrollElement = documentViewer.getScrollViewElement();
+    const scrollLeft = scrollElement.scrollLeft || 0
+    const scrollTop = scrollElement.scrollTop || 0
+  
+    return {
+      x: e.pageX + scrollLeft,
+      y: e.pageY + scrollTop
+    }
+  }
 }

+ 99 - 60
packages/core/src/annotation/freetext.js

@@ -1,10 +1,8 @@
 import Base from './base';
-import { ALIGN } from '../../constants'
 import { getActualPoint, getClickPoint, createSvg, keepLastIndex, getInitialPoint, getHtmlToText, createElement, pastePlainText } from './utils';
-import { hexToRgb, onClickOutside } from '../ui_utils'
+import { onClickOutside } from '../ui_utils'
 
 export default class Shape extends Base {
-  
   constructor ({
     container,
     annotation = null,
@@ -20,14 +18,13 @@ export default class Shape extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show
     })
     this.enableReply = enableReply
 
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -42,7 +39,6 @@ export default class Shape extends Base {
     this.endCircle = null
 
     this.show = show
-    this.firstSelect = false
 
     this.onContainerClick = this.handleContainerClick.bind(this)
     this.onMousedown = this.handleMouseDown.bind(this)
@@ -359,9 +355,7 @@ export default class Shape extends Base {
     this.outerLineContainer.append(this.deletetButton)
     this.enableReply && this.outerLineContainer.append(this.replyButton)
     this.initial = true
-    this.firstSelect = true
     if (this.show) {
-      this.firstSelect = false
       !this.layer.addMode && this.handleElementSelect()
     }
   }
@@ -471,13 +465,12 @@ export default class Shape extends Base {
 
   // 处理选中
   handleElementSelect () {
-    this.show = false
     this.hidden = false
-    if (!this.firstSelect) {
+    if (this.show) {
       this.updateTool()
+      this.show = false
     }
     onClickOutside([this.freetextElement, this.outerLine, this.deletetButton, this.replyButton, document.querySelector('.toggle-button')], this.handleOutside.bind(this))
-    this.firstSelect = false
   }
 
   // 获取实际坐标
@@ -736,44 +729,67 @@ export default class Shape extends Base {
         rightBottom,
       });
     } else if (startState.operator === 'move') {
-      let left = pageX - (startState.clickX - leftTop.x);
-      let top = pageY - (startState.clickY - leftTop.y);
-      let right = pageX - (startState.clickX - rightBottom.x);
-      let bottom = pageY - (startState.clickY - rightBottom.y);
-
-      const rect = {
-        width: Math.abs(left - right),
-        height: Math.abs(bottom - top)
-      }
-      if (left < right) {
-        left = Math.max(12, left)
-        left = Math.min(width - rect.width - 4, left)
-        right = Math.max(rect.width + 12, right)
-        right = Math.min(width - 4, right)
-      } else {
-        right = Math.max(4, right)
-        right = Math.min(width - rect.width - 12, right)
-        left = Math.max(rect.width + 4, left)
-        left = Math.min(width - 12, left)
-      }
-
-      if (bottom < top) {
-        bottom = Math.max(6, bottom)
-        bottom = Math.min(height - rect.height - 9, bottom)
-        top = Math.max(rect.height + 6, top)
-        top = Math.min(height - 9, top)
+      let left, top, right, bottom
+      const documentViewer = this.layer.documentViewer
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(leftTop.y - rightBottom.y)
+        left = pageX - (startState.clickX - leftTop.x)
+        top = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        right = pageX - (startState.clickX - rightBottom.x)
+        bottom = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        top = Math.max(9, top)
-        top = Math.min(height - rect.height - 6, top)
-        bottom = Math.max(rect.height + 9, bottom)
-        bottom = Math.min(height - 6, bottom)
+        left = pageX - (startState.clickX - leftTop.x);
+        top = pageY - (startState.clickY - leftTop.y);
+        right = pageX - (startState.clickX - rightBottom.x);
+        bottom = pageY - (startState.clickY - rightBottom.y);  
+
+        const rect = {
+          width: Math.abs(left - right),
+          height: Math.abs(bottom - top)
+        }
+        if (left < right) {
+          left = Math.max(12, left)
+          left = Math.min(width - rect.width - 4, left)
+          right = Math.max(rect.width + 12, right)
+          right = Math.min(width - 4, right)
+        } else {
+          right = Math.max(4, right)
+          right = Math.min(width - rect.width - 12, right)
+          left = Math.max(rect.width + 4, left)
+          left = Math.min(width - 12, left)
+        }
+  
+        if (bottom < top) {
+          bottom = Math.max(6, bottom)
+          bottom = Math.min(height - rect.height - 9, bottom)
+          top = Math.max(rect.height + 6, top)
+          top = Math.min(height - 9, top)
+        } else {
+          top = Math.max(9, top)
+          top = Math.min(height - rect.height - 6, top)
+          bottom = Math.max(rect.height + 9, bottom)
+          bottom = Math.min(height - 6, bottom)
+        }
       }
 
       this.update({
         leftTop: { x: left, y: top },
         rightBottom: { x: right, y: bottom },
-      });
+      })
     }
+    startState.clickX = pageX
+    startState.clickY = pageY  
   }
 
   handleMouseUp (event) {
@@ -790,12 +806,6 @@ export default class Shape extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
 
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.leftTop = this.newStart
-    this.rightBottom = this.newEnd
-
     const annotation = this.annotation
     const { leftTop, rightBottom } = this.getInitialPoint()
 
@@ -805,27 +815,56 @@ export default class Shape extends Base {
       right: rightBottom.x,
       bottom: rightBottom.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
     annotation.rect = rect
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-annot",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-annot",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+    }
   }
 
   update ({ leftTop, rightBottom }) {
     const { width, height } = this.viewport
     const rect = this.calculate(leftTop, rightBottom)
 
-    this.newStart = leftTop
-    this.newEnd = rightBottom
+    this.leftTop = leftTop
+    this.rightBottom = rightBottom
 
     this.setCss(this.annotationContainer, {
       top: rect.top - 2 + 'px',

+ 110 - 53
packages/core/src/annotation/ink.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, getInitialPoint, createElemen
 import { onClickOutside, } from '../ui_utils'
 
 export default class Ink extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -19,14 +18,13 @@ export default class Ink extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show
     })
     this.enableReply = enableReply
 
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -79,13 +77,12 @@ export default class Ink extends Base {
 
   calculate (start, end) {
     const initRect = this.rectCalc({ start, end });
-    const actualbdwidth = this.annotation.borderWidth * this.scale
 
     return {
-      top: initRect.top - actualbdwidth,
-      left: initRect.left - actualbdwidth,
-      width: initRect.width + actualbdwidth * 2,
-      height: initRect.height + actualbdwidth * 2,
+      top: initRect.top,
+      left: initRect.left,
+      width: initRect.width,
+      height: initRect.height,
     }
   }
 
@@ -376,37 +373,59 @@ export default class Ink extends Base {
       }
      
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - start.x);
+        y1 = pageY - (startState.clickY - start.y);
+        x2 = pageX - (startState.clickX - end.x);
+        y2 = pageY - (startState.clickY - end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -414,6 +433,9 @@ export default class Ink extends Base {
         end: { x: x2, y: y2 },
       });
     }
+    startState.clickX = pageX
+    startState.clickY = pageY
+
   }
 
   handleDelete (event) {
@@ -457,8 +479,6 @@ export default class Ink extends Base {
     document.removeEventListener('mouseup', this.onMouseup)
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
-    this.start = this.newStart
-    this.end = this.newEnd
 
     this.startState = null
 
@@ -471,6 +491,10 @@ export default class Ink extends Base {
       bottom: initialEnd.y
     }
 
+    const annotation = this.annotation
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
+    annotation.rect = rect
+
     let inkPointes = []
     for (let i = 0; i < this.inkPath.length; i++) {
       const inkPathPoints = []
@@ -482,18 +506,47 @@ export default class Ink extends Base {
       }
       inkPointes.push(inkPathPoints)
     }
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-annot",
-        name: this.annotation.name,
-        pageIndex: this.page,
-        pagePtr: this.annotation.pagePtr,
-        annotPtr: this.annotation.annotPtr,
-        inkPointes,
-        rect
+    annotation.inkPointes = inkPointes
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-annot",
+          name: this.annotation.name,
+          pageIndex: this.page,
+          pagePtr: this.annotation.pagePtr,
+          annotPtr: this.annotation.annotPtr,
+          inkPointes,
+          rect
+        }
+      })
+    }
   }
 
   handlePoint (point) {
@@ -524,8 +577,8 @@ export default class Ink extends Base {
     }
 
     this.rect = rect
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     const annotation = this.annotation
     const actualbdwidth = this.annotation.borderWidth * this.scale
@@ -617,7 +670,7 @@ export default class Ink extends Base {
     bottom = parseFloat(bottom * this.scale)
     right = parseFloat(right * this.scale)
     top = parseFloat(top * this.scale)
-    const rect={
+    const rect = {
       left,
       top,
       bottom,
@@ -900,6 +953,10 @@ export default class Ink extends Base {
     this.outerLineContainer.append(this.deletetButton)
     this.enableReply && this.outerLineContainer.append(this.replyButton)
     this.initial = true
+    if (this.show) {
+      !this.layer.addMode && this.selectAnnotation()
+      this.show = false
+    }
   }
 
   openReply () {

+ 11 - 1
packages/core/src/annotation/layer.js

@@ -30,6 +30,7 @@ import Redaction from './redaction.js'
 // 注释的画布层
 class ComPDFAnnotationLayer {
   constructor({
+    documentViewer,
     annotationStore,
     pageViewer,
     messageHandler,
@@ -44,6 +45,7 @@ class ComPDFAnnotationLayer {
     enableReply = true,
     $t
   }) {
+    this.documentViewer = documentViewer
     this._cancelled = false;
     this.pageViewer = pageViewer
     this.pageDiv = pageDiv;
@@ -735,7 +737,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
-        show: true,
+        show,
         layer: this,
         enableReply
       })
@@ -748,6 +750,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         enableReply
       })
@@ -760,6 +763,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         enableReply
       })
@@ -785,6 +789,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         enableReply
       })
@@ -798,6 +803,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         enableReply
       })
@@ -810,6 +816,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         highlight: this.annotationStore.highlightForm,
         messageHandler: this.messageHandler
@@ -823,6 +830,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         highlight: this.annotationStore.highlightForm,
         messageHandler: this.messageHandler
@@ -836,6 +844,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         highlight: this.annotationStore.highlightForm,
         messageHandler: this.messageHandler
@@ -905,6 +914,7 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
+        show,
         layer: this,
         messageHandler: this.messageHandler
       })

+ 103 - 53
packages/core/src/annotation/line.js

@@ -1,7 +1,5 @@
-import { v4 as uuidv4 } from 'uuid';
 import Base from './base';
-import { hexToRgb, onClickOutside } from '../ui_utils'
-import { getAbsoluteCoordinate } from './position';
+import { onClickOutside } from '../ui_utils'
 import { getClickPoint, createSvg, createElement } from './utils';
 import { MARGIN_DISTANCE } from '../../constants'
 import ArrowHelper from './arrow'
@@ -21,13 +19,13 @@ export default class Line extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       eventBus,
       show
     })
     this.enableReply = enableReply
 
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -239,6 +237,11 @@ export default class Line extends Base {
     this.outerLineContainer.append(this.deletetButton)
     this.enableReply && this.outerLineContainer.append(this.replyButton)
     this.initial = true
+
+    if (this.show) {
+      !this.layer.addMode && this.selectAnnotation()
+      this.show = false
+    }
   }
 
   selectAnnotation () {
@@ -431,37 +434,59 @@ export default class Line extends Base {
         end: { x: x2, y: y2 },
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -469,6 +494,8 @@ export default class Line extends Base {
         end: { x: x2, y: y2 },
       });
     }
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -513,12 +540,6 @@ export default class Line extends Base {
     document.removeEventListener('mouseup', this.onMouseup)
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
-    
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
 
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
@@ -535,19 +556,48 @@ export default class Line extends Base {
       right: right + 6,
       bottom: bottom + 6
     }
-
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-annot",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        linePoints,
-        rect
+    annotation.rect = rect
+
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-annot",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          linePoints,
+          rect
+        }
+      })
+    }
   }
 
   update ({ start, end }) {
@@ -561,8 +611,8 @@ export default class Line extends Base {
       height:innerRect.height+arrowLength*2
     }
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.svgElement.setAttribute("width", rect.width);
     this.svgElement.setAttribute("height", rect.height);

+ 99 - 51
packages/core/src/annotation/link.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from './utils
 import { onClickOutside } from '../ui_utils'
 
 export default class Link extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -19,14 +18,13 @@ export default class Link extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
       show,
       highlight
     })
-
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -575,37 +573,59 @@ export default class Link extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
-      } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
+      } else {  
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -613,6 +633,9 @@ export default class Link extends Base {
         end: { x: x2, y: y2 },
       });
     }
+    startState.clickX = pageX
+    startState.clickY = pageY
+
   }
 
   handleDelete (event) {
@@ -653,12 +676,6 @@ export default class Link extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -669,24 +686,55 @@ export default class Link extends Base {
      bottom: end.y
     }
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-annot",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-annot",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 1 - 0
packages/core/src/annotation/paint/shape.js

@@ -173,6 +173,7 @@ export default class PaintShape {
 
       this.eventBus.dispatch('annotationChange', {
         type: 'add',
+        show: true,
         annotation: annotationData
       })
 

+ 2 - 3
packages/core/src/annotation/redaction.js

@@ -19,14 +19,13 @@ export default class Redaction extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
       show,
       highlight
     })
-
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -142,7 +141,7 @@ export default class Redaction extends Base {
     outerLine.style.width = `${wholeRect.width + 8 * 2 + (annotation.erasure ? actualbdwidth : actualbdwidth * 2)}px`
     outerLine.style.height = `${wholeRect.height + 8 * 2}px`
     this.outerLine = outerLine
-    
+
     this.moveRect = createSvg(
       "rect",
       {

+ 104 - 55
packages/core/src/annotation/shape.js

@@ -1,7 +1,6 @@
 import Base from './base';
-import { MARGIN_DISTANCE } from '../../constants'
 import { getActualPoint, getClickPoint, createSvg, createElement } from './utils';
-import { hexToRgb, onClickOutside } from '../ui_utils'
+import { onClickOutside } from '../ui_utils'
 
 export default class Shape extends Base {
   
@@ -20,6 +19,7 @@ export default class Shape extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
@@ -27,7 +27,6 @@ export default class Shape extends Base {
     })
     this.enableReply = enableReply
 
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -317,6 +316,10 @@ export default class Shape extends Base {
     this.outerLineContainer.append(this.deletetButton)
     this.enableReply && this.outerLineContainer.append(this.replyButton)
     this.initial = true
+    if (this.show) {
+      !this.layer.addMode && this.selectAnnotation()
+      this.show = false
+    }
   }
 
   getActualRect (viewport, s,) {
@@ -552,37 +555,59 @@ export default class Shape extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        y1 = pageY - (startState.clickY - this.start.y);
+        x1 = pageX - (startState.clickX - this.start.x);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -590,6 +615,8 @@ export default class Shape extends Base {
         end: { x: x2, y: y2 },
       });
     }
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -628,12 +655,6 @@ export default class Shape extends Base {
     document.removeEventListener('mouseup', this.onMouseup)
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
-    
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
 
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
@@ -645,31 +666,59 @@ export default class Shape extends Base {
       bottom: end.y
     }
 
-    if (rect === annotation.rect) return
-    annotation.rect = rect
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    const annotationData = {
-      operate: "mod-annot",
-      name: annotation.name,
-      pageIndex: this.page,
-      pagePtr: annotation.pagePtr,
-      annotPtr: annotation.annotPtr,
-      rect
-    }
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
+      }
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      const annotationData = {
+        operate: "mod-annot",
+        name: annotation.name,
+        pageIndex: this.page,
+        pagePtr: annotation.pagePtr,
+        annotPtr: annotation.annotPtr,
+        rect
+      }
 
-    !annotation.annotPtr && (annotationData.linePoints = [rect.left, rect.bottom, rect.right, rect.top])
+      !annotation.annotPtr && (annotationData.linePoints = [rect.left, rect.bottom, rect.right, rect.top])
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: annotationData
-    })
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: annotationData
+      })
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     const actualbdwidth = (this.annotation.borderWidth || 2) * this.scale
 

+ 102 - 53
packages/core/src/annotation/stamp.js

@@ -1,11 +1,8 @@
 import Base from './base';
 import { getActualPoint, getClickPoint, createSvg, createElement } from './utils';
-import { onClickOutside, toDateObject } from '../ui_utils'
-import dayjs from 'dayjs'
-import { TextStampColor } from '../../constants';
+import { onClickOutside } from '../ui_utils'
 
 export default class Stamp extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -22,14 +19,13 @@ export default class Stamp extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show
     })
     this.enableReply = enableReply
 
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -290,6 +286,11 @@ export default class Stamp extends Base {
 
     this.eventBus.dispatch('imageChange')
     this.layer.annotationStore.creating = false
+
+    if (this.show) {
+      !this.layer.addMode && this.selectAnnotation()
+      this.show = false
+    }
   }
 
   getActualRect (viewport, s,) {
@@ -535,37 +536,59 @@ export default class Stamp extends Base {
         end: { x, y: end.y },
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -573,6 +596,8 @@ export default class Stamp extends Base {
         end: { x: x2, y: y2 },
       });
     }
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -615,12 +640,6 @@ export default class Stamp extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -631,24 +650,54 @@ export default class Stamp extends Base {
       bottom: end.y,
     }
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-annot",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: this.annotation.pagePtr,
-        annotPtr: this.annotation.annotPtr,
-        rect
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-annot",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: this.annotation.pagePtr,
+          annotPtr: this.annotation.annotPtr,
+          rect
+        }
+      })
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 93 - 51
packages/core/src/annotation/text.js

@@ -18,6 +18,7 @@ export default class Text extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
@@ -32,7 +33,6 @@ export default class Text extends Base {
     </svg>`
     this.deleteSvgStr = `<path xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" d="M14 1.5V4.5H19V5.5H16.5V18.5H3.5V5.5H1V4.5H6V1.5H14ZM4.5 5.5V17.5H15.5V5.5H4.5ZM13 2.5V4.5H7V2.5H13ZM8.5 8V15H7.5V8H8.5ZM12.5 15V8H11.5V15H12.5Z" fill="#333333"/>`
     
-    this.layer = layer
     this.hidden = true
     this.initial = false
     this.outline = null
@@ -155,43 +155,66 @@ export default class Text extends Base {
 
     const { width, height } = this.viewport
 
-    let x1 = pageX - (startState.clickX - this.start.x);
-    let y1 = pageY - (startState.clickY - this.start.y);
-    let x2 = pageX - (startState.clickX - this.end.x);
-    let y2 = pageY - (startState.clickY - this.end.y);
+    let x1, y1, x2, y2
+    const documentViewer = this.layer.documentViewer
 
-    const rect = {
-      width: Math.abs(start.x -end.x),
-      height: Math.abs(start.y -end.y)
-    }
-    if (x1 < x2) {
-      x1 = Math.max(0, x1)
-      x1 = Math.min(width - rect.width, x1)
-      x2 = Math.max(rect.width, x2)
-      x2 = Math.min(width, x2)
-    } else {
-      x2 = Math.max(0, x2)
-      x2 = Math.min(width - rect.width, x2)
-      x1 = Math.max(rect.width, x1)
-      x1 = Math.min(width, x1)
-    }
+    let windowCoordinates = this.getMouseLocation(event);
+    const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+    if (page.first && page.first !== (this.page + 1)) {
+      const annotationHeight = Math.abs(start.y - end.y)
+      x1 = pageX - (startState.clickX - this.start.x)
+      y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+      x2 = pageX - (startState.clickX - this.end.x)
+      y2 = page.first > (this.page + 1) ? annotationHeight : height
+      this.page = page.first - 1
+
+      this.annotationContainer.remove()
+      const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+      container.append(this.annotationContainer)
 
-    if (y1 < y2) {
-      y1 = Math.max(0, y1)
-      y1 = Math.min(height - rect.height, y1)
-      y2 = Math.max(rect.height, y2)
-      y2 = Math.min(height, y2)
+      this.container = container
     } else {
-      y2 = Math.max(0, y2)
-      y2 = Math.min(height - rect.height, y2)
-      y1 = Math.max(rect.height, y1)
-      y1 = Math.min(height, y1)
+      x1 = pageX - (startState.clickX - this.start.x);
+      y1 = pageY - (startState.clickY - this.start.y);
+      x2 = pageX - (startState.clickX - this.end.x);
+      y2 = pageY - (startState.clickY - this.end.y);
+
+      const rect = {
+        width: Math.abs(start.x -end.x),
+        height: Math.abs(start.y -end.y)
+      }
+      if (x1 < x2) {
+        x1 = Math.max(0, x1)
+        x1 = Math.min(width - rect.width, x1)
+        x2 = Math.max(rect.width, x2)
+        x2 = Math.min(width, x2)
+      } else {
+        x2 = Math.max(0, x2)
+        x2 = Math.min(width - rect.width, x2)
+        x1 = Math.max(rect.width, x1)
+        x1 = Math.min(width, x1)
+      }
+
+      if (y1 < y2) {
+        y1 = Math.max(0, y1)
+        y1 = Math.min(height - rect.height, y1)
+        y2 = Math.max(rect.height, y2)
+        y2 = Math.min(height, y2)
+      } else {
+        y2 = Math.max(0, y2)
+        y2 = Math.min(height - rect.height, y2)
+        y1 = Math.max(rect.height, y1)
+        y1 = Math.min(height, y1)
+      }
     }
 
     this.update({
       start: { x: x1, y: y1 },
       end: { x: x2, y: y2 },
     });
+    startState.clickX = pageX
+    startState.clickY = pageY
+
   }
 
   handleMouseUp (event) {
@@ -207,12 +230,6 @@ export default class Text extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
 
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const start = getInitialPoint(this.start, this.viewport, this.viewport.scale)
     const end = getInitialPoint(this.end, this.viewport, this.viewport.scale)
@@ -223,25 +240,54 @@ export default class Text extends Base {
       right: end.x,
       bottom: end.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-annot",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-annot'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-annot",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+    }
   }
 
   update ({ start, end }) {
     const rect = this.rectCalc({start, end})
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'
@@ -331,7 +377,6 @@ export default class Text extends Base {
       if (this.layer.selectedElementName === this.annotation.name) {
         this.layer.selectedElementName = null
       }
-      this.outerLineContainer.remove()
     } else {
       if (this.layer.selectedElementName !== this.annotation.name) {
         const annotation = this.annotation
@@ -347,9 +392,6 @@ export default class Text extends Base {
 
         this.eventBus.dispatch('annotationSelected', annotationData)
       }
-      this.container.append(this.outerLineContainer)
-      this.outerLine.addEventListener('mousedown', this.onMousedown)
-      this.outerLine.addEventListener('touchstart', this.onMousedown)
     }
   }
 

+ 99 - 54
packages/core/src/form/check_box.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from '../anno
 import { onClickOutsideUp } from '../ui_utils'
 
 export default class CheckBox extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -20,14 +19,11 @@ export default class CheckBox extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show,
-      highlight
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.initial = false
@@ -689,37 +685,59 @@ export default class CheckBox extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -727,6 +745,9 @@ export default class CheckBox extends Base {
         end: { x: x2, y: y2 },
       });
     }
+    startState.clickX = pageX
+    startState.clickY = pageY
+
   }
 
   handleDelete (event) {
@@ -765,12 +786,6 @@ export default class CheckBox extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -780,26 +795,56 @@ export default class CheckBox extends Base {
       right: end.x,
       bottom: end.y
     }
-
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
+
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
-    this.getImage(true)
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+      this.getImage(true)
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 98 - 53
packages/core/src/form/combo_box.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from '../anno
 import { onClickOutsideUp } from '../ui_utils'
 
 export default class ComboBox extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -20,14 +19,11 @@ export default class ComboBox extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show,
-      highlight
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.initial = false
@@ -665,37 +661,59 @@ export default class ComboBox extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -703,6 +721,9 @@ export default class ComboBox extends Base {
         end: { x: x2, y: y2 },
       });
     }
+
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -741,12 +762,6 @@ export default class ComboBox extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -756,26 +771,56 @@ export default class ComboBox extends Base {
       right: end.x,
       bottom: end.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
-    this.getImage(true)
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+      this.getImage(true)
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 98 - 53
packages/core/src/form/list_box.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from '../anno
 import { onClickOutsideUp } from '../ui_utils'
 
 export default class ListBox extends Base {
-
   constructor({
     container,
     annotation,
@@ -20,14 +19,11 @@ export default class ListBox extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show,
-      highlight
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.initial = false
@@ -641,37 +637,59 @@ export default class ListBox extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x - end.x),
-        height: Math.abs(start.y - end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x - end.x),
+          height: Math.abs(start.y - end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -679,6 +697,9 @@ export default class ListBox extends Base {
         end: { x: x2, y: y2 },
       });
     }
+
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete(event) {
@@ -717,12 +738,6 @@ export default class ListBox extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
 
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -732,26 +747,56 @@ export default class ListBox extends Base {
       right: end.x,
       bottom: end.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
-    this.getImage(true)
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+      this.getImage(true)
+    }
   }
 
   update({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 98 - 54
packages/core/src/form/push_button.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from '../anno
 import { onClickOutsideUp } from '../ui_utils'
 
 export default class PushButton extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -20,14 +19,11 @@ export default class PushButton extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show,
-      highlight
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.initial = false
@@ -618,44 +614,68 @@ export default class PushButton extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
-
       this.update({
         start: { x: x1, y: y1 },
         end: { x: x2, y: y2 },
       });
     }
+
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -694,12 +714,6 @@ export default class PushButton extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -709,26 +723,56 @@ export default class PushButton extends Base {
       right: end.x,
       bottom: end.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
-    this.getImage(true)
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+      this.getImage(true)
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 99 - 54
packages/core/src/form/radio_button.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from '../anno
 import { onClickOutsideUp } from '../ui_utils'
 
 export default class RadioButton extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -20,14 +19,11 @@ export default class RadioButton extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show,
-      highlight
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.initial = false
@@ -692,37 +688,59 @@ export default class RadioButton extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -730,6 +748,9 @@ export default class RadioButton extends Base {
         end: { x: x2, y: y2 },
       });
     }
+
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -768,12 +789,6 @@ export default class RadioButton extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -783,26 +798,56 @@ export default class RadioButton extends Base {
       right: end.x,
       bottom: end.y
     }
-
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
+
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
-    this.getImage(true)
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+      this.getImage(true)
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 97 - 50
packages/core/src/form/signature_fields.js

@@ -3,7 +3,6 @@ import { getActualPoint, getClickPoint, createSvg, createElement } from '../anno
 import { onClickOutside } from '../ui_utils'
 
 export default class SignatureFields extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -18,12 +17,11 @@ export default class SignatureFields extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.outline = null
@@ -551,37 +549,59 @@ export default class SignatureFields extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -589,6 +609,9 @@ export default class SignatureFields extends Base {
         end: { x: x2, y: y2 },
       });
     }
+
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (data) {
@@ -628,12 +651,6 @@ export default class SignatureFields extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -643,25 +660,55 @@ export default class SignatureFields extends Base {
       right: end.x,
       bottom: end.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 98 - 54
packages/core/src/form/text_field.js

@@ -1,10 +1,8 @@
 import Base from '../annotation/base';
-import { MARGIN_DISTANCE } from '../../constants'
 import { getActualPoint, getClickPoint, createSvg, createElement } from '../annotation/utils';
 import { onClickOutsideUp } from '../ui_utils'
 
 export default class TextField extends Base {
-  
   constructor ({
     container,
     annotation,
@@ -21,14 +19,11 @@ export default class TextField extends Base {
       container,
       annotation,
       page,
+      layer,
       viewport,
       scale,
       eventBus,
-      show,
-      highlight
     })
-
-    this.layer = layer
     this.messageHandler = messageHandler
     this.hidden = true
     this.initial = false
@@ -623,37 +618,59 @@ export default class TextField extends Base {
         end,
       });
     } else if (startState.operator === 'move') {
-      let x1 = pageX - (startState.clickX - this.start.x);
-      let y1 = pageY - (startState.clickY - this.start.y);
-      let x2 = pageX - (startState.clickX - this.end.x);
-      let y2 = pageY - (startState.clickY - this.end.y);
-
-      const rect = {
-        width: Math.abs(start.x -end.x),
-        height: Math.abs(start.y -end.y)
-      }
-      if (x1 < x2) {
-        x1 = Math.max(0, x1)
-        x1 = Math.min(width - rect.width, x1)
-        x2 = Math.max(rect.width, x2)
-        x2 = Math.min(width, x2)
+      let x1, y1, x2, y2
+      const documentViewer = this.layer.documentViewer
+
+      let windowCoordinates = this.getMouseLocation(event);
+      const page = documentViewer.getSelectedPage(windowCoordinates, windowCoordinates)
+      if (page.first && page.first !== (this.page + 1)) {
+        const annotationHeight = Math.abs(start.y - end.y)
+        x1 = pageX - (startState.clickX - this.start.x)
+        y1 = page.first > (this.page + 1) ? 0 : height - annotationHeight
+        x2 = pageX - (startState.clickX - this.end.x)
+        y2 = page.first > (this.page + 1) ? annotationHeight : height
+        this.page = page.first - 1
+
+        this.annotationContainer.remove()
+        this.outerLineContainer.remove()
+        const container = documentViewer.pdfViewer._pages[this.page].compdfAnnotationLayer.div
+        container.append(this.annotationContainer)
+        container.append(this.outerLineContainer)
+
+        this.container = container
       } else {
-        x2 = Math.max(0, x2)
-        x2 = Math.min(width - rect.width, x2)
-        x1 = Math.max(rect.width, x1)
-        x1 = Math.min(width, x1)
-      }
+        x1 = pageX - (startState.clickX - this.start.x);
+        y1 = pageY - (startState.clickY - this.start.y);
+        x2 = pageX - (startState.clickX - this.end.x);
+        y2 = pageY - (startState.clickY - this.end.y);
+
+        const rect = {
+          width: Math.abs(start.x -end.x),
+          height: Math.abs(start.y -end.y)
+        }
+        if (x1 < x2) {
+          x1 = Math.max(0, x1)
+          x1 = Math.min(width - rect.width, x1)
+          x2 = Math.max(rect.width, x2)
+          x2 = Math.min(width, x2)
+        } else {
+          x2 = Math.max(0, x2)
+          x2 = Math.min(width - rect.width, x2)
+          x1 = Math.max(rect.width, x1)
+          x1 = Math.min(width, x1)
+        }
 
-      if (y1 < y2) {
-        y1 = Math.max(0, y1)
-        y1 = Math.min(height - rect.height, y1)
-        y2 = Math.max(rect.height, y2)
-        y2 = Math.min(height, y2)
-      } else {
-        y2 = Math.max(0, y2)
-        y2 = Math.min(height - rect.height, y2)
-        y1 = Math.max(rect.height, y1)
-        y1 = Math.min(height, y1)
+        if (y1 < y2) {
+          y1 = Math.max(0, y1)
+          y1 = Math.min(height - rect.height, y1)
+          y2 = Math.max(rect.height, y2)
+          y2 = Math.min(height, y2)
+        } else {
+          y2 = Math.max(0, y2)
+          y2 = Math.min(height - rect.height, y2)
+          y1 = Math.max(rect.height, y1)
+          y1 = Math.min(height, y1)
+        }
       }
 
       this.update({
@@ -661,6 +678,9 @@ export default class TextField extends Base {
         end: { x: x2, y: y2 },
       });
     }
+
+    startState.clickX = pageX
+    startState.clickY = pageY
   }
 
   handleDelete (event) {
@@ -699,12 +719,6 @@ export default class TextField extends Base {
     document.removeEventListener('touchmove', this.onMousemove)
     document.removeEventListener('touchend', this.onMouseup)
     
-    const { pageX, pageY } = getClickPoint(event)
-    if (pageX === this.startState.clickX && pageY === this.startState.clickY) return
-
-    this.start = this.newStart
-    this.end = this.newEnd
-
     const annotation = this.annotation
     const { start, end } = this.getInitialPoint()
 
@@ -714,26 +728,56 @@ export default class TextField extends Base {
       right: end.x,
       bottom: end.y
     }
+    if (rect === annotation.rect && annotation.pageIndex === this.page) return
 
-    this.eventBus.dispatch('annotationChange', {
-      type: 'modify',
-      annotation: {
-        operate: "mod-form",
-        name: annotation.name,
-        pageIndex: this.page,
-        pagePtr: annotation.pagePtr,
-        annotPtr: annotation.annotPtr,
-        rect
+    annotation.rect = rect
+    if (annotation.pageIndex !== this.page) {
+      const annotationData = {
+        type: 'delete',
+        annotation: {
+          operate: "del-annot",
+          name: annotation.name,
+          pageIndex: annotation.pageIndex,
+          annotPtr: annotation.annotPtr
+        }
       }
-    })
-    this.getImage(true)
+      this.eventBus.dispatch('annotationChange', annotationData)
+
+      const newAnnotationData = Object.assign({}, annotation)
+      delete newAnnotationData.annotPtr
+      delete newAnnotationData.pagePtr
+      delete newAnnotationData.name
+      newAnnotationData.operate = 'add-form'
+      newAnnotationData.pageIndex = this.page
+      this.eventBus.dispatch('annotationChange', {
+        type: 'add',
+        show: true,
+        annotation: newAnnotationData
+      })
+
+      this.annotationContainer.remove()
+      this.outerLineContainer.remove()
+    } else {
+      this.eventBus.dispatch('annotationChange', {
+        type: 'modify',
+        annotation: {
+          operate: "mod-form",
+          name: annotation.name,
+          pageIndex: this.page,
+          pagePtr: annotation.pagePtr,
+          annotPtr: annotation.annotPtr,
+          rect
+        }
+      })
+      this.getImage(true)
+    }
   }
 
   update ({ start, end }) {
     const rect = this.calculate(start, end)
 
-    this.newStart = start
-    this.newEnd = end
+    this.start = start
+    this.end = end
 
     this.annotationContainer.style.top = rect.top + 'px'
     this.annotationContainer.style.left = rect.left + 'px'

+ 5 - 0
packages/core/src/index.js

@@ -2259,6 +2259,10 @@ class ComPDFKitViewer {
     return this.scrollContainer
   }
 
+  getViewerElement() {
+    return this.viewerContainer
+  }
+
   getSelectedPage(firstCoordinates, lastCoordinates) {
     let firstPageIndex = null, lastPageIndex = null
     for (let i = 0; i < this.pagesCount; i++) {
@@ -2338,6 +2342,7 @@ class ComPDFKitViewer {
     this.pdfViewer = new PDFViewer({
       container,
       viewer,
+      documentViewer: this,
       messageHandler: this.messageHandler,
       annotationStore,
       tool: {

+ 3 - 1
packages/core/src/pdf_page_view.js

@@ -79,6 +79,7 @@ class PDFPageView {
    * @param {PDFPageViewOptions} options
    */
   constructor(options) {
+    this.documentViewer = options.documentViewer
     this._loadingId = null;
     const container = options.container;
     const defaultViewport = options.defaultViewport;
@@ -90,7 +91,6 @@ class PDFPageView {
     this.doc = options.doc;
     this.messageHandler = options.messageHandler;
 
-    this.messageHandler = options.messageHandler;
     this.pagesPtr = options.pagesPtr
     this.pdfPage = null;
     this.pageLabel = null;
@@ -552,6 +552,7 @@ class PDFPageView {
 
           if (!this.compdfAnnotationLayer) {
             this.compdfAnnotationLayer = new ComPDFAnnotationLayer({
+              documentViewer: this.documentViewer,
               annotationStore: this.annotationStore,
               messageHandler: this.messageHandler,
               pageViewer: this,
@@ -1233,6 +1234,7 @@ class PDFPageView {
 
           if (!this.compdfAnnotationLayer) {
             this.compdfAnnotationLayer = new ComPDFAnnotationLayer({
+              documentViewer: this.documentViewer,
               annotationStore: this.annotationStore,
               messageHandler: this.messageHandler,
               pageViewer: this,

+ 2 - 0
packages/core/src/pdf_viewer.js

@@ -144,6 +144,7 @@ class PDFViewer {
    * @param {PDFViewerOptions} options
    */
   constructor(options) {
+    this.documentViewer = options.documentViewer
     this.eventBus = options.eventBus;
     this._annotationEditorUIManager = null;
     this.container = options.container;
@@ -634,6 +635,7 @@ class PDFViewer {
           const pageIndex = pageNum - 1;
 
           const pageView = new PDFPageView({
+            documentViewer: this.documentViewer,
             container: viewerElement,
             eventBus: this.eventBus,
             id: pageNum,