- 本次将说明如何在项目中使用SVG图,并做一些简单的操作等,毕竟SVG图相对于图片具有可操作性,对图像进行放大不会失真。
- SVG什么意思:SVG是一种可缩放矢量图形(英语:Scalable Vector Graphics,SVG)是基于可扩展标记语言(XML),用于描述二维矢量图形的图形格式。SVG由W3C制定,是一个开放标准。简单的理解,它是图形的另一种格式例如它和常见的图片格式.png、.jpg、.gif等是一类。
SVG 有如下特点:
SVG 绘制的是矢量图,因此对图像进行放大不会失真。
基于 XML,可以为每个元素添加 JavaScript 事件处理器。
每个图形均视为对象,更改对象的属性,图形也会改变。**
SVG 画布的预定义元素里,有六种基本图形跟一种比较特殊,也是功能最强的元素:
六种基本图形:
矩形 <rect>
圆形 <circle>
椭圆 <ellipse>
线段 <line>
折线 <polyline>
多边形 <polygon>
特殊元素:
路径 <path>
1. 在项目中使用SVG图并进行操作
1.1 安装
// npm
npm install @svgdotjs/svg.js
npm install axios
// yarn
yarn add @svgdotjs/svg.js
yarn add axios
1.2 在项目中引入
import { SVG } from '@svgdotjs/svg.js'
import axios from 'axios';
1.3 渲染准备好的SVG图
<template>
<div class="SVG-BOX">
<div class="SVG-BOX-directives" v-drag="{ set: set }">
<div class="SVG-BOX-center"></div>
</div>
</div>
</template>
<script>
import { SVG } from "@svgdotjs/svg.js";
import axios from "axios";
export default {
name: "",
props: {},
components: {},
data() {
return {};
},
directives: {
// 拖拽指令
drag: function (el, binding) {
const dragBox = el; // 获取当前元素
// 当选中对象为输入框或者文本框不执行拖拽操作
dragBox.onmousedown = (e) => {
if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA') {
return;
}
e.preventDefault(); // 防止默认行为
// 算出鼠标相对元素的位置
const disX = e.clientX - dragBox.offsetLeft;
const disY = e.clientY - dragBox.offsetTop;
document.onmousemove = (e) => {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
e.preventDefault();
const left = e.clientX - disX;
const top = e.clientY - disY;
// 移动当前元素
dragBox.style.left = left + "px";
dragBox.style.top = top + "px";
binding.value.set(left, top);
};
document.onmouseup = (e) => {
e.preventDefault();
// 鼠标弹起来的时候不再移动
document.onmousemove = null;
// 预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
document.onmouseup = null;
};
};
}
},
computed: {},
watch: {},
created() {},
mounted() {
this.initMap()
},
methods: {
set() {},
// 渲染SVG图
initMap() {
// 获取准备好的预设区域
const dom = document.querySelector(".SVG-BOX-center");
dom.innerHTML = "";
// 对SVG图进行异步渲染
return new Promise((resolve, reject) => {
const draw = SVG()
.addTo(".SVG-BOX-center") // 要渲染的区域
.size("100%", "100%") // 大小
.scale(1, 1); // 比例
axios.get(require("@/assets/map.svg")).then((res) => {
draw.svg(res.data);
resolve("success");
// this.dealMap(); // 操作SVG图
});
});
},
},
};
</script>
<style scoped lang="less">
.SVG-BOX {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.SVG-BOX-directives {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
.SVG-BOX-center {
width: 100%;
height: 100%;
}
}
}
</style>
1.4 操作SVG图
- 其实操作SVG图跟操作原生dom类似,不过一个是xml一个是html,不过操作起来还是有一点区别
// 操作svg
dealMap () {
// 给所有高亮的图层加点击
// 获取SVG图所有点位
const addSvg = document.querySelector('.SVG-BOX-center').querySelector('g').querySelectorAll('path')
Array.from(addSvg).forEach((x) => {
// 给所有点位加上鼠标经过小手样式
x.style.stroke = 'pink'
// x.style.cursor = 'pointer'
// // 给所有点位加上点击事件
// x.addEventListener('click', (e) => {
// })
})
},
- 以上可以看到其实跟原生dom操作是一样的,但下面就有不一样的了
// 改变边框线颜色
x.style.stroke = 'pink'
// 改变颜色
x.style.fill = 'pink'
// 改变 圆形 <circle> 的大小
x.r = 50 // 50是圆的半径 注意不需要加px
2 拖拽
<template>
<div class="SVG-BOX">
<div class="SVG-BOX-directives" v-drag="{ set: set }">
<div class="SVG-BOX-center"></div>
</div>
</div>
</template>
<script>
import { SVG } from "@svgdotjs/svg.js";
import axios from "axios";
export default {
name: "",
props: {},
components: {},
data() {
return {};
},
directives: {
// 拖拽指令
drag: function (el, binding) {
const dragBox = el; // 获取当前元素
// 当选中对象为输入框或者文本框不执行拖拽操作
dragBox.onmousedown = (e) => {
if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA') {
return;
}
e.preventDefault(); // 防止默认行为
// 算出鼠标相对元素的位置
const disX = e.clientX - dragBox.offsetLeft;
const disY = e.clientY - dragBox.offsetTop;
document.onmousemove = (e) => {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
e.preventDefault();
const left = e.clientX - disX;
const top = e.clientY - disY;
// 移动当前元素
dragBox.style.left = left + "px";
dragBox.style.top = top + "px";
binding.value.set(left, top);
};
document.onmouseup = (e) => {
e.preventDefault();
// 鼠标弹起来的时候不再移动
document.onmousemove = null;
// 预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
document.onmouseup = null;
};
};
}
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {
set() {},
},
};
</script>
<style scoped lang="less">
.SVG-BOX {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.SVG-BOX-directives {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
.SVG-BOX-center {
width: 100%;
height: 100%;
}
}
}
</style>
3 放大/缩小
<template>
<div class="SVG-BOX">
<div class="SVG-BOX-directives" v-drag="{ set: set }">
<div
class="SVG-BOX-center"
:style="scaleImg"
@mousewheel.prevent="scaleFun"
></div>
</div>
</div>
</template>
<script>
import { SVG } from "@svgdotjs/svg.js";
import axios from "axios";
export default {
name: "",
props: {},
components: {},
data() {
return {
scaleImg: "transform:scale(1)",
imgScale: 1,
};
},
directives: {
// 拖拽指令
drag: function (el, binding) {
const dragBox = el; // 获取当前元素
// 当选中对象为输入框或者文本框不执行拖拽操作
dragBox.onmousedown = (e) => {
if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA') {
return;
}
e.preventDefault(); // 防止默认行为
// 算出鼠标相对元素的位置
const disX = e.clientX - dragBox.offsetLeft;
const disY = e.clientY - dragBox.offsetTop;
document.onmousemove = (e) => {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
e.preventDefault();
const left = e.clientX - disX;
const top = e.clientY - disY;
// 移动当前元素
dragBox.style.left = left + "px";
dragBox.style.top = top + "px";
binding.value.set(left, top);
};
document.onmouseup = (e) => {
e.preventDefault();
// 鼠标弹起来的时候不再移动
document.onmousemove = null;
// 预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
document.onmouseup = null;
};
};
}
},
computed: {},
watch: {
imgScale: {
handler: function (val) {
if (val <= 0.5) return
this.scaleImg = `transform:scale(${this.imgScale})`;
this.stationAllAlarmDialogShow()
},
},
},
created() {},
mounted() {},
methods: {
set() {},
// 滚动放大
scaleFun(e) {
const direction = e.deltaY > 0 ? "down" : "up";
if (direction === "up") {
// 滑轮向上滚动
this.imgScale += 0.1;
} else {
if (this.imgScale <= 0.5) return
// 滑轮向下滚动
this.imgScale -= 0.1;
}
},
},
};
</script>
<style scoped lang="less">
.SVG-BOX {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.SVG-BOX-directives {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
.SVG-BOX-center {
width: 100%;
height: 100%;
}
}
}
</style>
4 完整代码(附点击SVG图在点击位置生成图标)
<template>
<div class="SVG-BOX">
<div class="SVG-BOX-directives" v-drag="{ set: set }">
<div
class="SVG-BOX-center"
id="SVG-BOX-center"
:style="scaleImg"
@mousewheel.prevent="scaleFun"
@click="clickSvgPage($event)"
></div>
</div>
<div
class="SVG-dialog"
id="SVG-dialog"
ref="SVGDialog"
v-show="SVGDialog"
></div>
</div>
</template>
<script>
import { SVG } from "@svgdotjs/svg.js";
import axios from "axios";
export default {
name: "",
props: {},
components: {},
data() {
return {
scaleImg: "transform:scale(1)",
imgScale: 1,
SVGDialog: false,
};
},
directives: {
// 拖拽指令
drag: function (el, binding) {
const dragBox = el; // 获取当前元素
// 当选中对象为输入框或者文本框不执行拖拽操作
dragBox.onmousedown = (e) => {
if (e.target.nodeName === 'INPUT' || e.target.nodeName === 'TEXTAREA') {
return;
}
e.preventDefault(); // 防止默认行为
// 算出鼠标相对元素的位置
const disX = e.clientX - dragBox.offsetLeft;
const disY = e.clientY - dragBox.offsetTop;
document.onmousemove = (e) => {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
e.preventDefault();
const left = e.clientX - disX;
const top = e.clientY - disY;
// 移动当前元素
dragBox.style.left = left + "px";
dragBox.style.top = top + "px";
binding.value.set(left, top);
};
document.onmouseup = (e) => {
e.preventDefault();
// 鼠标弹起来的时候不再移动
document.onmousemove = null;
// 预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
document.onmouseup = null;
};
};
}
}, computed: {},
watch: {
imgScale: {
handler: function (val) {
if (val <= 0.5) return
this.scaleImg = `transform:scale(${this.imgScale})`;
this.stationAllAlarmDialogShow()
},
},
},
created() {},
mounted() {
this.initMap();
},
methods: {
set() {},
// 滚动放大
scaleFun(e) {
const direction = e.deltaY > 0 ? "down" : "up";
if (direction === "up") {
// 滑轮向上滚动
this.imgScale += 0.1;
} else {
if (this.imgScale <= 0.5) return
// 滑轮向下滚动
this.imgScale -= 0.1;
}
},
// 渲染SVG图
initMap() {
// 获取准备好的预设区域
const dom = document.querySelector(".SVG-BOX-center");
dom.innerHTML = "";
// 对SVG图进行异步渲染
return new Promise((resolve, reject) => {
const draw = SVG()
.addTo(".SVG-BOX-center") // 要渲染的区域
.size("100%", "100%") // 大小
.scale(1, 1); // 比例
axios.get(require("@/assets/map.svg")).then((res) => {
draw.svg(res.data);
resolve("success");
this.dealMap(); // 操作SVG图
});
// 再次点击标记图标 就隐藏掉图标
const SVGDialogDom = document.querySelector('.SVG-dialog');
SVGDialogDom.addEventListener('click', (e) => {
this.SVGDialog = false;
});
});
},
// 操作svg
dealMap() {
// 给所有高亮的图层加点击
// 获取SVG图所有点位
const addSvg = document
.querySelector(".SVG-BOX-center")
.querySelector("g")
.querySelectorAll("path");
Array.from(addSvg).forEach((x) => {
// 给所有点位加上鼠标经过小手样式
x.style.stroke = "pink";
// x.style.cursor = 'pointer'
// // 给所有点位加上点击事件
x.addEventListener("click", (e) => {});
});
},
// SVG图标记位置
clickSvgPage(e) {
this.SVGDialog = true;
this.$refs.SVGDialog.style.left = e.pageX + "px";
this.$refs.SVGDialog.style.top = e.pageY + "px";
// 点击后图片的左上角会对应点击的位置,可以通过偏移量来达到想要的效果
this.$refs.SVGDialog.style.transform = "translate(-50%, -70%)";
},
},
};
</script>
<style scoped lang="less">
.SVG-BOX {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
.SVG-BOX-directives {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
.SVG-BOX-center {
width: 100%;
height: 100%;
}
}
.SVG-dialog {
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 26px;
background: url("../assets/logo.png") no-repeat;
background-size: 100%;
}
}
</style>