The renderings are as follows:
Making the address
Method of use
Introduce JS and corresponding CSS. If you really need it, just copy the corresponding folder dragger.js and dragger. CSS into your own project and use it
import Drag from '.. /.. /static/dragger.js'
import './assets/css/dragger.css'
Copy the code
After that, instantiate
new Drag({
id: 'box-dragger'.showAngle: true.isScale: false.showBorder: false
})
new Drag({
id: 'box-dragger2'.canZoom: false.canRotate: false
})
new Drag({
id: 'img-box'.showAngle: true.showPosition: true
})
new Drag({
id: 'test'
})
Copy the code
Implementation (encapsulation details)
Functional details:
- rotating
- The zoom
- translation
Technical difficulties:
- Notice that the position of each point in the box changes as you rotate
- After being dragged, the left and top of the box have changed. When calculating the left and top, it is necessary to rotate and align them according to the central axis before calculation
- If only one box is selected, click whichever box is selected. (How to ensure that operations do not affect each other when multiple Drag objects are instantiated on the current page)
- There are two different ways to implement this:
- You can select an element and add points to it directly
- There is a Pannel. When you select an element, locate the Pannel to the location of the element
I’ve done both of these once, the first one is easier, but the first one, it’s hard to control the selection of an element so that the action point is displayed.
How to encapsulate:
Consider how to let users quickly start using, can refer to the point:
- What required parameters does the user need to pass in
- What configurable parameters and methods are exposed to the user
Implementation process:
Configurable parameter
field | instructions | If required | The default value |
---|---|---|---|
id | Target element ID | is | There is no |
container | The parent container id | no | body |
canRotate | Can I rotate it | no | true |
canZoom | Can I scale | no | true |
canPull | Can I pull it up | no | true |
canMove | Can I shift it | no | true |
showAngle | Show the Angle | no | false |
showPosition | Show the location | no | false |
isScale | Whether to scale equally | no | true |
showBorder | Whether to display the border of the Pannel | no | false |
attribute
- canRotate
- canZoom
- canPull
- canMove
- showAngle
- isScale
- id
- container
- targetObj
- PannelDom divdom operation
- .
See the picture:
Code interpretation
-
Initialization parameter
-
Initialize the location of the target DOM object:
- Left horizontal distance to the left
- top
- width
- height
- angle
- RightBottomPoint The lower-right coordinate of the target DOM object
- RightTopPoint Upper right coordinate of the target DOM object
- LeftTopPoint Upper left coordinate of the target DOM object
- LeftBottomPoint The lower-left coordinate of the target DOM object
- LeftMiddlePoint Left-center coordinate of the target DOM object
- RightMiddlePoint Right-center coordinates of the target DOM object
- TopMiddlePoint The middle coordinate of the target DOM object
- BottomMiddlePoint Middle coordinates of the target DOM object
- CenterPos Specifies the center point of the target DOM object
-
Initialize the Pannel structure there is only one Pannel structure in the parent container. Each time the object is instantiated, it determines that if the parent container already has a pannel structure with the ID of Pannel, it clears its children and re-renders the Pannel structure according to the attributes passed in by the current instantiated object. If no structure with id pannel exists, create one.
-
Initialization event
- Bind the mouseDown event to pannelDom and targetObj
- Bind the Document to mousemove and mouseup events
initEvent () { document.addEventListener('mousemove', e => { e.preventDefault && e.preventDefault() this.moveChange(e, this.targetObj) }) document.addEventListener('mouseup', e => { this.moveLeave(this.targetObj) }) if (this.canMove) { // The outer layer adds a mouseDown event to this.pannelDom. After all instantiations, pannelDom is displayed on the last instantiated object and a moveInit event is triggered when the mouse is pressed on it this.pannelDom.onmousedown = e= > { e.stopPropagation() this.moveInit(9, e, this.targetObj) } this.targetObj.onmousedown = e= > { e.stopPropagation() this.moveInit(9, e, this.targetObj) this.initPannel() // When clicking on another unselected element, Pannel locates that element and overrides the pannelDom event because this.pannelDom has already been overridden based on the new target element this.pannelDom.onmousedown= e= > { this.moveInit(9, e, this.targetObj) } } } } Copy the code
-
Dom manipulation
- Rotation operation
- When the mouse is pressed down, record the arctangent function A1 of y/x between the current mouse position and the box center.
this.mouseInit = { x: Math.floor(e.clientX), y: Math.floor(e.clientY) } this.preRadian = Math.atan2(this.mouseInit.y - this.centerPos.y, this.mouseInit.x - this.centerPos.x) Copy the code
- When the mouse moves, the record calculates the arctangent function A2 of y/x from the center of the box.
this.rotateCurrent = { x: Math.floor(e.clientX), y: Math.floor(e.clientY) } this.curRadian = Math.atan2(this.rotateCurrent.y - this.centerPos.y, this.rotateCurrent.x - this.centerPos.x) Copy the code
- A2 minus A1, to figure out how many radians we’re moving
this.tranformRadian = this.curRadian - this.preRadian Copy the code
- This.getrotate (target) = this.getrotate (target) = this.getrotate (target)
this.angle = this.getRotate(target) + Math.round(this.tranformRadian * 180 / Math.PI) this.preRadian = this.curRadian // The Angle is calculated for each mouse move, so the radian value before each move is the radian value after the last move Copy the code
- Calculate the coordinates of each point of the box after rotation. According to the cosine formula, pass in: coordinates of each point before rotation, coordinates of the center of rotation and rotation Angle
let disAngle = this.angle - this.initAngle this.rightBottomPoint = this.getRotatedPoint(this.initRightBottomPoint, this.centerPos, disAngle) this.rightTopPoint = this.getRotatedPoint(this.initRightTopPoint, this.centerPos, disAngle) this.leftTopPoint = this.getRotatedPoint(this.initLeftTopPoint, this.centerPos, disAngle) this.leftBottomPoint = this.getRotatedPoint(this.initLeftBottomPoint, this.centerPos, disAngle) this.leftMiddlePoint = this.getRotatedPoint(this.initLeftMiddlePoint, this.centerPos, disAngle) this.rightMiddlePoint = this.getRotatedPoint(this.initRightMiddlePoint, this.centerPos, disAngle) this.topMiddlePoint = this.getRotatedPoint(this.initTopMiddlePoint, this.centerPos, disAngle) this.bottomMiddlePoint = this.getRotatedPoint(this.initBottomMiddlePoint, this.centerPos, disAngle) Copy the code
Copy the code
- When the mouse is pressed down, record the arctangent function A1 of y/x between the current mouse position and the box center.
- Pull operation in one direction.
- Scale along an Angle. These two operations mainly refer to the github Wiki address implemented by a big guy’s drag and drop idea
- Rotation operation
-
Optimized mousemove event to add throttling function
function throttle(fn, interval) { let canRun = true; return function () { if(! canRun)return; canRun = false; setTimeout((a)= > { fn.apply(this.arguments); canRun = true; }, interval); }; } let that = this document.addEventListener('mousemove', throttle(function (e) { e.preventDefault && e.preventDefault() that.moveChange(e, that.targetObj) }, 10)) Copy the code