let _ = { MIN_LIMIT: 48, // Min size of zone DECIMAL_PLACES: 4 // Hotzone positioning decimal point limit number of digits } /** * Get a power result of 10 for the power of the constant * @return {Number} */ _.getMultiple = (decimalPlaces = _.DECIMAL_PLACES) => { return Math.pow(10, decimalPlaces) } /** * Limit decimal places * @param {Number} num * @return {Number} */ _.decimalPoint = (val = 0) => { return Math.round(val * _.getMultiple()) / _.getMultiple() || 0 } /** * Get element width and height * @param {Object} elem * @return {Object} */ _.getOffset = (elem = {}) => ({ width: elem.clientWidth || 0, height: elem.clientHeight || 0 }) /** * Get pageX * @param {Object} e * @return {Number} */ _.getPageX = (e) => ('pageX' in e) ? e.pageX : e.touches[0].pageX /** * Get pageY * @param {Object} e * @return {Number} */ _.getPageY = (e) => ('pageY' in e) ? e.pageY : e.touches[0].pageY /** * Gets the abscissa value of the mouse click relative to the target node * @param {Object} e * @param {Object} container * @return {Number} */ _.getDistanceX = (e, container) => _.getPageX(e) - (container.getBoundingClientRect().left + window.pageXOffset) /** * Gets the ordinate value of the mouse click relative to the target node * @param {Object} e * @param {Object} container * @return {Number} */ _.getDistanceY = (e, container) => _.getPageY(e) - (container.getBoundingClientRect().top + window.pageYOffset) /** * Treatment of boundary conditions when changing the size of the hotzone * @param {Object} itemInfo * @param {Object} styleInfo * @param {Object} container */ _.dealEdgeValue = (itemInfo, styleInfo, container) => { if (styleInfo.hasOwnProperty('left') && styleInfo.left < 0) { styleInfo.left = 0 styleInfo.width = itemInfo.width + itemInfo.left } if (styleInfo.hasOwnProperty('top') && styleInfo.top < 0) { styleInfo.top = 0 styleInfo.height = itemInfo.height + itemInfo.top } if (!styleInfo.hasOwnProperty('left') && styleInfo.hasOwnProperty('width')) { if (itemInfo.left + styleInfo.width > container.width) { styleInfo.width = container.width - itemInfo.left } } if (!styleInfo.hasOwnProperty('top') && styleInfo.hasOwnProperty('height')) { if (itemInfo.top + styleInfo.height > container.height) { styleInfo.height = container.height - itemInfo.top } } return Object.assign(itemInfo, styleInfo) } /** * Handle different drag points, capital letters mean: T-top,L-left,C-center,R-right,B-bottom * @param {Object} itemInfo * @param {Number} moveX * @param {Number} moveY * @return {Object} */ _.dealTL = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let width = itemInfo.width - moveX let height = itemInfo.height - moveY if (width >= Math.min(minLimit, itemInfo.width)) { Object.assign(styleInfo, { width, left: itemInfo.left + moveX }) } if (height >= Math.min(minLimit, itemInfo.height)) { Object.assign(styleInfo, { height, top: itemInfo.top + moveY }) } return styleInfo } _.dealTC = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let height = itemInfo.height - moveY if (height >= Math.min(minLimit, itemInfo.height)) { styleInfo = { height, top: itemInfo.top + moveY } } return styleInfo } _.dealTR = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let width = itemInfo.width + moveX let height = itemInfo.height - moveY if (width >= Math.min(minLimit, itemInfo.width)) { Object.assign(styleInfo, { width }) } if (height >= Math.min(minLimit, itemInfo.height)) { Object.assign(styleInfo, { height, top: itemInfo.top + moveY }) } return styleInfo } _.dealCL = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let width = itemInfo.width - moveX if (width >= Math.min(minLimit, itemInfo.width)) { Object.assign(styleInfo, { width, left: itemInfo.left + moveX }) } return styleInfo } _.dealCR = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let width = itemInfo.width + moveX if (width >= Math.min(minLimit, itemInfo.width)) { Object.assign(styleInfo, { width }) } return styleInfo } _.dealBL = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let width = itemInfo.width - moveX let height = itemInfo.height + moveY if (width >= Math.min(minLimit, itemInfo.width)) { Object.assign(styleInfo, { width, left: itemInfo.left + moveX }) } if (height >= Math.min(minLimit, itemInfo.height)) { Object.assign(styleInfo, { height }) } return styleInfo } _.dealBC = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let height = itemInfo.height + moveY if (height >= Math.min(minLimit, itemInfo.height)) { Object.assign(styleInfo, { height }) } return styleInfo } _.dealBR = (itemInfo, moveX, moveY, minLimit = _.MIN_LIMIT) => { let styleInfo = {} let width = itemInfo.width + moveX let height = itemInfo.height + moveY if (width >= Math.min(minLimit, itemInfo.width)) { Object.assign(styleInfo, { width }) } if (height >= Math.min(minLimit, itemInfo.height)) { Object.assign(styleInfo, { height }) } return styleInfo } let addItem = { bind: function (el, binding, vnode) { const MIN_LIMIT = _.MIN_LIMIT // 拖拽添加 // el.addEventListener('mousedown', handleMouseDown) function handleMouseDown (e) { e && e.preventDefault() let itemInfo = { top: _.getDistanceY(e, el), left: _.getDistanceX(e, el), width: 0, height: 0 } let container = _.getOffset(el) // Only used once at the beginning of init let setting = { topPer: _.decimalPoint(itemInfo.top / container.height), leftPer: _.decimalPoint(itemInfo.left / container.width), widthPer: 0, heightPer: 0 } let preX = _.getPageX(e) let preY = _.getPageY(e) vnode.context.addhotZoneItem(setting) window.addEventListener('mousemove', handleChange) window.addEventListener('mouseup', handleMouseUp) function handleChange (e) { e && e.preventDefault() let moveX = _.getPageX(e) - preX let moveY = _.getPageY(e) - preY preX = _.getPageX(e) preY = _.getPageY(e) // Not consider the direction of movement first, consider only the lower right drag point let minLimit = 0 let styleInfo = _.dealBR(itemInfo, moveX, moveY, minLimit) // Boundary value processing itemInfo = _.dealEdgeValue(itemInfo, styleInfo, container) Object.assign(el.lastElementChild.style, { top: `${itemInfo.top}px`, left: `${itemInfo.left}px`, width: `${itemInfo.width}px`, height: `${itemInfo.height}px` }) } function handleMouseUp () { let perInfo = { topPer: _.decimalPoint(itemInfo.top / container.height), leftPer: _.decimalPoint(itemInfo.left / container.width), widthPer: _.decimalPoint(itemInfo.width / container.width), heightPer: _.decimalPoint(itemInfo.height / container.height) } if (vnode.context.isOverRange()) { vnode.context.overRange() } else if (container.height < MIN_LIMIT && itemInfo.width > MIN_LIMIT) { vnode.context.changeItem(Object.assign(perInfo, { topPer: 0, heightPer: 1 })) } else if (container.width < MIN_LIMIT && itemInfo.height > MIN_LIMIT) { vnode.context.changeItem(Object.assign(perInfo, { leftper: 0, widthPer: 1 })) } else if (itemInfo.width > MIN_LIMIT && itemInfo.height > MIN_LIMIT) { vnode.context.changeItem(perInfo) } else { vnode.context.eraseItem() } window.removeEventListener('mousemove', handleChange) window.removeEventListener('mouseup', handleMouseUp) } } el.$destroy = () => el.removeEventListener('mousedown', handleMouseDown) }, unbind: function (el) { el.$destroy() } } let changeSize = { bind: function (el, binding, vnode) { el.addEventListener('mousedown', handleMouseDown) function handleMouseDown (e) { let pointer = e.target.dataset.pointer if (!pointer) { return } e && e.stopPropagation() let zone = el.parentNode let setting = vnode.context.setting let container = _.getOffset(zone.parentNode) let itemInfo = { width: _.getOffset(zone).width || 0, height: _.getOffset(zone).height || 0, top: setting.topPer * container.height || 0, left: setting.leftPer * container.width || 0 } let preX = _.getPageX(e) let preY = _.getPageY(e) let flag // Hide the info displayed by hover vnode.context.handlehideZone(true) window.addEventListener('mousemove', handleChange) window.addEventListener('mouseup', handleMouseUp) function handleChange (e) { e && e.preventDefault() flag = true let moveX = _.getPageX(e) - preX let moveY = _.getPageY(e) - preY preX = _.getPageX(e) preY = _.getPageY(e) // Handling the situation when different dragging points are selected let styleInfo = _[pointer](itemInfo, moveX, moveY) // Boundary value processing itemInfo = _.dealEdgeValue(itemInfo, styleInfo, container) Object.assign(zone.style, { top: `${itemInfo.top}px`, left: `${itemInfo.left}px`, width: `${itemInfo.width}px`, height: `${itemInfo.height}px` }) } function handleMouseUp () { if (flag) { flag = false let perInfo = { topPer: _.decimalPoint(itemInfo.top / container.height), leftPer: _.decimalPoint(itemInfo.left / container.width), widthPer: _.decimalPoint(itemInfo.width / container.width), heightPer: _.decimalPoint(itemInfo.height / container.height) } vnode.context.changeInfo(perInfo) // 兼容数据无变更情况下导致 computed 不更新,数据仍为 px 时 resize 出现的问题 Object.assign(zone.style, { top: `${itemInfo.top}px`, left: `${itemInfo.left}px`, width: `${itemInfo.width}px`, height: `${itemInfo.height}px` }) } // Show the info vnode.context.handlehideZone(false) window.removeEventListener('mousemove', handleChange) window.removeEventListener('mouseup', handleMouseUp) } } el.$destroy = () => el.removeEventListener('mousedown', handleMouseDown) }, unbind: function (el) { el.$destroy() } } let dragItem = { bind: function (el, binding, vnode) { el.addEventListener('mousedown', handleMouseDown) function handleMouseDown (e) { e && e.stopPropagation() let container = _.getOffset(el.parentNode) let preX = _.getPageX(e) let preY = _.getPageY(e) let topPer let leftPer let flag window.addEventListener('mousemove', handleChange) window.addEventListener('mouseup', handleMouseUp) function handleChange (e) { e && e.preventDefault() flag = true // Hide the info displayed by hover vnode.context.handlehideZone(true) let setting = vnode.context.setting let moveX = _.getPageX(e) - preX let moveY = _.getPageY(e) - preY setting.topPer = setting.topPer || 0 setting.leftPer = setting.leftPer || 0 topPer = _.decimalPoint(moveY / container.height + setting.topPer) leftPer = _.decimalPoint(moveX / container.width + setting.leftPer) // Hotzone moving boundary processing if (topPer < 0) { topPer = 0 moveY = -container.height * setting.topPer } if (leftPer < 0) { leftPer = 0 moveX = -container.width * setting.leftPer } if (topPer + setting.heightPer > 1) { topPer = 1 - setting.heightPer moveY = container.height * (topPer - setting.topPer) } if (leftPer + setting.widthPer > 1) { leftPer = 1 - setting.widthPer moveX = container.width * (leftPer - setting.leftPer) } el.style.transform = `translate(${moveX}px, ${moveY}px)` } function handleMouseUp () { if (flag) { flag = false el.style.transform = 'translate(0, 0)' vnode.context.changeInfo({ topPer, leftPer }) } // Show the info vnode.context.handlehideZone(false) window.removeEventListener('mousemove', handleChange) window.removeEventListener('mouseup', handleMouseUp) } } el.$destroy = () => el.removeEventListener('mousedown', handleMouseDown) }, unbind: function (el) { el.$destroy() } } // export default _