溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

VUE怎么使用canvas繪制管線管廊

發(fā)布時間:2023-04-27 14:27:50 來源:億速云 閱讀:92 作者:iii 欄目:開發(fā)技術

這篇文章主要介紹了VUE怎么使用canvas繪制管線管廊的相關知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇VUE怎么使用canvas繪制管線管廊文章都會有所收獲,下面我們一起來看看吧。

    首先,我在JS中定義了一下常量,其作用如下:

    let canvas = {}, ctx = {};
    const image = new Image();
    // 定義管線默認寬度
    const PIPELINE_NUMBER = 15;
    // 定義圖標默認縮放比例
    const ICON_SCALE_RATIO = 25;
    // 所有繪制元素
    let allElementCollection = [];
    // 初始化管線水類型: 0為冷水 1為熱水
    let pipeline_water_type = 0;
    // 當前繪制設備的對象
    let equipment_select = {};
    // 是否顯示設備繪制的范圍
    let equipment_area_show = false
    // 初始化繪制類型:0為管線 1為設備,2為文字框 默認為管線
    let draw_element_type = 0;
    // 管線流動速度初始值
    let pipeline_offset = 0;
    // 定義當前選中的已繪制元素
    let current_select_element_index = {};

    接下來是處理鼠標左鍵在按下后,在上節(jié)的代碼中,針對于鼠標左鍵按下后,需要判斷當前點擊的區(qū)域是否已經(jīng)存在繪制的內(nèi)容,如果有,執(zhí)行繪制內(nèi)容移動,如果沒有,則開始新建繪制內(nèi)容,代碼如下:

    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))
        }
    }

    我們一個一個的來,如果繪制內(nèi)容不存在,則執(zhí)行新建繪制內(nèi)容,這里我使用三目運算來判斷當前需要繪制的類型drawRealTimePipeline、drawRealTimeEquipment、drawRealTimeText。

    drawRealTimePipeline:繪制實時管線

    // 繪制實時管線
    const drawRealTimePipeline = (e, clickX, clickY, rect) => {
        const shape = new ElementFactory(clickX, clickY);
        shape.endX = clickX;
        shape.endY = clickY;
        // 繪制管線時,刪除通過 new 的對象的 textInfo 和 equipmentInfo,這兩個對于管線來說沒有用處
        delete shape.textInfo;
        delete shape.equipmentInfo;
        let shapeWidth = 0, shapeHeight = 0;
        // 為了方便處理元素刪除,動態(tài)添加一個隨機的 ID,并且在當前位置拿到,方便在繪制線段過短時來精確刪除
        let current_uid = setuid(shape);
        allElementCollection.push(shape);
        window.onmousemove = (evt) => {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            shapeWidth = (evt.clientX - rect.left) - clickX;
            shapeHeight = (evt.clientY - rect.top) - clickY;
            // 判斷繪制為 豎線 還是 橫線
            let shapeDirection = Math.abs(shapeWidth) >= Math.abs(shapeHeight);
            if (shapeDirection) {
                // 如果是橫線,則 endY 為固定值
                shape.endX = evt.clientX - rect.left;
                shape.endY = clickY + PIPELINE_NUMBER;
            } else {
                // 如果是豎線,則 endX 為固定值
                shape.endX = clickX + PIPELINE_NUMBER;
                shape.endY = evt.clientY - rect.top;
            }
            shape.pipelineInfo.direction = shapeDirection;
            shape.pipelineInfo.waterType = pipeline_water_type;
            draw();
        };
        // 畫線時,鼠標抬起判斷如果線段繪制過短,則不推入 allElementCollection
        window.onmouseup = () => {
            if(parseInt(draw_element_type) === 0 && shape.endX) {
                if (Math.abs(shape.startX - shape.endX) < 45 && Math.abs(shape.startY - shape.endY) < 45) {
                    let index = allElementCollection.findIndex(item => item.uid === current_uid);
                    allElementCollection.splice(index, 1)
                    ctx.clearRect(0, 0, canvas.width, canvas.height)
                    draw()
                }
            }
        };
    }
    const setuid = (shape) => {
        // 生成唯一ID
        let uid = Math.round( Math.random() * 100000000000);
        shape.uid = uid;
        return uid
    }

    drawRealTimeEquipment:繪制實時設備:

    繪制設備時,由于繪制的圖片,所以對于構造函數(shù)中的endX、endY需要自己計算

    VUE怎么使用canvas繪制管線管廊

    // 繪制實時設備
    const drawRealTimeEquipment = (e, clickX, clickY, rect) => {
        const shape = new ElementFactory(clickX, clickY)
        // 繪制設備時,刪除通過 new 的對象的 textInfo 和 pipelineInfo,這兩個對于圖形來說沒有用處
        delete shape.textInfo;
        delete shape.pipelineInfo;
        // 設備繪制在鼠標點擊的那一刻就需要開始創(chuàng)建,
        setEquipment(e);
        setuid(shape);
        allElementCollection.push(shape);
        window.onmousemove = (evt) => setEquipment(evt);
        function setEquipment(evt) {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            shape.startX = evt.clientX - rect.left;
            shape.startY = evt.clientY - rect.top;
            // 計算當前繪制的endX endY
            image.src = require(`../assets/images/${equipment_select.iconPath}`);
            let icon_width = Math.ceil(image.width / ICON_SCALE_RATIO),
                icon_height = Math.ceil(image.height / ICON_SCALE_RATIO);
            shape.endX = evt.clientX - rect.left + icon_width;
            shape.endY = evt.clientY - rect.top + icon_height;
            draw();
        }
        draw();
    };

    drawRealTimeText:繪制實時文本:

    // 繪制實時文字
    const drawRealTimeText = (e, clickX, clickY, rect) => {
        const shape = new ElementFactory(clickX, clickY);
        setuid(shape);
        // 繪制文字時,刪除通過 new 的對象的 equipmentInfo 和 pipelineInfo,這兩個對于圖形來說沒有用處
        delete shape.equipmentInfo;
        delete shape.pipelineInfo;
        ctx.font = `normal normal normal ${shape.textInfo.fontSize + 'px' || '16px'} Microsoft YaHei`;
        const defaultText = '默認文字,請右鍵修改';
        const measureText = ctx.measureText(defaultText);
        const textW = measureText.width,
            textH = measureText.actualBoundingBoxAscent + measureText.actualBoundingBoxDescent;
        shape.textInfo.text = defaultText;
        allElementCollection.push(shape);
        setText(e)
        window.onmousemove = (evt) => setText(evt)
        function setText(evt) {
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            shape.startX = evt.clientX - rect.left;
            shape.startY = evt.clientY - rect.top;
            shape.endX = evt.clientX - rect.left + textW;
            shape.endY = evt.clientY - rect.top - textH;
            draw();
        }
        draw();
    };

    接下來是鼠標點的位置,已經(jīng)存在了繪制的內(nèi)容,那么這個時候就有兩種情況了,一個是 鼠標左鍵 點擊的,一個是 鼠標右鍵 點擊的。

    鼠標左鍵點擊只能執(zhí)行移動,鼠標右鍵則是彈出操作框,如圖:

    VUE怎么使用canvas繪制管線管廊

    這里有一點需要注意,管線的操作框中沒有 編輯 按鈕,且彈出框的位置需要根據(jù)鼠標點擊的位置變化而變化。

    moveAllElement:元素移動事件:

    // 元素移動
    const moveAllElement = (e, clickX, clickY, rect, shape) => {
        const { startX, startY, endX, endY } = shape;
        let tipX = 0, tipY = 0;
        // 鼠標左鍵:拖動位置
        if (e.buttons === 1) {
            window.onmousemove = (evt) => {
                removeEditTip();
                ctx.clearRect(0, 0, canvas.width, canvas.height);
                const distanceX = evt.clientX - rect.left - clickX;
                const distanceY = evt.clientY - rect.top - clickY;
                shape.startX = startX + distanceX;
                shape.startY = startY + distanceY;
                shape.endX = endX + distanceX;
                shape.endY = endY + distanceY;
                draw();
            }
        }
        // 鼠標右鍵:執(zhí)行信息編輯
        if (e.buttons === 2) {
            if (shape.type === 0) {
                // 管線
                tipX = e.clientX;
                tipY = e.clientY + 10;
            } else if (shape.type === 1) {
                // 如果點擊的是圖標,彈出提示出現(xiàn)在圖標下方
                tipX = (shape.endX - shape.startX) / 2 + shape.startX + rect.left
                tipY = shape.endY + rect.top
            } else if (shape.type === 2) {
                // 文字
                tipX = shape.startX + rect.left + ctx.measureText(`${shape.textInfo.text}`).width / 2;
                tipY = shape.startY + rect.top;
            }
            createEditTip(tipX, tipY, shape);
            return false
        }
    };

    createEditTip為動態(tài)創(chuàng)建的DOM結構,即操作提示框。

    createEditTip、removeEditTip:動態(tài)創(chuàng)建及移除DOM操作提示框:

    // 創(chuàng)建管線點擊事件彈窗
    const createEditTip = (x, y, shape) => {
        let width = shape.type ? 180 : 120, marginLeft = shape.type ? 95 : 65, display = shape.type ? 'inline-block' : 'none'
        removeEditTip()
        let tipText = document.createElement('div')
        tipText.classList.add('tip-text-content')
        tipText.innerHTML = `<div class="tip-text" id="tipText" >
                                <p>
                                    <span id="equipmentDelete">刪除</span>
                                    <span id="${parseInt(shape.type) === 2 ? 'textModify' : 'equipmentModify'}" >編輯</span>
                                    <span id="buttonCancel">取消</span>
                                </p>
                             </div>`
        document.body.appendChild(tipText)
        document.getElementById('equipmentDelete').onclick = () => {
            allElementCollection.splice(current_select_element_index, 1)
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            draw()
            removeEditTip()
        };
        // 判斷點擊的是 圖片 的編輯按鈕,還是 文字 的編輯按鈕
        let modifyButton = document.getElementById('equipmentModify') ? 'equipmentModify' : 'textModify';
        document.getElementById(modifyButton).onclick = () => {
            removeEditTip()
        };
        document.getElementById('buttonCancel').onclick = () => {
            removeEditTip()
        };
    };
    // 移除管線事件彈窗
    const removeEditTip = () => {
        const popup = document.querySelector('.tip-text-content')
        if (popup) document.body.removeChild(popup)
    }

    關于“VUE怎么使用canvas繪制管線管廊”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“VUE怎么使用canvas繪制管線管廊”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

    AI