实现
实现大概思路是通过transform 的scale属性实现元素缩放,通过translate 设置偏移,transform-origin设置缩放圆点
transform
translate
用translate的主要原因是因为,他的值是相对于父元素的相对位置,方便后面缩放偏移量的计算,而top,left的值是相对于目标元素而言,所以当目标元素的高度或宽度高于容器的高度或宽度时,他的值为负数,不方便计算目标物距离容器左上角的距离,不方便计算偏移量。
scale
scale缩放好处在于不需要考虑被缩放物的内部布局,width、height在缩放div时就不适用了,在缩放图片时没有影响
tranform-origin
在本文中主要作用于元素缩放圆点
计算偏移量公式
如下计算公式,其实就相当于根据鼠标当前位置进行中心缩放
当前鼠标 X 轴的坐标到目标元素左上角的距离 = 相当于X轴的半径
当前鼠标 Y 轴的坐标到目标元素左上角的距离 = 相当于Y轴的半径
translateX-=([缩放后的宽度-缩放前的宽度]*([当前鼠标 X 轴的坐标到目标元素左上角的距离]/缩放前的宽度))
translateY-=([缩放后的高度-缩放前的高度]*([当前鼠标 Y 轴的坐标到目标元素左上角的距离]/缩放前的高度))
实例
<div class="container">
<div class="draw"></div>
</div>
mouseEvent(target) {
/**
* 判断传入参数是否是HTML DOM
*/
let isElement = (obj) => {
return typeof HTMLElement === "object"
? obj instanceof HTMLElement
: !!(
obj &&
typeof obj === "object" &&
(obj.nodeType === 1 || obj.nodeType === 9) &&
typeof obj.nodeName === "string"
)
}
/**
* 被拖拽物、被缩放元素
*/
let drawEl =target;
/**
* 如果传入参数不是一个HTML DOM,则查找目标元素
*/
if(!isElement(target)){
drawEl= document.querySelector(target)
}
/**
* 父元素:容器
*/
const parent = drawEl.parentElement
/**
* 获取父元素的大小及其相对于视口的位置。
*/
const parentRect = parent.getBoundingClientRect()
/**
* 鼠标相对于目标物缩放点的距离
*/
let diffX = 0,
diffY = 0
/**
* 是否正在拖拽
*/
let isDrawing = false
/**
* 鼠标当前相对于父容器的坐标
*/
let mouseX = 0,
mouseY = 0
/**
* 偏移坐标,缩放比例
*/
let translateX = 0,
translateY = 0
let scale = 1
/**
* 一次缩放的比例
*/
const diff = 0.005
/**
* 滚轮滚动方向是否向上
* 向上,缩小
* 向下,放大
*/
let isUpward = false
/**
* 刷新鼠标距离目标元素缩放点的距离
*/
let refreshMousePositionDiffValue = () => {
diffX = mouseX - translateX
diffY = mouseY - translateY
}
/**
* 更新样式
*/
let refreshTargetStyle = () => {
drawEl.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`
parent.style.cursor = isDrawing ? "move" : "default"
}
/**
* 鼠标移动事件
*/
parent.addEventListener("mousemove", (e) => {
mouseX = e.x - parentRect.left
mouseY = e.y - parentRect.top
if (isDrawing) {
translateX = mouseX - diffX
translateY = mouseY - diffY
refreshTargetStyle()
}
})
/**
* 鼠标按下事件
*/
parent.addEventListener("mousedown", () => {
refreshMousePositionDiffValue()
isDrawing = true
refreshTargetStyle()
})
/**
* 鼠标抬起事件
*/
window.addEventListener("mouseup", () => {
isDrawing = false
refreshTargetStyle()
})
/**
* 鼠标滚动事件
*/
let mouseZoom = (e) => {
e = e || window.event
if (e.wheelDelta) {
isUpward = e.wheelDelta > 0
} else if (e.detail) {
isUpward = e.detail < 0
}
let oldWidth = scale * drawEl.clientWidth
let oldHeight = scale * drawEl.clientHeight
if (isUpward) {
scale += diff
} else if (!isUpward && scale > 0.05) {
scale -= diff
}
let newWidth = scale * drawEl.clientWidth
let newHeight = scale * drawEl.clientHeight
//刷新鼠标距离目标元素缩放点坐标
refreshMousePositionDiffValue()
/**
* 重新计算缩放偏移量
*/
translateX -= (newWidth - oldWidth) * (diffX / oldWidth)
translateY -= (newHeight - oldHeight) * (diffY / oldHeight)
refreshTargetStyle()
}
/**
* 鼠标滚轮兼容
*/
/*IE、Opera注册事件*/
if (document.attachEvent) {
parent.attachEvent("onmousewheel", mouseZoom)
}
//Firefox使用addEventListener添加滚轮事件
if (document.addEventListener) {
parent.addEventListener("DOMMouseScroll", mouseZoom, false)
}
//Safari与Chrome属于同一类型
window.onmousewheel = parent.onmousewheel = mouseZoom
/**
* 页面初始化
*/
/**
* 判断缩放元素高度是否高于容器高度
* 如果大于,则缩放值容器高度
*/
if (drawEl.clientHeight > parent.clientHeight) {
scale =
1 - (drawEl.clientHeight - parent.clientHeight) / drawEl.clientHeight
}
/**
* 让目标元素居中显示
*/
translateX = (parent.clientWidth - (scale * drawEl.clientWidth)) / 2
translateY = (parent.clientHeight - (scale * drawEl.clientHeight)) / 2
//设置初始样式
drawEl.style.transformOrigin = "0 0"
/**
* 当目标元素 是img时,需要禁用元素鼠标可拖拽
* div user-drag 默认是none 可以不设置
*/
drawEl.style.userDrag='none'
drawEl.style.webkitUserDrag='none';
//禁用选则,防止拖拽时出现先择元素内部元素的情况
drawEl.style.userSelect='none'
refreshTargetStyle()
}
mouseEvent('.draw')