Skip to content

Instantly share code, notes, and snippets.

@DCdafan
Forked from syrxw/drr.vue
Created December 20, 2018 01:19
Show Gist options
  • Save DCdafan/1a225afb6c32598b4490a0c970a7d97c to your computer and use it in GitHub Desktop.
Save DCdafan/1a225afb6c32598b4490a0c970a7d97c to your computer and use it in GitHub Desktop.
缩放插件
<template>
<div class="container">
<div class="wrap">
<div class="d1" @mousedown="eleDown" :style="style">
</div>
</div>
<!--drr-->
<div class="drr" :style="style" :class="{active: active}" ref="drr">
<div v-if="resizable">
<div
v-for="name in handle.handles"
class="handle"
:key="name"
:class="'handle-' + name"
:style="{ display: active ? 'block' : 'none', cursor: cursorStyle[name]}"
@mousedown.stop.prevent.self="handleDown(name, $event)"
></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'home',
created(){
document.documentElement.addEventListener('mousemove', (e) => {
this.flag = true
this.eleHandleMove(e)
}, true)
document.documentElement.addEventListener('mouseup', (e) => {
if (this.flag) {
this.eleUp(e)
} else {
this.dragging = false
this.resizing = false
this.rotating = false
}
document.documentElement.removeEventListener('mousemove', this.eleHandleMove, true)
document.documentElement.removeEventListener('mousedown', this.eleHandleMove, true)
}, true)
},
computed:{
style() { //组件样式
return {
top: this.top + 'px',
left: this.left + 'px',
width: this.width + 'px',
height: this.height + 'px',
transform: 'rotate(' + this.rotate + 'deg)',
zIndex:10,
}
},
/**
* 根据旋转方向来设置操作条
* @returns {default.props.cursors|{default, type}|({} & default.props.cursors) | ({} & {default, type})}
*/
cursorStyle() {
const cursors = this.handle.cursors
const names = ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml']
const ARR_LENGTH = 8
const STEP = 45
const rotate = this.rotate
const startIndex = rotate ? Math.round(rotate / STEP) : 0
let newCursors = cursors
if (startIndex > 1) {
newCursors = Object.assign({}, cursors)
names.forEach((v, i) => {
newCursors[v] = cursors[names[(startIndex + i) % ARR_LENGTH]]
})
}
return newCursors
}
},
data(){
return {
active:false,
width:200,
height:200,
top:0,
left:0,
rotate:0,
draggable:true,
dragging:false,
resizable:true,
resizing: false,
rotatable:true,
rotating: false,
container:{
x:'',
y:'',
w:'',
h:''
},
ele:{
x:'',
y:'',
w:'',
h:''
},
current:{
mouseX:'',
mouseY:'',
centerX:'',
centerY:'',
x:'',
y:'',
w:'',
h:''
},
handle:{
x:'',
y:'',
w:'',
h:'',
name:'',
handles:['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml', 'rot'],
cursors:{
tl: 'nwse-resize',
tm: 'ns-resize',
tr: 'nesw-resize',
mr: 'ew-resize',
br: 'nwse-resize',
bm: 'ns-resize',
bl: 'nesw-resize',
ml: 'ew-resize'
}
},
fixed:{
xName:'',
yName:'',
x:'',
y:''
}
}
},
methods:{
eleDown(e){
this.active = true
if (this.draggable) {
this.eleDragDown(e)
}
},
eleHandleMove(e){
if (this.dragging) {
this.eleDrag(e)
}
if(this.resizing){
this.handleResize(e)
}
if(this.rotating){
this.handleRotate(e)
}
},
eleUp(e){
console.log(e)
let {x: mouseX, y: mouseY} = this.getMouseCoordinate(e)
this.current.mouseX = mouseX
this.current.mouseY = mouseY
this.dragging = false
this.resizing = false
this.rotating = false
},
eleDragDown(e){
this.dragging = true
let {x: mouseX, y: mouseY} = this.getMouseCoordinate(e)
// 鼠标当前位置
this.current.mouseX = mouseX
this.current.mouseY = mouseY
this.recordElePosition(e)
this.recordHandlePosition(e)
// 获取父级画布信息
// this.getContainerInfo()
//记录点击初始位置
this.current.x = this.ele.x
this.current.y = this.ele.y
},
eleDrag(e){
let {x: mouseX, y: mouseY} = this.getMouseCoordinate(e)
let diffX = mouseX - this.current.mouseX
let diffY = mouseY - this.current.mouseY
// 每一次先复原初始位置
this.ele.x = this.current.x
this.ele.y = this.current.y
this.ele.x += diffX
this.ele.y += diffY
this.left = Math.round(this.ele.x)
this.top = Math.round(this.ele.y)
},
handleDown(handleName,e){
this.handleName = handleName
if (e.stopPropagation) e.stopPropagation()
if (e.preventDefault) e.preventDefault()
this.recordHandlePosition()
if (handleName === 'rot') {
this.handleRotateDown(e)
}else{
this.handleResizeDown(handleName, e)
}
},
handleResizeDown(handleName,e){
let {x: mouseX, y: mouseY} = this.getMouseCoordinate(e)
// 鼠标当前位置
this.current.mouseX = mouseX
this.current.mouseY = mouseY
let fixedName = {
x: handleName[1] === 'l' ? 'right' : 'left',
y: handleName[0] === 't' ? 'bottom' : 'top'
}
let rect = {
top: this.top,
right: this.left + this.width,
bottom: this.top + this.height,
left: this.left
}
// 计算固定点坐标
let fixedCoordinate = this.rotatedPoint(rect, this.rotate, fixedName)
// 计算固定点名称
this.fixed.xName = fixedName.x
this.fixed.yName = fixedName.y
// 固定点坐标赋值
this.fixed.x = fixedCoordinate.x
this.fixed.y = fixedCoordinate.y
this.current.x = this.handle.x
this.current.y = this.handle.y
this.current.w = this.handle.w
this.current.h = this.handle.h
this.resizing = true
},
handleResize(e){
if(this.resizing){
let {x: mouseX, y: mouseY} = this.getMouseCoordinate(e)
let rotate = this.rotate
let width = mouseX - this.current.mouseX
let height = mouseY - this.current.mouseY
let c = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2))
let angle = this.getAngle(width, height)
let rad = Math.PI / 180 * (angle - rotate)
let diffY = Math.round(Math.sin(rad) * c)
let diffX = Math.round(Math.cos(rad) * c)
this.handle.x = this.current.x
this.handle.y = this.current.y
this.handle.w = this.current.w
this.handle.h = this.current.h
// 缩放计算
let [handleY, handleX] = this.handleName
if (handleX !== 'm') {
this.handle.w += diffX * (handleX === 'r' ? 1 : -1)
}
if (handleY !== 'm') {
this.handle.h += diffY * (handleY === 'b' ? 1 : -1)
}
// 边界处理
if (this.handle.w < 50) {
this.handle.w = 50
}
if (this.handle.h < 50) {
this.handle.h = 50
}
if (this.handle.w < 0) {
this.handle.w = -this.handle.w
this.fixedXExchange = true
}
if (this.handle.h < 0) {
this.handle.h = -this.handle.h
this.fixedYExchange = true
}
this.handleFixed()
this.left = Math.round(this.handle.x)
this.top = Math.round(this.handle.y)
this.width = Math.round(this.handle.w)
this.height = Math.round(this.handle.h)
}
},
handleRotateDown(e) {
let {x, y, w, h} = this.handle
this.current.centerX = window.pageXOffset + x + w / 2
this.current.centerY = window.pageYOffset + y + h / 2
this.rotating = true
},
handleRotate(e){
console.log(e)
if(this.rotating){
let {x: mouseX, y: mouseY} = this.getMouseCoordinate(e)
let x = mouseX - this.current.centerX
let y = mouseY - this.current.centerY
this.rotate = (this.getAngle(x, y) + 90) % 360
console.log(this.rotate)
}
},
handleFixed() {
// 获取元素区域
let rect = {
top: this.handle.y,
right: this.handle.x + this.handle.w,
bottom: this.handle.y + this.handle.h,
left: this.handle.x
}
let fixedXName, fixedYName
if (this.fixedXExchange) {
fixedXName = this.fixed.xName === 'right' ? 'left' : 'right'
} else {
fixedXName = this.fixed.xName
}
if (this.fixedYExchange) {
fixedYName = this.fixed.yName === 'top' ? 'bottom' : 'top'
} else {
fixedYName = this.fixed.yName
}
let fixed = {
x: fixedXName,
y: fixedYName
}
let {x: fixedX, y: fixedY} = this.rotatedPoint(rect, this.rotate, fixed)
let dX = Math.round(this.fixed.x - fixedX)
let dY = Math.round(this.fixed.y - fixedY)
this.handle.x += dX
this.handle.y += dY
},
/**
* 获取元素基本信息
*/
recordElePosition(e){
const info = e.target
this.ele.x = parseInt(info.style.left)
this.ele.y = parseInt(info.style.top)
this.ele.w = info.offsetWidth ||info.clientWidth
this.ele.h = info.offsetHeight || info.clientHeight
},
/**
* 获取操作条基本信息
*/
recordHandlePosition(){
const info = this.$refs.drr
this.handle.x = parseInt(info.style.left)
this.handle.y = parseInt(info.style.top)
this.handle.w = info.offsetWidth ||info.clientWidth
this.handle.h = info.offsetHeight || info.clientHeight
},
/**
* 获取鼠标位置
* @param e
* @returns {*}
*/
getMouseCoordinate(e) {
return {
x: e.pageX || e.clientX + document.documentElement.scrollLeft,
y: e.pageY || e.clientY + document.documentElement.scrollTop
}
},
/**
* 旋转点计算
* @param rect
* @param rotate
* @param point
* @returns {{x: *, y: *}}
*/
rotatedPoint(rect, rotate, point) {
let {top, right, bottom, left} = rect
let rad = Math.PI / 180 * rotate
let cos = Math.cos(rad)
let sin = Math.sin(rad)
let originX = (right - left + 1) / 2 + left
let originY = (bottom - top + 1) / 2 + top
let x = rect[point.x]
let y = rect[point.y]
x -= originX
y -= originY
return {
x: x * cos - y * sin + originX,
y: x * sin + y * cos + originY
}
},
/**
* 旋转角度
* @param x
* @param y
* @returns {number}
*/
getAngle(x, y) {
let theta = Math.atan2(y, x) // range (-PI, PI]
theta = Math.round(180 / Math.PI * theta) // rads to degs, range (-180, 180]
if (theta < 0) theta = 360 + theta // range [0, 360)
return theta
},
}
}
</script>
<style>
.container{
position: fixed;
top:0;
left: 0;
width: 100%;
height: 100%;
}
.wrap{
position: relative;
width:800px;
height:600px;
background-color: #5B6B73;
}
.d1{
position: absolute;
top: 116px;
left: 128px;
width: 160px;
height: 160px;
z-index: 7;
background-color: #108ee9;
}
.d2{
position: absolute;
top: 216px;
left: 328px;
width: 200px;
height: 200px;
z-index: 8;
background-color: #108ee9;
}
/*drr*/
.drr {
position: absolute;
box-sizing: border-box;
display: none;
pointer-events: none;
}
.drr.dragging {
user-select: none;
}
.drr.active{
display: block;
}
.drr.active:before {
content: '';
position: absolute;
top: -1px;
right: -1px;
bottom: -1px;
left: -1px;
border: 1px solid #f00;
z-index: -1;
}
.handle {
box-sizing: border-box;
display: none;
position: absolute;
width: 10px;
height: 10px;
font-size: 1px;
border-radius: 5px;
background: #eee;
border: 1px solid #1baee1;
z-index: 100;
pointer-events: auto;
}
.handle-tl {
top: -5px;
left: -5px;
}
.handle-tm {
top: -5px;
left: 50%;
margin-left: -5px;
}
.handle-tr {
top: -5px;
right: -5px;
}
.handle-ml {
top: 50%;
margin-top: -5px;
left: -5px;
}
.handle-mr {
top: 50%;
margin-top: -5px;
right: -5px;
}
.handle-bl {
bottom: -5px;
left: -5px;
}
.handle-bm {
bottom: -5px;
left: 50%;
margin-left: -5px;
}
.handle-br {
bottom: -5px;
right: -5px;
}
.handle-rot {
position: absolute;
top: 0;
left: 50%;
margin-top: -20px;
width: 10px;
height: 10px;
transform: translate(-50%, 0);
cursor: url(./img/rotate.svg) 20 20, move;
z-index: -1;
pointer-events: auto;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment