|
@@ -0,0 +1,290 @@
|
|
|
+import {
|
|
|
+ getAbsoluteCoordinate,
|
|
|
+ createElement,
|
|
|
+ getInitialPoint,
|
|
|
+ getSvgPathFromStroke
|
|
|
+} from '../annotation/utils'
|
|
|
+
|
|
|
+export default class AddImage {
|
|
|
+ constructor ({
|
|
|
+ tool,
|
|
|
+ color,
|
|
|
+ container,
|
|
|
+ viewport,
|
|
|
+ page,
|
|
|
+ eventBus,
|
|
|
+ contentContainer
|
|
|
+ }) {
|
|
|
+ this._tool = tool
|
|
|
+ this.color = color
|
|
|
+ this.container = container
|
|
|
+ this.viewport = viewport
|
|
|
+ this.page = page
|
|
|
+ this.eventBus = eventBus
|
|
|
+ this.contentContainer = contentContainer
|
|
|
+
|
|
|
+ this.path = []
|
|
|
+ this.initStartPoint = null
|
|
|
+ this.initEndPoint = null
|
|
|
+ this.shapeEle = null
|
|
|
+
|
|
|
+ this.onMousedown = this.handleMouseDown.bind(this)
|
|
|
+ this.onMouseup = this.handleMouseUp.bind(this)
|
|
|
+ this.onMousemove = this.handleMouseMove.bind(this)
|
|
|
+
|
|
|
+ this.init()
|
|
|
+ }
|
|
|
+
|
|
|
+ init () {
|
|
|
+ this.container.addEventListener('mousedown', this.onMousedown)
|
|
|
+ this.container.addEventListener('touchstart', this.onMousedown)
|
|
|
+ this.container.style.cursor = 'crosshair'
|
|
|
+ this.container.style.touchAction = 'none'
|
|
|
+ document.removeEventListener('mousemove', this.onMousemove)
|
|
|
+ document.removeEventListener('mouseup', this.onMouseup)
|
|
|
+ document.removeEventListener('touchmove', this.onMousemove)
|
|
|
+ document.removeEventListener('touchend', this.onMouseup)
|
|
|
+ }
|
|
|
+
|
|
|
+ get tool () {
|
|
|
+ return this._tool
|
|
|
+ }
|
|
|
+
|
|
|
+ set tool (toolType) {
|
|
|
+ if (toolType === this._tool) return
|
|
|
+ if (!toolType) {
|
|
|
+ this.reset()
|
|
|
+ this.container.style.cursor = 'default'
|
|
|
+ this.container.style.touchAction = ''
|
|
|
+
|
|
|
+ this.container.removeEventListener('mousedown', this.onMousedown)
|
|
|
+ this.container.removeEventListener('touchstart', this.onMousedown)
|
|
|
+ }
|
|
|
+ this._tool = toolType
|
|
|
+ }
|
|
|
+
|
|
|
+ reset () {
|
|
|
+ this.initStartPoint = null
|
|
|
+ this.initEndPoint = null
|
|
|
+ if (this.shapeEle) this.shapeEle.remove()
|
|
|
+ this.shapeEle = null
|
|
|
+ this.path = []
|
|
|
+ document.removeEventListener('mousemove', this.onMousemove)
|
|
|
+ document.removeEventListener('mouseup', this.onMouseup)
|
|
|
+
|
|
|
+ document.removeEventListener('touchmove', this.onMousemove)
|
|
|
+ document.removeEventListener('touchend', this.onMouseup)
|
|
|
+
|
|
|
+ this.container.removeEventListener('mousedown', this.onMousedown)
|
|
|
+ this.container.removeEventListener('touchstart', this.onMousedown)
|
|
|
+ }
|
|
|
+
|
|
|
+ handleMouseDown (event) {
|
|
|
+ if ((!event.target.className && !event.target.className.includes('contentContainer')) || this.contentContainer.selectedFrameIndex !== -1) return
|
|
|
+ const { x, y } = getAbsoluteCoordinate(this.container, event)
|
|
|
+ this.initStartPoint = { x, y }
|
|
|
+
|
|
|
+ document.addEventListener('mousemove', this.onMousemove)
|
|
|
+ document.addEventListener('mouseup', this.onMouseup)
|
|
|
+
|
|
|
+ document.addEventListener('touchmove', this.onMousemove)
|
|
|
+ document.addEventListener('touchend', this.onMouseup)
|
|
|
+ }
|
|
|
+
|
|
|
+ handleMouseUp () {
|
|
|
+ let initStartPoint = this.initStartPoint
|
|
|
+ let initEndPoint = this.initEndPoint
|
|
|
+ if (initEndPoint && initStartPoint.x !== initEndPoint.x && initStartPoint.y !== initEndPoint.y) {
|
|
|
+ let start = getInitialPoint(initStartPoint, this.viewport, this.viewport.scale)
|
|
|
+ let end = getInitialPoint(initEndPoint, this.viewport, this.viewport.scale)
|
|
|
+
|
|
|
+ const newStart = {
|
|
|
+ x: Math.min(start.x, end.x),
|
|
|
+ y: Math.min(start.y, end.y)
|
|
|
+ }
|
|
|
+ const newEnd = {
|
|
|
+ x: Math.max(start.x, end.x),
|
|
|
+ y: Math.max(start.y, end.y)
|
|
|
+ }
|
|
|
+
|
|
|
+ const rect = {
|
|
|
+ left: newStart.x,
|
|
|
+ top: newStart.y,
|
|
|
+ right: newEnd.x,
|
|
|
+ bottom: newStart.y,
|
|
|
+ width: newEnd.x - newStart.x,
|
|
|
+ height: newEnd.y - newStart.y
|
|
|
+ }
|
|
|
+
|
|
|
+ this.uploadFile()
|
|
|
+ .then((data) => {
|
|
|
+ const { imageBase64, width, height } = data
|
|
|
+
|
|
|
+ const imageRatio = width / height
|
|
|
+ const rectRatio = rect.width / rect.height
|
|
|
+ let scaledWidth, scaledHeight
|
|
|
+
|
|
|
+ if (imageRatio > rectRatio) {
|
|
|
+ scaledWidth = rect.width
|
|
|
+ scaledHeight = rect.width / imageRatio
|
|
|
+ } else {
|
|
|
+ scaledWidth = rect.height * imageRatio
|
|
|
+ scaledHeight = rect.height
|
|
|
+ }
|
|
|
+
|
|
|
+ let left, right, bottom, top
|
|
|
+ const centerPoint = {
|
|
|
+ x: rect.left + rect.width / 2,
|
|
|
+ y: rect.top + rect.height / 2
|
|
|
+ }
|
|
|
+
|
|
|
+ left = centerPoint.x - scaledWidth / 2
|
|
|
+ right = centerPoint.x + scaledWidth / 2
|
|
|
+ bottom = centerPoint.y + scaledHeight / 2
|
|
|
+ top = centerPoint.y - scaledHeight / 2
|
|
|
+
|
|
|
+ this.contentContainer.addImageEditor({
|
|
|
+ rect: {
|
|
|
+ left,
|
|
|
+ right,
|
|
|
+ bottom,
|
|
|
+ top
|
|
|
+ },
|
|
|
+ imageBase64
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .catch((error) => {
|
|
|
+ console.error(error)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // this.reset()
|
|
|
+ this.initStartPoint = null
|
|
|
+ this.initEndPoint = null
|
|
|
+ if (this.shapeEle) this.shapeEle.remove()
|
|
|
+ this.shapeEle = null
|
|
|
+ this.path = []
|
|
|
+ document.removeEventListener('mousemove', this.onMousemove)
|
|
|
+ document.removeEventListener('mouseup', this.onMouseup)
|
|
|
+
|
|
|
+ document.removeEventListener('touchmove', this.onMousemove)
|
|
|
+ document.removeEventListener('touchend', this.onMouseup)
|
|
|
+ }
|
|
|
+
|
|
|
+ handleMouseMove (event) {
|
|
|
+ let { x, y } = getAbsoluteCoordinate(this.container, event)
|
|
|
+ const { width, height } = this.viewport
|
|
|
+ const scale = this.viewport.scale
|
|
|
+ x = Math.min(width, x)
|
|
|
+ x = Math.max(0, x)
|
|
|
+ y = Math.min(height, y)
|
|
|
+ y = Math.max(0, y)
|
|
|
+ this.initEndPoint = { x, y }
|
|
|
+ if (this.initStartPoint.x !== this.initEndPoint.x && this.initStartPoint.y !== this.initEndPoint.y) {
|
|
|
+ if (!this.shapeEle) {
|
|
|
+ const shapeEle = createElement('div', {
|
|
|
+ 'backgroundColor': '#DDE9FF',
|
|
|
+ 'position': "absolute",
|
|
|
+ 'z-index': 3
|
|
|
+ },
|
|
|
+ {
|
|
|
+ class: 'add-text'
|
|
|
+ })
|
|
|
+ this.shapeEle = shapeEle
|
|
|
+ this.container.append(this.shapeEle)
|
|
|
+ } else {
|
|
|
+ if (event.shiftKey) {
|
|
|
+ const { initStartPoint, initEndPoint } = this
|
|
|
+ const distanceX = Math.abs(initEndPoint.x - initStartPoint.x)
|
|
|
+ const distanceY = Math.abs(initEndPoint.y - initStartPoint.y)
|
|
|
+ const distance = Math.min(distanceX, distanceY)
|
|
|
+ if (initStartPoint.x < initEndPoint.x) {
|
|
|
+ initEndPoint.x = initStartPoint.x + distance
|
|
|
+ } else {
|
|
|
+ initEndPoint.x = initStartPoint.x - distance
|
|
|
+ }
|
|
|
+ if (initStartPoint.y < initEndPoint.y) {
|
|
|
+ initEndPoint.y = initStartPoint.y + distance
|
|
|
+ } else {
|
|
|
+ initEndPoint.y = initStartPoint.y - distance
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const rect = this.calculate(this.initStartPoint, this.initEndPoint)
|
|
|
+
|
|
|
+ const shapeEle = this.shapeEle
|
|
|
+ shapeEle.style.top = `${rect.top}px`
|
|
|
+ shapeEle.style.left = `${rect.left}px`
|
|
|
+ shapeEle.style.width = `${Math.abs(rect.width - 1)}px`
|
|
|
+ shapeEle.style.height = `${Math.abs(rect.height - 1)}px`
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rectCalc ({ start, end }) {
|
|
|
+ return {
|
|
|
+ top: start.y < end.y ? start.y : end.y,
|
|
|
+ left: start.x < end.x ? start.x : end.x,
|
|
|
+ width: Math.abs(end.x - start.x),
|
|
|
+ height: Math.abs(end.y - start.y),
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ calculate (start, end) {
|
|
|
+ const initRect = this.rectCalc({ start, end })
|
|
|
+ const actualbdwidth = 1 * this.viewport.scale
|
|
|
+
|
|
|
+ return {
|
|
|
+ top: initRect.top - actualbdwidth,
|
|
|
+ left: initRect.left - actualbdwidth,
|
|
|
+ width: initRect.width + actualbdwidth * 2,
|
|
|
+ height: initRect.height + actualbdwidth * 2,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上传图片并获取宽高
|
|
|
+ uploadFile () {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const fileInput = document.createElement('input')
|
|
|
+ fileInput.type = 'file'
|
|
|
+ fileInput.accept = '.jpg, .jpeg, .png, .bmp'
|
|
|
+
|
|
|
+ fileInput.onchange = () => {
|
|
|
+ const file = fileInput.files[0]
|
|
|
+
|
|
|
+ if (file.size > 2 * 1024 * 1024) {
|
|
|
+ reject('文件大小超过2M限制')
|
|
|
+ fileInput.remove()
|
|
|
+ window.$message.error('The file size exceeds the 2M limit.', {
|
|
|
+ duration: 3000,
|
|
|
+ // icon: () => h('img', { src: MessageError })
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (file) {
|
|
|
+ const reader = new FileReader()
|
|
|
+ reader.onload = function (e) {
|
|
|
+ const image = new Image()
|
|
|
+ image.onload = function () {
|
|
|
+ resolve({
|
|
|
+ // file,
|
|
|
+ imageBase64: e.target.result,
|
|
|
+ width: image.width,
|
|
|
+ height: image.height
|
|
|
+ })
|
|
|
+ }
|
|
|
+ image.onerror = function (error) {
|
|
|
+ reject(error)
|
|
|
+ }
|
|
|
+ image.src = e.target.result
|
|
|
+ }
|
|
|
+ reader.onerror = function (error) {
|
|
|
+ reject(error)
|
|
|
+ }
|
|
|
+ reader.readAsDataURL(file)
|
|
|
+ fileInput.remove()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fileInput.click()
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|