vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > VUE canvas绘制管线管廊

VUE使用canvas绘制管线管廊实现思路

作者:前端界的CV大师

这篇文章主要为大家介绍了VUE使用canvas绘制管线管廊实现思路详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正文

最近接到公司项目中的一个需求,需要绘制一个展示管线平面图的功能,除了展示以外,还需要进行内容的编辑,UI人员给的最终效果图如下:

经过分析后,觉得使用canvas,能够将此效果实现。最终将功能拆分为以下三点:

其中,绘制图形并填充对应的为管线,绘制图片对应的为设备图标,绘制文字则对应设备上方的文字描述及其他部分的文字信息,例如:一供、二回等。

因上述功能为项目中的功能的一部分,项目整体由VUE搭建,所以,此功能需要在VUE的项目结构上进行建立。

查阅大量资料及论坛后,没有找到合适的案例,那只能由本人亲自来手搓了,此案例涉及到以下知识点:

先分享一下最后的成果吧~

因时间及此案例代码量的关系

vue使用canvas绘制管线实现思路

首先,因canvas的绘制离不开JS,但是在vue页面中来书写,又会导致vue页面代码量过多,所以,我单独写了一个js文件,通过 export 进行导出,在vue页面中进行调用,下面来看代码:

index.vue

<template>
    <div class="canvas-container">
        <div class="canvas-icon-content">左侧选项列表</div>
        <div class="canvas-content">
            <div class="canvas" id="canvas">
                <canvas id="myCanvas" ref="myCanvas"></canvas>
            </div>
            <div class="canvas-options">下方操作按钮</div>
        </div>
    </div>
</template>
<script>
import canvas from '../utils/canvas'
let myCanvas = {}
export default {
    name: 'index',
    data() {
        return {}
    },
    mounted() {
        myCanvas = canvas.init('myCanvas')
    },
}
</script>

在 vue 页面中,主要是针对整体界面的搭建,css样式进行编写,其中除了界面外,还有 管线设备 信息修改的弹窗界面编写,如下图

针对信息编辑后的 “确定” 及 “取消” 事件,全部通过调用 myCanvas 中的方法来进行。

JS文件

在JS文件中,

首先定义一个 allElementCollection 数组,这个数组最终需要提交给后端,同时,页面中元素的绘制主要来自于这个主要数组。

剩下的就是来添加绘制的工作,以及JS中数据传入vue页面,vue页面的数据,传入JS中。

数据传输这里,我是这样做的,定义了一个对象 canvasDraw ,里面部分方法,如下代码:

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';
        return canvas
    },
    // 回传鼠标抬起事件
    canvasMouseUp: (e) =&gt; {},
    // 绘制类型切换
    drawTypeChange: (ele) =&gt; {},
    // 修改管线类型(冷热水)
    changePipelineType: (type) =&gt; {},
    // 设备参数修改
    canvasModifyInfo: (info) =&gt; {},
    // 显示设备可拖动的区域范围
    showEquipmentIconArea: ()  =&gt; {},
    commit: () =&gt; {
        // todo
        // 提交事件
    },
    // 清除整个画布
   clearAll: (info) =&gt; {},
    // 数据回显
    echoData: (data) =&gt; {}
}
export default canvasDraw

上述代码中,所有的 canvas 相关的方法,都通过对象 canvasDraw 导出,在vue页面,就可以通过 myCanvas 来进行调用了。

接下来,我们需要一个构造函数,这个函数的作用是,通过构造函数,可以 new 多个对象,每个对象里面有鼠标按下的起点坐标 startXstartY,鼠标抬起的重点坐标 endXendY,以及绘制的类型、绘制不同类型的信息对象、绘制形状的方法、绘制文字的方法、绘制图片的方法:

/**
 * 创建绘制元素工厂函数
 *
 * */
class ElementFactory {
    constructor(startX, startY, endX, endY) {
        this.startX = startX;  // 鼠标 按下 X点
        this.startY = startY;  // 鼠标 按下 Y点
        this.endX = endX;      // 鼠标 抬起 X点
        this.endY = endY;      // 鼠标 抬起 Y点
        this.type = 0;       // 绘制类型:图形、文字、图片
        this.pipelineInfo = {};  // 图形(管线)私有信息
        this.equipmentInfo = {};  // 图片(设备)私有信息
        this.textInfo = {};      // 文字(文字)私有信息
    }
    get minX() {
        return Math.min(this.startX, this.endX);
    }
    get maxX() {
        return Math.max(this.startX, this.endX);
    }
    get minY() {
        return Math.min(this.startY, this.endY);
    }
    get maxY() {
        return Math.max(this.startY, this.endY);
    }
    get middleX() {
        return this.endX - (this.endX - this.startX) / 2
    }
    get middleY() {
        return this.endY - (this.endY - this.startY) / 2
    }
    // 判断点击的是否存在元素绘制的范围之内
    isInside(x, y) {
        return x &gt;= this.minX &amp;&amp; x &lt;= this.maxX &amp;&amp; y &gt;= this.minY &amp;&amp; y &lt;= this.maxY
    }
    // 绘制管线
    drawPipeline() {}
    // 绘制设备
    drawEquipment() {}
    // 绘制设备上方文字
    drawEquipmentText() {}
    // 绘制纯文本
    drawText() {}
    // 根据条件来调用不同的绘制方法
    drawAllElement() {
        parseInt(this.type) === 0 ? this.drawPipeline() : (parseInt(this.type) === 1 ? this.drawEquipment() : this.drawText())
    }
}

基本的方法已经写完了,那接下来,就剩下一些鼠标的管理事件了。

在函数 canvasMousedown 中,主要处理三件事情:

1、鼠标按下事件;

2、鼠标移动事件;

3、鼠标抬起事件。

鼠标按下的那一刻,有以下几个方面需要注意:

具体代码如下:

const canvasMousedown = (e) =&gt; {
    const rect = canvas.getBoundingClientRect();
    const clickX = e.clientX - rect.left;
    const clickY = e.clientY - rect.top;
    // 查询所点击元素是否存在
    const shape = getElement(clickX, clickY);
    if (shape) {
        moveAllElement(e, clickX, clickY, rect, shape);
        canvas.style.cursor= "move";
    } else {
        if (e.buttons === 1) {
            draw_element_type === 0 ? drawRealTimePipeline(e, clickX, clickY, rect) : (draw_element_type === 1 ? drawRealTimeEquipment(e, clickX, clickY, rect) : drawRealTimeText(e, clickX, clickY, rect))
        }
    }
};

其中 getElement 方法为:

// 鼠标点击canvas查看是否点击到了已经绘制的路线,若是,则返回相关线的对象,若否,返回null
const getElement = (x, y) =&gt; {
    for (let i = allElementCollection.length - 1; i &gt;= 0; i--) {
        if (element.isInside(x, y)) return element;
    }
    return null
};

鼠标按下后,获取到 clickXclickY,判断当前点击的位置是否已经绘制了元素shape,如果shape存在,执行移动事件,如果不存在,则执行绘制事件。

大致的思路就是上述分享内容,接下来的文章中,我会将具体的方法及注意事项进行细化,

以上就是VUE使用canvas绘制管线管廊实现思路的详细内容,更多关于VUE canvas绘制管线管廊的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文