书接上回,针对构造函数内部的绘制方法,基本上介绍完毕,本章最后介绍一下vue页面与canvas的数据传输方式以及管线信息修改的方式。
主要还是两部分,vue界面以及js。
VUE界面及样式
<!--
文件描述:
创建时间:2023/4/12 10:33
创建人:ChenJinZhu
-->
<template>
<div class="canvas-container">
<div class="canvas-icon-content">
<ul>
<li v-for="(eq, index) in equipment" :key="index" @click="equipmentChange(eq, index)"
:class="{ 'canvas-icon-active': equipmentSelect === index }">
<img :src="eq.icon" :alt="eq.name">
<p>{{eq.name}}</p>
</li>
</ul>
</div>
<div class="canvas-content">
<div class="canvas" id="canvas">
<canvas id="myCanvas" ref="myCanvas"></canvas>
</div>
<div class="canvas-options">
<div class="option-change-water-type">
<el-select v-model="value" placeholder="请选择" size="medium" @change="pipelineTypeChange">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</div>
<el-divider direction="vertical"></el-divider>
<div class="option-draw-text">
<el-button :type="addTextStatus ? 'success' : 'warning'" @click="addText">自定义文字</el-button>
</div>
<el-divider direction="vertical"></el-divider>
<div class="option-commit">
<el-button type="primary" @click="commit">上传所绘制内容</el-button>
</div>
<el-divider direction="vertical"></el-divider>
<div class="option-drag">
<el-button type="info" plain @click="showEquipmentArea">显示设备拖动区域</el-button>
</div>
<el-divider direction="vertical"></el-divider>
<div class="option-clear">
<el-button type="info" @click="clearAll">清除所有绘制内容</el-button>
</div>
</div>
</div>
<div class="pipeline-info-add">
<el-dialog :title="!modifyType ? '设备信息' : '文本信息'" :visible.sync="iconDialog" width="750px">
<div class="icon-form-container">
<el-form v-if="!modifyType" :model="iconForm" label-position="right" label-width="120px"
:inline="true">
<el-form-item label="设备名称">
<el-input v-model="iconForm.name"></el-input>
</el-form-item>
<el-form-item label="设备编号">
<el-input v-model="iconForm.id"></el-input>
</el-form-item>
<el-form-item label="设备单位">
<el-input v-model="iconForm.unit"></el-input>
</el-form-item>
<el-form-item label="图标缩放比例">
<el-input-number v-model="iconForm.scale" :min="10" :max="30" label="值越大,图标越小:10-30"></el-input-number>
</el-form-item>
<el-form-item label="设备旋转角度">
<el-select v-model="iconForm.rotate" placeholder="请选择设备旋转角度">
<el-option v-for="(item, index) in rotateOptions" :key="index + 'op'" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="是否展示信息">
<el-radio-group v-model="iconForm.show" size="small">
<el-radio-button :label="true">展示</el-radio-button>
<el-radio-button :label="false">隐藏</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="描述信息">
<div v-for="(item, index) in iconForm.others" :key="index">
<el-input class="describe" v-model="iconForm.others[index]">
<template slot="append">
<el-button icon="el-icon-delete" @click="delDescribe(index)"></el-button>
</template>
</el-input>
</div>
<el-button size="mini" type="primary" @click="addDescribe">新增描述</el-button>
</el-form-item>
</el-form>
<el-form v-else :model="textForm" label-position="right" label-width="100px" :inline="true">
<el-form-item label="文本内容">
<el-input v-model="textForm.text"></el-input>
</el-form-item>
<el-form-item label="字体大小">
<el-input-number v-model="textForm.fontSize" :min="16" :max="30"></el-input-number>
</el-form-item>
<el-form-item label="字体颜色">
<el-input disabled placeholder="请选择颜色" :value="textForm.color"
@click.native="colorStatus = !colorStatus"></el-input>
<div class="sketch-picker" v-show="colorStatus">
<sketch-picker v-model="color" @input="colorValueChange"></sketch-picker>
<el-button size="mini" @click="colorStatus = false">取消</el-button>
<el-button size="mini" type="primary" @click="colorStatus = false">确定</el-button>
</div>
</el-form-item>
</el-form>
<div style="width: 100%;display: flex;justify-content: space-around;">
<el-button @click="iconDialog = false">取消</el-button>
<el-button type="primary" @click="iconModify">确定</el-button>
</div>
</div>
</el-dialog>
</div>
</div>
</template>
<script>
import canvas from '../utils/canvas'
import { Sketch } from 'vue-color'
let myCanvas = {}
export default {
name: "draw",
components: { 'sketch-picker': Sketch },
data() {
return {
// 设备列表
equipment: [
{
name: '管线',
eId: 11,
icon: require('../assets/images/line.png'),
iconPath: 'line.png',
drawType: 0
},
{
name: '温度表',
eId: 1,
icon: require('../assets/images/thermometer.png'),
iconPath: 'thermometer.png',
drawType: 1
},
{
name: '压力表',
eId: 2,
icon: require('../assets/images/manometer.png'),
iconPath: 'manometer.png',
drawType: 1
},
{
name: '接头',
eId: 3,
icon: require('../assets/images/joint.png'),
iconPath: 'joint.png',
drawType: 1
},
{
name: '直流阀',
eId: 4,
icon: require('../assets/images/direct_current_valve.png'),
iconPath: 'direct_current_valve.png',
drawType: 1
},
{
name: '循环阀',
eId: 5,
icon: require('../assets/images/circulating_valve.png'),
iconPath: 'circulating_valve.png',
drawType: 1
},
{
name: '电动阀',
eId: 6,
icon: require('../assets/images/electric_valve.png'),
iconPath: 'electric_valve.png',
drawType: 1
},
{
name: '开关阀',
eId: 7,
icon: require('../assets/images/on_off_valve.png'),
iconPath: 'on_off_valve.png',
drawType: 1
},
{
name: '热换机',
eId: 8,
icon: require('../assets/images/heat_exchanger.png'),
iconPath: 'heat_exchanger.png',
drawType: 1
},
{
name: '热换机',
eId: 9,
icon: require('../assets/images/heat_exchanger1.png'),
iconPath: 'heat_exchanger1.png',
drawType: 1
},
{
name: '蓄水池',
eId: 10,
icon: require('../assets/images/reservoir.png'),
iconPath: 'reservoir.png',
drawType: 1
},
],
// 设备选中index
equipmentSelect: 0,
// 冷热水下拉
options: [
{
value: '0',
label: '冷水'
}, {
value: '1',
label: '热水'
}
],
// 冷热水选中值
value: '0',
// 文字添加状态
addTextStatus: false,
// 修改类型:0设备信息修改、1文字信息修改
modifyType: 0,
// 弹窗显隐
iconDialog: false,
// 设备信息
iconForm: {
show: true,
},
// 文本信息
textForm: {},
// 旋转度数
rotateOptions: [
{
label: '0 度',
value: 0
}, {
label: '90 度',
value: 90,
}, {
label: '-90 度',
value: -90,
}, {
label: '180 度',
value: 180,
}
],
// 当前选择颜色
color: '',
colorStatus: false,
//储存临时回显数据
echoDataList: []
}
},
methods: {
equipmentChange(element,index) {
this.equipmentSelect = index
this.addTextStatus = false
canvas.drawTypeChange(element)
},
// 管线类型选择
pipelineTypeChange() {
canvas.changePipelineType(this.value)
},
// 添加自定义文字
addText() {
this.addTextStatus = !this.addTextStatus
this.equipmentSelect = this.addTextStatus ? -1 : 0;
canvas.drawTypeChange(this.addTextStatus ? {drawType: 2} : this.equipment[0])
},
// 显示设备可拖动区域
showEquipmentArea() {
canvas.showEquipmentIconArea()
},
// 监听tip的点击事件
handleMouseup(idx) {
this.modifyType = idx
let currentEditObject = JSON.parse(JSON.stringify(canvas.canvasMouseUp()));
this[['iconForm', 'textForm'][idx]] = currentEditObject[['equipmentInfo', 'textInfo'][idx]]
this.iconDialog = true
},
addDescribe() {
this.iconForm.others.push('')
},
// 颜色值改变事件处理
colorValueChange(val) {
this.textForm.color = val.hex
},
// 设备信息修改
iconModify() {
// console.log(this[['iconForm', 'textForm'][this.modifyType]])
canvas.canvasModifyInfo(this[['iconForm', 'textForm'][this.modifyType]], ['equipmentInfo', 'textInfo'][this.modifyType])
this.iconDialog = false
},
//删除描述信息
delDescribe(index) {
this.iconForm.others.splice(index, 1)
},
commit() {
canvas.commit()
},
clearAll() {
canvas.clearAll()
}
},
mounted() {
myCanvas = canvas.init('myCanvas')
window.addEventListener('click', (e) => {
if (e.target.id.includes('equipmentModify')) this.handleMouseup(0)
if (e.target.id.includes('textModify')) this.handleMouseup(1)
})
},
created() {
},
beforeDestroy() {
window.removeEventListener('click')
}
}
</script>
<style scoped lang="less">
.canvas-container{
width: 1300px;
border: 1px solid #000000;
border-radius: 20px;
margin: 10px;
overflow: hidden;
display: flex;
*{
box-sizing: border-box;
}
.canvas-icon-content{
width: 100px;
border-right: 1px solid #000;
cursor: pointer;
overflow: hidden;
ul{
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
li{
padding: 5px 0;
img{
display: block;
max-width: 35%;
margin: 0 auto;
}
p{
text-align: center;
font-size: 12px;
letter-spacing: 3px;
}
&:hover{
transform: scale(1.3);
}
&.canvas-icon-active{
background-color: rgba(93, 143, 170, 0.6);
p{
color: #fff;
}
}
}
}
}
.canvas-content{
width: calc(100% - 100px);
.canvas{
height: 800px;
cursor: crosshair;
}
.canvas-options{
border-top: 1px solid #000;
height: 60px;
cursor: pointer;
display: flex;
align-items: center;
>div{
height: 60px;
line-height: 60px;
text-align: center;
button{
width: 80%;
}
}
.option-change-water-type{
width: 10%;
/*background-color: #ea5e00;*/
}
.option-draw-text{
width: 20%;
/*background-color: #4beab0;*/
}
.option-commit{
width: 45%;
/*background-color: #76beea;*/
}
.option-drag{
width: 18%;
}
.option-clear{
width: 18%;
/*background-color: #ea0000;*/
}
}
}
}
</style>
效果图如下:
canvas事件
const canvasDraw = {
init(element) {
canvas = document.getElementById(element)
ctx = canvas.getContext('2d')
const w = 1200, h = 800;
canvas.width = w * devicePixelRatio;
canvas.height = h * devicePixelRatio;
canvas.style.width = w + 'px';
canvas.style.height = h + 'px';
calculationFlow();
canvas.onmousedown = (e) => canvasMousedown(e);
canvas.onmouseup = () => {
canvas.onmousemove = null;
window.onmousemove = null;
canvas.style.cursor= "crosshair"
}
return canvas
},
// 回传鼠标抬起事件
canvasMouseUp: () => {
return allElementCollection[current_select_element_index]
},
// 更改绘制类型
drawTypeChange(element) {
equipment_select = element
draw_element_type = element.drawType
},
// 修改管线类型(冷热水)
changePipelineType: (type) => {
pipeline_water_type = type
},
// 修改信息提交
canvasModifyInfo: (params, flag) => {
const shape = allElementCollection[current_select_element_index]
if (flag.includes('equipmentInfo')) {
image.src = require(`../assets/images/${params.iconPath}`);
let icon_width = Math.ceil(image.width / params.scale),
icon_height = Math.ceil(image.height / params.scale);
shape.endX = shape.startX + icon_width;
shape.endY = shape.startY + icon_height;
}
if (flag.includes('textInfo')) {
ctx.font = `normal normal normal ${params.fontSize + 'px' || '16px'} Microsoft YaHei`;
const measureText = ctx.measureText(params.text);
const textW = measureText.width,
textH = measureText.actualBoundingBoxAscent + measureText.actualBoundingBoxDescent;
shape.endX = shape.startX + textW;
shape.endY = shape.startY - textH;
}
allElementCollection[current_select_element_index][flag] = params;
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
},
// 显示设备可拖动的区域范围
showEquipmentIconArea: () => {
equipment_area_show = !equipment_area_show;
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
},
commit: () => {
// todo
// 提交事件
console.log(allElementCollection)
},
//回显
echoData(data) {
//下方为前后端正式对接所用数据格式 回显处理
// let echoData = []
// data.map(item => {
// let echoItem = new PipelineFactory()
// for (let i in item) {
// echoItem[i] = item[i]
// }
// echoData.push(echoItem)
// // console.log(echoItem);
// })
// allElementCollection = echoData
},
// 清除所有
clearAll: () => {
allElementCollection = []
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
好了,综合前面 4 节,这个功能就全部结束了,如果这个功能对您有所帮助的话,还恳请您点赞、评论、及收藏。谢谢!
最后,附上源码地址: https://gitee.com/zhuzio/online-pipeline.git ;
欢迎叨扰,请邮件:1483364913@qq.com;
版权声明:本文为qq_37070696原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。