zrender制作一个基础的绘图板,绘图板可用于组态界面的基础性开发,本实基于vue基础开发,可用于vue项目组态界面的参考。
zrender开发文档地址:https://ecomfe.github.io/zrender-doc/public/api.html
zrender库的安装:npm install zrender
import zrender from 'zrender'
//绘图板
class DrawingBoard {
//绘图板容器的id
constructor(id) {
this.zr = zrender.init(document.getElementById(id));
}
init() {
sessionStorage.setItem('operate', 'move');//默认绘制圆形
this.draw('circle');
this.draw('line');
}
//绘制的形状及参数配置,此处以圆的绘制为例
draw(shape, option) {
switch (shape) {
case 'circle':
new Circle(this.zr, option);
break;
case 'line':
new Line(this.zr, option);
break;
default:
break;
}
}
}
//圆的绘制
class Circle {
constructor(zr, option) {
if (option == undefined) {
option = {
borderColor: 'red',
fillColor: 'orange'
}
}
this.option = option;
this.zr = zr;
this.group = new zrender.Group();//用于存放所有圆
this.position = [];//圆心位置
this.movePosition = this.position;//鼠标移动的位置
this.r = 1;//半径
this.result = null;//绘制的结果
this.zr.on('mousedown', e => {
let id = '';
if (e.target != undefined) {
id = e.target.id;
}
switch (sessionStorage.getItem('operate')) {
case "circle":
this.position.length == 0 ? this.start(e) : this.end();
break;
case "delete":
this.delete(id);
break;
default:
this.end();
break;
}
})
this.zr.on('mousemove', e => {
this.move(e)
})
}
//点击绘图板获得圆心坐标
start(e) {
if (this.position.length == 0) {
this.position = [parseInt(e.offsetX), parseInt(e.offsetY)]
}
}
//鼠标移动时计算圆的半径并刷新绘制的图形
move(e) {
if (this.position.length != 0) {
this.movePosition = [parseInt(e.offsetX), parseInt(e.offsetY)]
this.r = zrender.vector.distance(this.position, this.movePosition)
this.draw()
}
}
//鼠标中键滚动时结束图形绘制
end() {
this.position = []
this.result = null
}
//图形绘制及刷新方法
draw() {
if (this.result == null) {
this.result = new zrender.Circle({
shape: {
cx: this.position[0],
cy: this.position[1],
r: this.r
},
draggable: true,
style: {
fill: this.option.fillColor,
stroke: this.option.borderColor,
opacity: 0.6
}
});
this.result.on('click', function (e) {
window.console.log(e);
})
this.group.add(this.result)
this.zr.add(this.group)
} else {
this.result.attr({shape: {r: this.r}})//修改对象关键代码
this.zr.refresh();
}
}
//删除一个图形对象
delete(id) {
let group = this.group.children();
group.forEach(elm => {
if (elm.id == id) {
this.group.remove(elm);
}
})
}
}
//线的绘制
class Line {
constructor(zr, option) {
if (option == undefined) {
option = {
borderColor: 'red',
fillColor: 'orange'
}
}
this.option = option;
this.zr = zr;
this.group = new zrender.Group();//用于存放所有线
this.movePosition = this.position;//鼠标移动的位置
this.points = [];//绘制线的点集合
this.result = null;//绘制的结果
// 事件名称,支持: 'click'、 'mousedown'、 'mouseup'、 'mousewheel'、 'dblclick'、 'contextmenu'。
this.zr.on('mousedown', e => {
let id = '';
if (e.target != undefined) {
id = e.target.id;
}
switch (sessionStorage.getItem('operate')) {
case "line":
this.start(e);
break;
case "delete":
this.delete(id);
break;
default:
this.end();
break;
}
})
this.zr.on('mousemove', e => {
this.move(e)
})
this.zr.on('dblclick', () => {
this.end()
})
}
//点击绘图板获得坐标
start(e) {
this.points.push([parseInt(e.offsetX), parseInt(e.offsetY)]);
if (this.points.length == 1) {
this.points.push([parseInt(e.offsetX), parseInt(e.offsetY)]);
}
}
//鼠标移动时刷新绘制的图形
move(e) {
if (this.points.length != 0) {
this.movePosition = [parseInt(e.offsetX), parseInt(e.offsetY)];
this.points[this.points.length - 1][0] = this.movePosition[0];
this.points[this.points.length - 1][1] = this.movePosition[1];
this.draw()
}
}
//结束图形绘制
end() {
this.points = []
this.result = null
}
//绘制及刷新方法
draw() {
if (this.result == null) {
this.result = new zrender.Polyline({
shape: {
points: this.points
},
draggable: true,
style: {
// fill: this.option.fillColor,
stroke: this.option.borderColor,
opacity: 0.6
}
});
this.result.on('click', function (e) {
window.console.log(e);
})
this.group.add(this.result)
this.zr.add(this.group)
} else {
this.result.attr({shape: {points: this.points}})//修改对象关键代码
this.zr.refresh();
}
}
//删除一个对象
delete(id) {
let group = this.group.children();
group.forEach(elm => {
if (elm.id == id) {
this.group.remove(elm);
}
})
}
}
export const canvas = function (id) {
return new DrawingBoard(id);
}
页面调用,vue项目调用时最好在mounted钩子中进行调用,因为绘图板必须要dom元素绘制完成,下面是调用代码:
<template>
<div class="hello">
<ul class="tool">
<li @click="operate('move')" :class="operateType=='move'?'selected':''">移动</li>
<li @click="operate('line')" :class="operateType=='line'?'selected':''">线</li>
<li @click="operate('circle')" :class="operateType=='circle'?'selected':''">圆</li>
<li @click="operate('delete')" :class="operateType=='delete'?'selected':''">删除</li>
</ul>
<div id="main">
</div>
</div>
</template>
<script>
import {canvas} from '../units/draw'
export default {
name: 'HelloWorld',
data() {
return {
operateType: 'move'
}
},
created() {
},
methods: {
operate: function (operateType) {
this.operateType=operateType
sessionStorage.setItem('operate', operateType);
}
},
mounted() {
canvas('main').init();
}
}
</script>
<style scoped>
#main {
width: 100%;
height: 400px;
border: 2px solid olive;
box-shadow: 5px 5px 10px #f5f5f5;
margin: 10px auto;
}
.tool {
display: block;
list-style: none;
overflow: hidden;
margin: 0;
}
.tool li {
float: left;
width: 40px;
cursor: pointer;
}
.tool .selected {
background: #2c3e50;
color: #FFFFFF;
}
</style>
draw.js库中为方便文章书写圆与直线类放到了一起,实际项目中可各自单独写js文件存放管理。扩展的图形添加新类进行管理即可。本文由作者原创,仅供项目参考。