依赖插件如下:
https://www.npmjs.com/package/panzoom(9.4.3)
https://www.npmjs.com/package/decimal.js/v/10.2.0(10.2.0)
https://nightcatsama.github.io/vue-slider-component/#/api/slots(vue-slider-component)
效果图:
代码如下(vue 版本 2.6.11):
<template>
<div class="page-wrapper">
<div class="lft">
<div>Left</div>
</div>
<div class="rht">
<div
class="rht-top"
style="background: rgb(239, 226, 250); height: 120px"
>
xxxxx
</div>
<div class="rht-content">
<div style="position: absolute; top: 10px; left: 10px; z-index: 1; background: #fff; padding: 10px;">缩放:按住alt键盘 + 鼠标滚动</div>
<div
style="
background: #fff;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 10px;
left: 10px;
display: flex;
align-items: center;
z-index: 1;
"
>
<i class="el-icon-remove-outline" @click="zoomIn(-1)"></i>
<!-- 参考: https://nightcatsama.github.io/vue-slider-component/#/api/slots -->
<vue-slider
v-model="canvasInfo.scale"
:min="sliderMin"
:max="sliderMax"
:interval="interval"
@change="handleChagneScale"
:tooltip-formatter="tooltipFormatter"
style="width: 100px; margin: 0 10px"
>
</vue-slider>
<i class="el-icon-circle-plus-outline" @click="zoomIn(1)"></i>
</div>
<div class="nodes-content-wrapper" id="nodes-content-wrapper">
<div class="nodes-wrapper" id="nodes-wrapper">
<div style="font-size: 80px; height: 100%; display: flex; align-items: center; justify-content: center;">测试字符</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import panzoom from "panzoom";
import { Decimal } from "decimal.js";
export default {
data() {
return {
pan: null,
sliderMin: 0.2,
sliderMax: 3,
interval: 0.01,
canvasInfo: {
scale: 0.8,
},
tooltipFormatter: (v) => `${this.getPercentage(v)}`,
};
},
mounted() {
this.initPanZoom(this.canvasInfo.scale, 100, 50);
},
methods: {
initPanZoom(scale = 1, x = 0, y = 0) {
let that = this;
if (that.pan) {
that.pan.dispose();
}
const mainContainer = document.getElementById("nodes-wrapper");
let params = {
smoothScroll: false,
bounds: false, //可以移动出父容器
// autocenter: true,
zoomDoubleClickSpeed: 1,
minZoom: this.minZoom,
maxZoom: this.maxZoom,
// overflow: 'auto',
// contain: 'outside',
beforeWheel: (e) => {
let shouldIgnore = !e.altKey;
if (!shouldIgnore) {
//按下了 alt 键
if (e.deltaY > 0) {
this.zoomIn(-1, 0.1);
} else if (e.deltaY < 0) {
this.zoomIn(1, 0.1);
}
}
return true; //不需要自带的滚动放大缩小
// // 仅当 altKey 按下时才允许滚轮缩放。否则 - 忽略
// //暂时不支持滚轮放大缩小,还没有和拖拽同步
// let shouldIgnore = !e.altKey;
// return shouldIgnore;
},
beforeMouseDown: function (e) {},
};
if (scale) {
params.initialZoom = scale;
// that.jsp.setZoom(scale);
}
that.pan = panzoom(mainContainer, params);
that.pan.moveTo(x, y);
},
getContentClientRect() {
let container = document.getElementById("nodes-content-wrapper");
let rect = container.getBoundingClientRect();
return rect;
},
getCenter() {
let rect = this.getContentClientRect();
let cx = rect.x + rect.width / 2;
let cy = rect.y + rect.height / 2;
return {
cx,
cy,
};
},
zoomIn(type = 1, step = 0.01) {
let center = this.getCenter();
let scale =
type > 0
? (this.canvasInfo.scale += step)
: (this.canvasInfo.scale -= step);
if (type == 1) {
//放大
scale = scale >= this.sliderMax ? this.sliderMax : scale;
} else if (type == -1) {
//缩小
scale = scale <= this.sliderMin ? this.sliderMin : scale;
}
this.canvasInfo.scale = scale;
this.pan.zoomAbs(center.cx, center.cy, this.canvasInfo.scale);
},
getPercentage(val) {
return new Decimal(val).mul(new Decimal(100)).toFixed(0) + "%";
},
handleChagneScale(val) {
let center = this.getCenter();
this.pan.zoomAbs(center.cx, center.cy, this.canvasInfo.scale);
this.canvasInfo.scale = val;
},
},
};
</script>
<style scoped lang="scss">
.page-wrapper {
height: 100%;
display: flex;
.lft {
width: 300px;
flex-shrink: 0;
}
.rht {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
.rht-top {
flex-shrink: 0;
}
.rht-content {
flex: 1;
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
.nodes-content-wrapper {
background: #f1f1f1;
position: relative;
width: 100%;
height: 100%;
.nodes-wrapper {
background: yellow;
position: relative;
width: 100%;
height: 100%;
}
}
}
}
}
</style>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。