/**
* 矩阵类
* @class Matrix
* @description 用于处理矩阵的类
*/
class Matrix {
/**
* 构造方法
*
* @param {Number} row 行数
* @param {Number} column 列数
* @param {Array} value 值
*/
constructor(row, column, value) {
this.r = row
this.c = column
for (let i = 0; i < row; i++) {
this[i] = []
}
if (value) {
for (let i = 0; i < this.r; i++) {
for (let j = 0; j < this.c; j++) {
this[i][j] = value[i][j] ?? this[i][j]
}
}
}
}
/**
* 矩阵相乘
*
* @param {Object} other 矩阵
* @return {Matrix} 结果
* */
multiplyD(other) {
const result = new Matrix(this.r, other.c, null)
const n = this.c
for (let i = 0; i < result.r; i++) {
for (let j = 0; j < result.c; j++) {
let value = 0
for (let k = 0; k < n; k++) {
value += this[i][k] * other[k][j]
}
result[i][j] = value
}
}
return result
}
}
/**
* 屏幕移动类
* @class ScreenMove
* @description 用于处理屏幕鼠标平移缩放的类
*/
class ScreenMove {
/**
* 构造方法
* @description 父容器需提前指定宽高
* @param {string} fatherContainerId 父容器id
* @param {string} sonContainerId 子容器id
* @param {Boolean} translate 平移
* @param {Boolean} scale 缩放
* @param {Boolean} exceedScreen 超出屏幕
* @param {Number} translateSpeed 平移速度
* @param {Number} scaleSpeed 缩放速度
*/
constructor(fatherContainerId, sonContainerId,
translate = true, scale = true, exceedScreen = false,
translateSpeed = 2, scaleSpeed = 1) {
this._config = {
translate: true,
scale: true,
translateSpeed: 2,
scaleSpeed: 1,
sonContainerId: '',
fatherContainerId: '',
exceedScreen: false,
}
this._x = 0
this._y = 0
this._s = 1
this._$translate = null
this._$scale = null
this._moveDelta = 0
// 获取父元素,给元素添加指定样式
const $container = document.getElementById(fatherContainerId)
if ($container === null) {
throw new Error('查找不到父容器id')
}
this._config.fatherContainerId = fatherContainerId
$container.style.overflow = 'hidden'
$container.style.position = 'relative'
// 指定父容器事件监听
$container.addEventListener('mousemove', this.#handle_move.bind(this))
$container.addEventListener('click', this.#handle_click.bind(this), true)
$container.addEventListener('mousewheel', this.#handle_wheel.bind(this))
const _$translate = document.createElement('div')
_$translate.style.transformOrigin = '0 0'
const _$scale = document.createElement('div')
_$scale.style.transformOrigin = '0 0'
// 子容器
const $content = document.getElementById(sonContainerId)
if ($content === null) {
throw new Error('查找不到子容器id')
}
this._config.sonContainerId = sonContainerId
$content.style.width = 'max-content'
$content.style.height = 'max-content'
$container.appendChild(_$translate)
_$translate.appendChild(_$scale)
_$scale.appendChild($content)
this._$translate = _$translate
this._$scale = _$scale
this._config.translate = translate
this._config.scale = scale
this._config.translateSpeed = translateSpeed
this._config.scaleSpeed = scaleSpeed
this._config.exceedScreen = exceedScreen
this.#adaptive($content)
}
/**
* son 自适应页面大小
*
* @param {Object} $content 元素
* */
#adaptive($content) {
if ($content.offsetWidth < document.getElementById(this._config.fatherContainerId).offsetWidth &&
$content.offsetHeight < document.getElementById(this._config.fatherContainerId).offsetHeight) {
this._s = Math.max(document.getElementById(this._config.fatherContainerId).offsetWidth /
$content.offsetWidth, document.getElementById(this._config.fatherContainerId).offsetHeight / $content.offsetHeight)
this.#scale()
}
// 自适应son缩放控制
const w = this._s < document.getElementById(this._config.fatherContainerId).offsetWidth / document.getElementById(this._config.sonContainerId).offsetWidth
const h = this._s < document.getElementById(this._config.fatherContainerId).offsetHeight / document.getElementById(this._config.sonContainerId).offsetHeight
if (w === false && h === true) {
while (this._s < document.getElementById(this._config.fatherContainerId).offsetHeight / document.getElementById(this._config.sonContainerId).offsetHeight) {
const delta = this.#computeDeltaY(-100)
this.#origin(delta, 0, 0)
this.#scale()
}
const delta = this.#computeDeltaY(-100)
this.#exceedScreen_scale()
this.#origin(delta, 0, 0)
this.#scale()
return
}
if (w === false && h === false) {
while (!(this._s < document.getElementById(this._config.fatherContainerId).offsetHeight / document.getElementById(this._config.sonContainerId).offsetHeight)) {
const delta = this.#computeDeltaY(100)
this.#origin(delta, 0, 0)
this.#scale()
}
const delta = this.#computeDeltaY(100)
this.#exceedScreen_scale()
this.#origin(delta, 0, 0)
this.#scale()
}
}
/**
* 处理鼠标拖动
* @param {Object} ev 事件对象
*/
#handle_move(ev) {
if (this._config.translate) {
if (ev.buttons === 1) {
this._x += (ev.movementX / this._s) * this._config.translateSpeed
this._y += (ev.movementY / this._s) * this._config.translateSpeed
this._moveDelta += Math.abs(ev.movementX + ev.movementY)
this.#exceedScreen_move()
this.#translate()
}
}
}
/**
* 处理鼠标抬起
* @description 阻止拖动时点击
* @param {Object} ev 事件对象
*/
#handle_click(ev) {
if (this._moveDelta > 10) {
ev.preventDefault()
ev.stopPropagation()
}
this._moveDelta = 0
}
/**
* 处理鼠标滚轮
* @param {Object} ev 事件对象
*/
#handle_wheel(ev) {
if (this._config.scale) {
const delta = this.#computeDeltaY(ev.deltaY)
if (this._config.exceedScreen) {
this.#origin(delta, ev.clientX, ev.clientY)
this.#scale()
return
}
if (this._s < document.getElementById(this._config.fatherContainerId).offsetWidth / document.getElementById(this._config.sonContainerId).offsetWidth ||
this._s < document.getElementById(this._config.fatherContainerId).offsetHeight / document.getElementById(this._config.sonContainerId).offsetHeight) {
this.#exceedScreen_scale()
} else {
this.#origin(delta, ev.clientX, ev.clientY)
this.#scale()
}
}
}
/**
* 计算滚动距离
* @param {Number} deltaY 滚动距离
* @return {Number} 滚动距离
* */
#computeDeltaY(deltaY) {
const delta = -(deltaY / 2000) * this._config.scaleSpeed
this._s *= 1 + delta
return delta
}
/**
* 超出屏幕时的拖动
* */
#exceedScreen_move() {
if (this._config.exceedScreen) {
return
}
if (this._x > 0) {
this._x = 0
}
if (this._y > 0) {
this._y = 0
}
if (this._x < document.getElementById(this._config.fatherContainerId).offsetWidth - document.getElementById(this._config.sonContainerId).offsetWidth * this._s) {
this._x = document.getElementById(this._config.fatherContainerId).offsetWidth - document.getElementById(this._config.sonContainerId).offsetWidth * this._s
}
if (this._y < document.getElementById(this._config.fatherContainerId).offsetHeight - document.getElementById(this._config.sonContainerId).offsetHeight * this._s) {
this._y = document.getElementById(this._config.fatherContainerId).offsetHeight - document.getElementById(this._config.sonContainerId).offsetHeight * this._s
}
}
/**
* 超出屏幕时的缩放
* */
#exceedScreen_scale() {
if (this._config.exceedScreen) {
return
}
if (this._s < document.getElementById(this._config.fatherContainerId).offsetWidth / document.getElementById(this._config.sonContainerId).offsetWidth) {
this._s = document.getElementById(this._config.fatherContainerId).offsetWidth / document.getElementById(this._config.sonContainerId).offsetWidth
}
if (this._s < document.getElementById(this._config.fatherContainerId).offsetHeight / document.getElementById(this._config.sonContainerId).offsetHeight) {
this._s = document.getElementById(this._config.fatherContainerId).offsetHeight / document.getElementById(this._config.sonContainerId).offsetHeight
}
this.#exceedScreen_move()
this.#translate()
}
/**
* 缩放原点
* @param {Number} delta 缩放系数变化量
* @param {Number} ox 缩放中心横坐标
* @param {Number} oy 缩放中心纵坐标
*/
#origin(delta, ox, oy) {
const v = new Matrix(1, 3, [[this._x, this._y, 1]])
const tf = new Matrix(3, 3, [
[1, 0, 0],
[0, 1, 0],
[-ox, -oy, 1],
])
const sc = new Matrix(3, 3, [
[1 + delta, 0, 0],
[0, 1 + delta, 0],
[0, 0, 1],
])
const tb = new Matrix(3, 3, [
[1, 0, 0],
[0, 1, 0],
[ox, oy, 1],
])
const r = v.multiplyD(tf).multiplyD(sc).multiplyD(tb)
this._x = r[0][0]
this._y = r[0][1]
this.#translate()
}
/**
* 平移
*/
#translate() {
this._$translate.style.transform = `translate(${this._x}px, ${this._y}px)`
}
/**
* 缩放
*/
#scale() {
this._$scale.style.transform = `scale(${this._s})`
}
}
export default ScreenMove
08-11
1050
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交