Skip to content

Instantly share code, notes, and snippets.

@syrxw
Last active November 24, 2018 05:36
Show Gist options
  • Save syrxw/3f14445d29f4df8e85f7d9b766fbcd8e to your computer and use it in GitHub Desktop.
Save syrxw/3f14445d29f4df8e85f7d9b766fbcd8e to your computer and use it in GitHub Desktop.
vue+svg 实现缩放
<template>
<svg width="800px" height="800px" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
<g class="port_output" style="pointer-events: all;">
<rect fill="#ddd" stroke-width="1.5"
:x="listData['001'].x" :y="listData['001'].y"
:width="listData['001'].width" :height="listData['001'].height"
:transform="listData['001'].transform"
style="vector-effect: non-scaling-stroke"
class="port" @click="elementClick($event,'001')" stroke-dasharray="none" stroke="#000"></rect>
<rect fill="#ddd" stroke-width="1.5"
:x="listData['002'].x" :y="listData['002'].y"
:width="listData['002'].width" :height="listData['002'].height"
:transform="listData['002'].transform"
style="vector-effect: non-scaling-stroke"
class="port" @click="elementClick($event,'002')" stroke-dasharray="none" stroke="#000"></rect>
</g>
<!--<path :d="item" stroke="red" stroke-width="2" fill="none" v-for="(item,index) in listData"-->
<!--:key="index"></path>-->
<g class="selected-group" :display="selectGroup.info.isShow" :transform="selectGroup.transform">
<path :d="selectGroup.path" stroke="blue" stroke-width="1" fill="none"></path>
<image :xlink:href="require('../assets/rotate.png')"
:x="selectGroup.rotate.x" :y="selectGroup.rotate.y"
:width="selectGroup.rotate.width" :height="selectGroup.rotate.height"
@mousedown="shapeRotate($event)"></image>
<circle :cx="selectGroup.connect.cw.x" :cy="selectGroup.connect.cw.y" r="2.5"
stroke="blue" fill="white"></circle>
<circle :cx="selectGroup.connect.ce.x" :cy="selectGroup.connect.ce.y" r="2.5"
stroke="blue" fill="white"></circle>
<rect style="cursor:nw-resize"
:x="selectGroup.resize.nw.x - 2.5" :y="selectGroup.resize.nw.y - 2.5"
stroke="blue" fill="white"
width="5" height="5"
class="port"
@mousedown="shapeScale($event,type='nw')"
></rect>
<rect style="cursor:ne-resize"
:x="selectGroup.resize.ne.x - 2.5" :y="selectGroup.resize.ne.y - 2.5"
stroke="blue" fill="white"
width="5" height="5"
class="port"
@mousedown="shapeScale($event,type='ne')"
></rect>
<rect style="cursor:sw-resize"
:x="selectGroup.resize.sw.x - 2.5" :y="selectGroup.resize.sw.y - 2.5"
stroke="blue" fill="white"
width="5" height="5"
class="port"
@mousedown="shapeScale($event,type='sw')"
></rect>
<rect style="cursor:se-resize"
:x="selectGroup.resize.se.x - 2.5" :y="selectGroup.resize.se.y - 2.5"
stroke="blue" fill="white"
width="5" height="5"
class="port"
@mousedown="shapeScale($event,type='se')"
></rect>
<rect :x="selectGroup.center.x - 2.5" :y="selectGroup.center.y - 2.5"
stroke="blue" fill="white"
width="5" height="5"
class="port"
@mousedown="shapeScale"
></rect>
</g>
</svg>
</template>
<script>
import * as d3 from 'd3';
export default {
name: 'home',
data() {
return {
clickPoint: {
x: '',
y: ''
},
listData: {
'001': {
width: 100,
height: 100,
x: 200,
y: 100,
transform: '',
translateX: '',
translateY: '',
rotate: 0,
},
'002': {
width: 150,
height: 150,
x: 450,
y: 100,
transform: '',
translateX: '',
translateY: '',
rotate: 0
}
},
selectGroup: {
info: {
isShow: 'none',
},
resize: {
nw: {
name: '',
x: '',
y: ''
},
sw: {
name: '',
x: '',
y: ''
},
ne: {
name: '',
x: '',
y: ''
},
se: {
name: '',
x: '',
y: ''
},
},
path: "",
rotate: {
x: '0',
y: '0',
width: '20',
height: '20',
angle: 0
},
connect: {
cw: {
name: '',
x: '0',
y: '0'
},
ce: {
name: '',
x: '0',
y: '0'
},
},
center: {
name: '',
x: '',
y: ''
},
transform: ''
},
selectedItem: {
target: null,
id: ""
},
scaleValue: {
x: 1,
y: 1
},
}
},
computed: {},
mounted() {
},
methods: {
initSelectGroup() {
//初始化数据
const target = this.listData[this.selectedItem.id]
target.translateX = target.x + target.width
target.translateY = target.y + target.height
this.scaleValue.x = 1
this.scaleValue.y = 1
this.selectGroup.rotate.angle = target.rotate
},
drawSelectPoint(target) { // 画点
//左上角
this.selectGroup.resize.nw = {
name: 'nw',
x: target.x,
y: target.y
}
//左下角
this.selectGroup.resize.sw = {
name: 'sw',
x: target.x,
y: target.y + target.height
}
//右上角
this.selectGroup.resize.ne = {
name: 'ne',
x: target.x + target.width,
y: target.y
}
//右下角
this.selectGroup.resize.se = {
name: 'se',
x: target.x + target.width,
y: target.y + target.height
}
//左中角
this.selectGroup.connect.cw = {
name: 'cw',
x: target.x,
y: target.y + target.height / 2
}
//右中角
this.selectGroup.connect.ce = {
name: 'ce',
x: target.x + target.width,
y: target.y + (target.height / 2)
}
//中心点
this.selectGroup.center = {
name: 'center',
x: target.x + (target.width / 2),
y: target.y + (target.height / 2)
}
},
drawSelectLine() { // 画线
const m1 = `M${this.selectGroup.resize.nw.x}, ${this.selectGroup.resize.nw.y}`
const m2 = `L${this.selectGroup.resize.ne.x}, ${this.selectGroup.resize.ne.y}`
const m3 = `L${this.selectGroup.resize.se.x}, ${this.selectGroup.resize.se.y}`
const m4 = `L${this.selectGroup.resize.sw.x}, ${this.selectGroup.resize.sw.y}`
const m5 = `L${this.selectGroup.resize.nw.x}, ${this.selectGroup.resize.nw.y}`
this.selectGroup.path = `${m1}${m2}${m3}${m4}${m5}`
},
drawSelectRotate(target) {// 画旋转图标
this.selectGroup.rotate.x = this.selectGroup.center.x - this.selectGroup.rotate.width / 2
this.selectGroup.rotate.y = this.selectGroup.center.y - (target.height / 2) - this.selectGroup.rotate.height * 1.5
},
drawSelectAngle() {
const target = this.listData[this.selectedItem.id]
if (target.rotate !== 0) {
this.selectGroup.transform = `rotate(${target.rotate},${this.selectGroup.center.x},${this.selectGroup.center.y})`
}else{
this.selectGroup.transform = ''
}
},
drawSelect(target) {
this.drawSelectPoint(target)
this.drawSelectLine()
this.drawSelectRotate(target)
this.drawSelectAngle()
},
elementClick(e, id) {
this.selectedItem.id = id;
this.selectedItem.target = e.target
this.initSelectGroup()
const p_data = this.calculatePointer('nw')
this.drawSelect(p_data)
this.selectGroup.info.isShow = 'inline'
},
calculatePointer(type) {
let return_data = {}
const target = this.listData[this.selectedItem.id]
return_data.width = target.width * Math.abs(this.scaleValue.x)
return_data.height = target.height * Math.abs(this.scaleValue.y)
//计算重绘坐标点 逻辑相对复杂
if (type === 'nw') {
return_data.x = target.translateX - return_data.width
return_data.y = target.translateY - return_data.height
if (this.scaleValue.x < 0) {
return_data.x = target.x + target.width
}
if (this.scaleValue.y < 0) {
return_data.y = target.y + target.height
}
}
if (type === 'ne') {
return_data.x = target.translateX
return_data.y = target.translateY - return_data.height
if (this.scaleValue.x < 0) {
return_data.x = target.x - return_data.width
}
if (this.scaleValue.y < 0) {
return_data.y = target.y + target.height
}
}
if (type === 'sw') {
return_data.x = target.translateX - return_data.width
return_data.y = target.translateY
if (this.scaleValue.x < 0) {
return_data.x = target.x + target.width
}
if (this.scaleValue.y < 0) {
return_data.y = target.y - return_data.height
}
}
if (type === 'se') {
return_data.x = target.x
return_data.y = target.y
if (this.scaleValue.x < 0) {
return_data.x = target.x - return_data.width
}
if (this.scaleValue.y < 0) {
return_data.y = target.y - return_data.height
}
}
return return_data
},
shapeScale(e, type) {
const target = this.listData[this.selectedItem.id]
//初始计算位移距离,让scale保持原地缩放
if (type === 'nw') {
const tx = target.x + target.width
const ty = target.y + target.height
this.scaleFunc(e, tx, ty, 'nw')
}
if (type === 'ne') {
const tx = target.x
const ty = target.y + target.height
this.scaleFunc(e, tx, ty, 'ne')
}
if (type === 'sw') {
const tx = target.x + target.width
const ty = target.y
this.scaleFunc(e, tx, ty, 'sw')
}
if (type === 'se') {
const tx = target.x
const ty = target.y
this.scaleFunc(e, tx, ty, 'se')
}
},
scaleFunc(e, tx, ty, type) {
const target = this.listData[this.selectedItem.id]
target.translateX = tx
target.translateY = ty
const pos_x = e.clientX - target.translateX
const pos_y = e.clientY - target.translateY
let isMoving = false
document.onmousemove = (e) => {
const move_x = e.clientX - target.translateX
const move_y = e.clientY - target.translateY
this.scaleValue = {
x: move_x / pos_x,
y: move_y / pos_y
}
const p_data = this.calculatePointer(type)
this.drawSelect(p_data)
if (!isNaN(this.scaleValue.x) && !isNaN(this.scaleValue.y)) {
if (target.rotate !== 0) {
target.transform = `rotate(${target.rotate},${this.selectGroup.center.x},${this.selectGroup.center.y}) translate(${target.translateX},${target.translateY}) scale(${this.scaleValue.x},${this.scaleValue.y}) translate(-${target.translateX},-${target.translateY})`
} else {
target.transform = `translate(${target.translateX},${target.translateY}) scale(${this.scaleValue.x},${this.scaleValue.y}) translate(-${target.translateX},-${target.translateY})`
}
}
isMoving = true
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
if (isMoving) {
const p_data = this.calculatePointer(type)
const target = this.listData[this.selectedItem.id]
target.x = p_data.x
target.y = p_data.y
target.width = p_data.width
target.height = p_data.height
if (target.rotate !== 0) {
target.transform = `rotate(${target.rotate},${this.selectGroup.center.x},${this.selectGroup.center.y})`
} else {
target.transform = ''
}
}
};
},
shapeRotate(e) {
console.log(e)
this.initSelectGroup()
const target = this.listData[this.selectedItem.id]
const center = this.selectGroup.center
const angle = Math.PI / 180 * this.selectGroup.rotate.angle
// const x = (target.x - center.x) * Math.cos(angle) - (target.y - center.y) * Math.sin(angle) + center.x
// const y = (target.x - center.x) * Math.sin(angle) + (target.y - center.y) * Math.cos(angle) + center.y
const p_data = this.calculatePointer('nw')
this.drawSelect(p_data)
// 旋转开始
const event = window.event,
prevAngle = Math.atan2(event.pageY - center.y, event.pageX - center.x) - angle;
document.onmousemove = () => {
// 旋转
const event = window.event,
angle = Math.atan2(event.pageY - center.y, event.pageX - center.x);
this.selectGroup.rotate.angle = Math.floor((angle - prevAngle) * 180 / Math.PI);
const transform = `rotate(${this.selectGroup.rotate.angle},${this.selectGroup.center.x},${this.selectGroup.center.y})`
target.rotate = this.selectGroup.rotate.angle
target.transform = transform
this.selectGroup.transform = transform
}
document.onmouseup = () => {
// 旋转结束
document.onmousemove = null;
document.onmouseup = null;
}
},
pointDown(e) {
this.clickPoint.x = e.offsetX
this.clickPoint.y = e.offsetY
document.onmousemove = (e) => {
this.drawLine(this.clickPoint.x, this.clickPoint.y, e.offsetX, e.offsetY, '002')
};
document.onmouseup = () => {
document.onmousemove = null;
document.onmouseup = null;
};
},
drawLine(x1, y1, x2, y2, id) {
const path = d3.path()
path.moveTo(x1, y1)
path.bezierCurveTo(x2, y1, x1, y2, x2, y2);
// path.lineTo(x2,y2)
this.$set(this.listData, id, path.toString())
console.log(this.listData)
},
}
}
</script>
<style>
:not(svg), :not(foreignObject) > svg {
transform-origin: 0px 0px 0px;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment