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

  1. Initialization parameter

  2. 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
  3. 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.

  4. 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
  5. 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
    • 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
  6. 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