mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-17 22:08:25 +08:00
271 lines
8.2 KiB
JavaScript
271 lines
8.2 KiB
JavaScript
// 节点图片大小调整插件
|
|
import { resizeImgSizeByOriginRatio } from '../utils/index'
|
|
import btnsSvg from '../svg/btns'
|
|
|
|
class NodeImgAdjust {
|
|
// 构造函数
|
|
constructor({ mindMap }) {
|
|
this.mindMap = mindMap
|
|
this.resizeBtnSize = 26 // 调整按钮的大小
|
|
this.handleEl = null // 自定义元素,用来渲染临时图片、调整按钮
|
|
this.isShowHandleEl = false // 自定义元素是否在显示中
|
|
this.node = null // 当前节点实例
|
|
this.img = null // 当前节点的图片节点
|
|
this.rect = null // 当前图片节点的尺寸信息
|
|
this.isMousedown = false // 当前是否是按住调整按钮状态
|
|
this.currentImgWidth = 0 // 当前拖拽实时图片的大小
|
|
this.currentImgHeight = 0
|
|
this.isAdjusted = false // 是否是拖拽结束后的渲染期间
|
|
this.bindEvent()
|
|
}
|
|
|
|
// 监听事件
|
|
bindEvent() {
|
|
this.onNodeImgMouseleave = this.onNodeImgMouseleave.bind(this)
|
|
this.onNodeImgMousemove = this.onNodeImgMousemove.bind(this)
|
|
this.onMousemove = this.onMousemove.bind(this)
|
|
this.onMouseup = this.onMouseup.bind(this)
|
|
this.onRenderEnd = this.onRenderEnd.bind(this)
|
|
this.mindMap.on('node_img_mouseleave', this.onNodeImgMouseleave)
|
|
this.mindMap.on('node_img_mousemove', this.onNodeImgMousemove)
|
|
this.mindMap.on('mousemove', this.onMousemove)
|
|
this.mindMap.on('mouseup', this.onMouseup)
|
|
this.mindMap.on('node_mouseup', this.onMouseup)
|
|
this.mindMap.on('node_tree_render_end', this.onRenderEnd)
|
|
}
|
|
|
|
// 解绑事件
|
|
unBindEvent() {
|
|
this.mindMap.off('node_img_mouseleave', this.onNodeImgMouseleave)
|
|
this.mindMap.off('node_img_mousemove', this.onNodeImgMousemove)
|
|
this.mindMap.off('mousemove', this.onMousemove)
|
|
this.mindMap.off('mouseup', this.onMouseup)
|
|
this.mindMap.off('node_mouseup', this.onMouseup)
|
|
this.mindMap.off('node_tree_render_end', this.onRenderEnd)
|
|
}
|
|
|
|
// 节点图片鼠标移动事件
|
|
onNodeImgMousemove(node, img) {
|
|
// 如果当前正在拖动调整中那么直接返回
|
|
if (this.isMousedown || this.isAdjusted || this.mindMap.opt.readonly) return
|
|
// 如果在当前节点内移动,以及自定义元素已经是显示状态,那么直接返回
|
|
if (this.node === node && this.isShowHandleEl) return
|
|
// 更新当前节点信息
|
|
this.node = node
|
|
this.img = img
|
|
this.rect = this.img.rbox()
|
|
// 显示自定义元素
|
|
this.showHandleEl()
|
|
}
|
|
|
|
// 节点图片鼠标移出事件
|
|
onNodeImgMouseleave() {
|
|
if (this.isMousedown) return
|
|
this.hideHandleEl()
|
|
}
|
|
|
|
// 隐藏节点实际的图片
|
|
hideNodeImage() {
|
|
if (!this.img) return
|
|
this.img.hide()
|
|
}
|
|
|
|
// 显示节点实际的图片
|
|
showNodeImage() {
|
|
if (!this.img) return
|
|
this.img.show()
|
|
}
|
|
|
|
// 显示自定义元素
|
|
showHandleEl() {
|
|
if (!this.handleEl) {
|
|
this.createResizeBtnEl()
|
|
}
|
|
this.setHandleElRect()
|
|
this.handleEl.style.display = 'block'
|
|
this.isShowHandleEl = true
|
|
}
|
|
|
|
// 隐藏自定义元素
|
|
hideHandleEl() {
|
|
if (!this.isShowHandleEl) return
|
|
this.isShowHandleEl = false
|
|
this.handleEl.style.display = 'none'
|
|
this.handleEl.style.backgroundImage = ``
|
|
this.handleEl.style.width = 0
|
|
this.handleEl.style.height = 0
|
|
this.handleEl.style.left = 0
|
|
this.handleEl.style.top = 0
|
|
}
|
|
|
|
// 设置自定义元素尺寸位置信息
|
|
setHandleElRect() {
|
|
let { width, height, x, y } = this.rect
|
|
this.handleEl.style.left = `${x}px`
|
|
this.handleEl.style.top = `${y}px`
|
|
this.currentImgWidth = width
|
|
this.currentImgHeight = height
|
|
this.updateHandleElSize()
|
|
}
|
|
|
|
// 更新自定义元素宽高
|
|
updateHandleElSize() {
|
|
this.handleEl.style.width = `${this.currentImgWidth}px`
|
|
this.handleEl.style.height = `${this.currentImgHeight}px`
|
|
}
|
|
|
|
// 创建调整按钮元素
|
|
createResizeBtnEl() {
|
|
// 容器元素
|
|
this.handleEl = document.createElement('div')
|
|
this.handleEl.style.cssText = `
|
|
pointer-events: none;
|
|
position: fixed;
|
|
display:none;
|
|
background-size: cover;
|
|
`
|
|
this.handleEl.className = 'node-img-handle'
|
|
// 调整按钮元素
|
|
const btnEl = document.createElement('div')
|
|
btnEl.innerHTML = btnsSvg.imgAdjust
|
|
btnEl.style.cssText = `
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
pointer-events: auto;
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
width: ${this.resizeBtnSize}px;
|
|
height: ${this.resizeBtnSize}px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
cursor: nwse-resize;
|
|
`
|
|
btnEl.className = 'node-image-resize'
|
|
// 给按钮元素绑定事件
|
|
btnEl.addEventListener('mouseenter', () => {
|
|
// 移入按钮,会触发节点图片的移出事件,所以需要再次显示按钮
|
|
this.showHandleEl()
|
|
})
|
|
btnEl.addEventListener('mouseleave', () => {
|
|
// 移除按钮,需要隐藏按钮
|
|
if (this.isMousedown) return
|
|
this.hideHandleEl()
|
|
})
|
|
btnEl.addEventListener('mousedown', e => {
|
|
e.stopPropagation()
|
|
this.onMousedown(e)
|
|
})
|
|
btnEl.addEventListener('mouseup', e => {
|
|
setTimeout(() => {
|
|
//点击后直接松开异常处理; 其他事件响应之后处理
|
|
this.hideHandleEl()
|
|
this.isAdjusted = false
|
|
}, 0)
|
|
})
|
|
btnEl.addEventListener('click', e => {
|
|
e.stopPropagation()
|
|
})
|
|
this.handleEl.appendChild(btnEl)
|
|
// 删除按钮
|
|
const btnRemove = document.createElement('div')
|
|
this.handleEl.prepend(btnRemove)
|
|
btnRemove.className = 'node-image-remove'
|
|
btnRemove.innerHTML = btnsSvg.remove
|
|
btnRemove.style.cssText = `
|
|
position: absolute;
|
|
right: 0;top:0;color:#fff;
|
|
pointer-events: auto;
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
width: ${this.resizeBtnSize}px;
|
|
height: ${this.resizeBtnSize}px;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
cursor: pointer;
|
|
`
|
|
btnRemove.addEventListener('mouseenter', e => {
|
|
this.showHandleEl()
|
|
})
|
|
btnRemove.addEventListener('mouseleave', e => {
|
|
if (this.isMousedown) return
|
|
this.hideHandleEl()
|
|
})
|
|
btnRemove.addEventListener('click', e => {
|
|
this.mindMap.execCommand('SET_NODE_IMAGE', this.node, { url: null })
|
|
})
|
|
// 添加元素到页面
|
|
const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
|
|
targetNode.appendChild(this.handleEl)
|
|
}
|
|
|
|
// 鼠标按钮按下事件
|
|
onMousedown() {
|
|
this.isMousedown = true
|
|
// 隐藏节点实际图片
|
|
this.hideNodeImage()
|
|
// 将节点图片渲染到自定义元素上
|
|
this.handleEl.style.backgroundImage = `url(${this.node.nodeData.data.image})`
|
|
}
|
|
|
|
// 鼠标移动
|
|
onMousemove(e) {
|
|
if (!this.isMousedown) return
|
|
e.preventDefault()
|
|
// 计算当前拖拽位置对应的图片的实时大小
|
|
let { width: imageOriginWidth, height: imageOriginHeight } =
|
|
this.node.nodeData.data.imageSize
|
|
let newWidth = e.clientX - this.rect.x
|
|
let newHeight = e.clientY - this.rect.y
|
|
if (newWidth <= 0 || newHeight <= 0) return
|
|
let [actWidth, actHeight] = resizeImgSizeByOriginRatio(
|
|
imageOriginWidth,
|
|
imageOriginHeight,
|
|
newWidth,
|
|
newHeight
|
|
)
|
|
this.currentImgWidth = actWidth
|
|
this.currentImgHeight = actHeight
|
|
this.updateHandleElSize()
|
|
}
|
|
|
|
// 鼠标松开
|
|
onMouseup() {
|
|
if (!this.isMousedown) return
|
|
// 显示节点实际图片
|
|
this.showNodeImage()
|
|
// 隐藏自定义元素
|
|
this.hideHandleEl()
|
|
// 更新节点图片为新的大小
|
|
let { image, imageTitle } = this.node.nodeData.data
|
|
let { scaleX, scaleY } = this.mindMap.draw.transform()
|
|
this.mindMap.execCommand('SET_NODE_IMAGE', this.node, {
|
|
url: image,
|
|
title: imageTitle,
|
|
width: this.currentImgWidth / scaleX,
|
|
height: this.currentImgHeight / scaleY,
|
|
custom: true // 代表自定义了图片大小
|
|
})
|
|
this.isAdjusted = true
|
|
this.isMousedown = false
|
|
}
|
|
|
|
// 渲染完成事件
|
|
onRenderEnd() {
|
|
if (!this.isAdjusted) {
|
|
this.hideHandleEl()
|
|
return
|
|
}
|
|
this.isAdjusted = false
|
|
}
|
|
|
|
// 插件被移除前做的事情
|
|
beforePluginRemove() {
|
|
this.unBindEvent()
|
|
}
|
|
}
|
|
|
|
NodeImgAdjust.instanceName = 'nodeImgAdjust'
|
|
|
|
export default NodeImgAdjust
|