项目需求中需要图片的放大、缩小、移动,和实现一个放大缩小的缩略条。在这里记录一下实现的方法。
使用了 vue 和 konva
IMG_2089.GIF
<v-stage ref="layerStage" :config="configKonva">
<v-layer ref="layerEditor">
<v-group
:draggable="true"
@dragend="bgImageDragEnd"
@wheel="wheelForScale($event)"
:config="{
name: 'layerImage',
x: bgx,
y: bgy,
scaleX: imageScale,
scaleY: imageScale,
}"
>
<v-image :config="layerImage"></v-image>
</v-group>
</v-layer>
</v-stage>
method
bgImageDragEnd() {
const layerImageNode = this.stage.find(".layerImage")[0];
this.bgx = layerImageNode.getAttr("x");
this.bgy = layerImageNode.getAttr("y");
}
// 放大缩小函数
wheelForScale(e) {
const stage = this.self.stage;
const oldScale = this.self.imageScale;
const scaleBy = 1.2;
let pointer = stage.getPointerPosition();
// let bar = this.self.$refs.slider.getStage().find('.sliderMoveBar')[0]
var mousePointTo = {
x: (pointer.x - this.self.bgx) / oldScale,
y: (pointer.y - this.self.bgy) / oldScale,
};
if (e.evt.deltaY > 0 && oldScale * scaleBy > 8) {
this.self.$noty("已放大到最大");
return;
}
if (e.evt.deltaY < 0 && oldScale / scaleBy < 0.2) {
this.self.$noty("已缩小到最小");
return;
}
let newScale;
if (e.evt.deltaY > 0) {
newScale = oldScale * scaleBy;
} else {
newScale = oldScale / scaleBy;
}
this.self.bgx = pointer.x - mousePointTo.x * newScale;
this.self.bgy = pointer.y - mousePointTo.y * newScale;
this.self.imageScale = newScale;
stage.batchDraw();
}
// 还原函数
reduction() {
this.self.bgx = 0;
this.self.bgy = 0;
this.self.imageScale = 1;
this.self.hideMenu();
this.self.$refs.scaleBox.changeScaleBar()
}
滚动条
<template>
<div class="scale-box">
<Tooltip content="[ctrl] + 鼠标滚轮亦可进行缩放" placement="top">
<div class="slidecontainer">
<input
type="range"
min="0"
max="200"
:value="scaleBar"
@input="sliderDgMove($event)"
class="slider"
id="myRange"
/>
</div>
</Tooltip>
<span class="scale-text">{{ showScale }}% </span>
<Tooltip content="还原" placement="top">
<Icon class="reduction" @click="reduction" type="ios-expand" />
</Tooltip>
</div>
</template>
<script>
export default {
props: ["imageScale"],
name: "ScaleBox",
data() {
return {
scaleBar:1
};
},
computed: {
showScale() {
let showScale = 100;
if (this.imageScale > 1) {
showScale = Math.ceil((8 / (8 - this.imageScale)) * 100);
showScale > 800 && (showScale = 800);
}
if (this.imageScale < 1) {
showScale = Math.ceil(this.imageScale * 100);
}
return showScale;
}
},
methods: {
sliderDgMove(ev) {
let val = ev.target.value;
let upperLen = 100 / 11;
let lowerLen = 100 / 8;
let times = 1;
if (val > 100) {
times = (val - 100) / upperLen;
} else if (val < 100) {
times = (val - 100) / lowerLen;
} else {
times = 0;
}
let imageScale = Math.pow(1.2, times);
this.$emit('changeImageScale', imageScale)
this.changeScaleBar();
},
changeScaleBar() {
let times = Math.round(Math.log(this.imageScale) / Math.log(1.2));
let upperLen = 100 / 11;
let lowerLen = 100 / 8;
if (times >= 0) {
this.scaleBar = 100 + upperLen * times;
} else {
this.scaleBar = 100 + lowerLen * times;
}
}
},
mounted() {
this.changeScaleBar();
},
};
</script>
<style lang="less" scoped>
.scaled-box {
width: 200px;
border-top: 2px solid #fff;
margin: 0 10px;
position: relative;
-webkit-user-select: none;
}
.scale-bar {
position: absolute;
width: 2px;
height: 12px;
background-color: #fff;
top: -6px;
cursor: pointer;
}
.scale-text {
-webkit-user-select: none;
}
.slidecontainer {
width: 220px;
}
.slider {
-webkit-appearance: none;
width: 200px;
height: 5px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: 0.2s;
transition: opacity 0.2s;
}
.slider:hover {
opacity: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 5px;
height: 24px;
background: #fff;
cursor: pointer;
}
</style>