欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

fabric.js圖層功能獨(dú)立顯隱?添加?刪除?預(yù)覽實(shí)現(xiàn)詳解

 更新時(shí)間:2023年05月04日 16:52:41   作者:圊妖  
這篇文章主要為大家介紹了fabric.js圖層功能獨(dú)立顯隱?添加?刪除?預(yù)覽實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

去年經(jīng)歷了個(gè)虛擬人的項(xiàng)目,其中我參與了前端的部分,一個(gè)用electron寫的編輯器,UI部分用的vue3+tsx的寫法(這種組合是不是沒見過?我也是第一次見,驚得我當(dāng)時(shí)還發(fā)了個(gè)沸點(diǎn))

我所負(fù)責(zé)的部分是讓用戶可以對貼圖進(jìn)行修改,其中就涉及到了圖層功能(類似Photoshop),而我當(dāng)時(shí)選用的fabric是沒有圖層的,因此我就得考慮如何實(shí)現(xiàn)圖層

原理

fabric本身有提供group功能,本意是讓你將畫布上的一些元素組合起來,這也將成為本次圖層功能的基礎(chǔ) 既以一個(gè)group代表一個(gè)圖層,畫布下第一層children只有圖層(group),而在group中,才是用戶實(shí)際繪制的內(nèi)容

效果預(yù)覽

本次demo實(shí)現(xiàn):

  • 用戶可手動(dòng)添加/刪除圖層
  • 可對每個(gè)圖層進(jìn)行獨(dú)立顯隱操作,并反饋到畫布中
  • 可對每個(gè)圖層單獨(dú)預(yù)覽

效果圖:

(別嫌我的樣式丑,我已經(jīng)下班了,沒有UI能夠PUSH我!)

下期預(yù)告

  • 讓圖層能夠調(diào)整圖層層級
  • 結(jié)合undo + redo + 橡皮擦

小Tips

首先fabric是需要到官方上下載的,在選擇你需要的模塊后再進(jìn)行打包

雖然npm上也可以下載,但那不是官方的包,是有網(wǎng)友打包好以后上傳的,其中沒有包含橡皮擦模塊,很可能會(huì)不符合你的需求

所以我個(gè)人建議你可以自行去官網(wǎng)上打包,然后傳到你的私有npm庫里,然后就可以通過npm來管理了

fabric自定義打包下載地址:Custom Fabric build — Fabric.js Javascript Canvas Library (fabricjs.com)

fabric的事件文檔:Event inspector | Fabric.js Demos (fabricjs.com)

接下來的demo將會(huì)通過直接引入的方式來使用fabric,雖然我平時(shí)寫項(xiàng)目都是ts,但練手demo我個(gè)人建議還是js,問就是省事

完整代碼

目錄:

  • fabric.js即為官網(wǎng)下載的插件包,這個(gè)文件就不放了,大家可以自行去官網(wǎng)打包下載
  • index.html即本次的頁面,主要負(fù)責(zé)dom的處理,直接扔瀏覽器運(yùn)行就可以
  • sketchpad.js 是對fabric的二次封裝,同時(shí)也避免在html中寫太多fabric功能代碼

index.html代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .content {
            display: flex;
        }
        .preview {
            margin-top: 40px;
            padding-top: 20px;
            width: 100%;
            display: flex;
            justify-content: center;
            border-top: 1px solid rgba(0,0,0,0.1);
        }
        .preview > img {
            width: 300px;
            height: 200px;
        }
        .layer-list {
            width: 300px;
            display: flex;
            flex-direction: column;
            padding-right: 10px;
            margin-right: 10px;
            box-sizing: content-box;
            border-right: 1px solid rgba(0,0,0, 0.2);
        }
        .layer {
            width: 300px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
            border: 1px solid rgba(0,0,0, 0.2);
        }
        .layer > img {
            width: 30px;
            height: 30px;
            border: 1px solid rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <div id="app">
        <div class="content">
            <!-- 左側(cè)的圖層列表 -->
            <div class="layer-list">
                <button style="margin-bottom: 20px;" @click="addLayer">增加圖層</button>
                <div @click="changeCurrentLayer(item.id)" class="layer" :style="currentLayer === item.id ? 'background-color: rgba(0,0,0, 0.1)' : '' " v-for="item of layers" :key="item.id">
                    <button @click="changeVisible(item.id)">{{ item.show ? '已顯示' : '已隱藏'}}</button>
                    <img :src="item.data">
                    <span>{{ item.name }}</span>
                    <button @click="deleteLayer(item.id)">刪除</button>
                </div>
            </div>
            <!-- 右側(cè)的畫板 -->
            <div class="sketchpad-layout"  style="width: 600px;">
                <canvas id="sketchpad" width="600" height="400" style="border: 1px solid #ccc;"></canvas>
            </div>
        </div>
        <!-- 對整張畫布進(jìn)行圖片預(yù)覽 -->
        <div class="preview">
            <button @click="updatePreview">整個(gè)畫布預(yù)覽:</button>
            <img :src="preview">
        </div>
    </div>
    <!-- 使用vue3來進(jìn)行ui的渲染,懶得操作dom了 -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <!-- 打包好的fabric文件 -->
    <script src="./fabric.js"></script>
    <!-- sketchpad里面就是將fabric封裝了一層 -->
    <script src="./sketchpad.js"></script>
    <script>
        const { createApp } = Vue
        /** 單條的數(shù)據(jù)類型定義 */
        const LayerData = {
            /** 用于顯示的名稱 */
            name: '圖層名稱',
            /** 圖層的id,也用于管理圖層 */
            id: '1111',
            /** 圖層的顯示狀態(tài) */
            show: true,
            /** 圖層的數(shù)據(jù),用于顯示預(yù)覽圖 */
            data: '',
        }
        createApp({
            data() {
                return {
                    layers: [],// 圖層數(shù)組,方便管理
                    sketchpad: null,// 畫板
                    currentLayer: '',// 當(dāng)前圖層的id
                    preview: '',// 預(yù)覽圖的base64數(shù)據(jù)
                }
            },
            methods: {
                /**
                 * 改變圖層的顯示/隱藏
                 * @param id 圖層的id
                */
                changeVisible(id) {
                    const index = this.layers.findIndex(v => v.id === id);
                    if (index > -1) {
                        this.layers[index].show = !this.layers[index].show;
                    }
                    this.sketchpad.changeLayerVisible(id)
                },
                /**
                 * 刪除圖層
                 * @param id 圖層的id
                */
                deleteLayer(id) {
                    const index = this.layers.findIndex(v => v.id === id);
                    if (index > -1) {
                        this.layers.splice(index, 1)
                        this.sketchpad.deleteLayer(id)
                    }
                },
                /**
                 * 增加圖層
                */
                addLayer() {
                    const item = {
                        ...LayerData
                    }
                    item.id = new Date().getTime()
                    item.name = `圖層${this.layers.length + 1}`
                    this.layers.push(item)
                    this.sketchpad.addLayer(item.id)
                    this.changeCurrentLayer(item.id)
                },
                /** 選擇當(dāng)前要操作的圖層 */
                changeCurrentLayer(id) {
                    this.currentLayer = id
                    this.sketchpad.changeCurrentLayer(id)
                },
                /**
                 * 更新預(yù)覽圖
                */
                updatePreview() {
                    this.preview = this.sketchpad.getImage()
                },
                /** 圖層數(shù)據(jù)更新的回調(diào) */
                onChangeData(id, data) {
                    const index = this.layers.findIndex(v => v.id === id);
                    if (index > -1) {
                        this.layers[index].data = data;
                    }
                }
            },
            mounted() {
                this.sketchpad = new Sketchpad('sketchpad', {
                    change: this.onChangeData
                });
                this.addLayer()
            }
        }).mount('#app')
    </script>
</body>
</html>

sketchpad.js代碼

console.log('Sketchpad load');
class Sketchpad {
    /** fabric實(shí)例 */
    instance = null;
    /** 當(dāng)前所在圖層的id */
    currentLayer = '';
    /** 畫布寬度 */
    width = 600;
    /** 畫布高度 */
    height = 600
    /** 事件訂閱 */
    listeners = {
        /**
         * 圖層內(nèi)容變化時(shí)的回調(diào)
         * @param {string} id 圖層id
         * @param {base64} data 圖層內(nèi)容的base64格式
         */
        change: (id, data) => {}
    }
    constructor(id, listeners) {
        this.instance = new fabric.Canvas(id);
        this.width = this.instance.width;
        this.height = this.instance.height;
        this.instance.isDrawingMode = true;
        this.listeners.change = listeners.change
        this.instance.on('object:added', ((options) => {
                if (options.target.type === 'group') return;
                const groups = this.instance.getObjects()
                groups.forEach(v => {
                    if (v.layerId === this.currentLayer  && v.type === 'group') {
                        v.addWithUpdate(options.target);
                        this.instance.remove(options.target);
                        this.listeners.change(v.layerId, v.toDataURL({
                            width: this.width,
                            height: this.height
                        }))
                    }
                })
        }))
        console.log('Sketchpad init')
    }
    /** 添加圖層 */
    addLayer(id) {
        const group = new fabric.Group([], {
            width: this.width,
            height: this.width,
        });
        // 在這里增加一個(gè)自定義屬性 layerId ,用于區(qū)分圖層
        group.layerId = id
        this.instance.add(group)
        this.currentLayer = id;
            this.listeners.change(id, group.toDataURL({
                width: this.width,
                height: this.height
            }))
    }
    /** 改變圖層的顯示/隱藏 */
    changeLayerVisible(id) {
        const groups = this.instance.getObjects()
        groups.forEach(v => {
            if (v.layerId === id && v.type === 'group') {
                v.visible = !v.visible;
                this.instance.renderAll() // 刷新畫布,改變group的visible屬性,必須通過刷新畫布,才能應(yīng)用新屬性值
            }
        })
    }
    /** 選擇要操作的圖層 */
    changeCurrentLayer(id) {
        this.currentLayer = id
    }
    /** 刪除圖層 */
    deleteLayer(id) {
        const groups = this.instance.getObjects()
        groups.forEach(v => {
            if (v.layerId === id && v.type === 'group') {
                this.instance.remove(v)
                this.instance.renderAll() // 刷新畫布
            }
        })
    }
    /** 獲取畫布數(shù)據(jù),以img標(biāo)簽可以識別的base64格式 */
    getImage() {
        return this.instance.toDataURL()
    }
}

將以上這兩個(gè)文件代碼直接復(fù)制粘貼到編輯器里,然后再去打包個(gè)fabric.js也放進(jìn)編輯器里,就可以運(yùn)行啦

以上就是fabric.js圖層功能獨(dú)立顯隱 添加 刪除 預(yù)覽實(shí)現(xiàn)詳解的詳細(xì)內(nèi)容,更多關(guān)于fabric.js圖層功能實(shí)現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Javascript 跨域知識詳細(xì)介紹

    Javascript 跨域知識詳細(xì)介紹

    這篇文章主要介紹了Javascript 跨域知識詳細(xì)介紹的相關(guān)資料,并附簡單實(shí)例代碼,幫助大家理解,需要的朋友可以參考下
    2016-10-10
  • ChatGPT前端編程秀之別拿編程語言不當(dāng)語言

    ChatGPT前端編程秀之別拿編程語言不當(dāng)語言

    這篇文章主要為大家介紹了ChatGPT前端編程秀之教你別拿編程語言不當(dāng)語言,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • JavaScript前端實(shí)用的工具函數(shù)封裝

    JavaScript前端實(shí)用的工具函數(shù)封裝

    這篇文章主要為大家介紹了JavaScript前端實(shí)用的一些工具函數(shù)的封裝,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • 微信小程序 vidao實(shí)現(xiàn)視頻播放和彈幕的功能

    微信小程序 vidao實(shí)現(xiàn)視頻播放和彈幕的功能

    這篇文章主要介紹了微信小程序 vidao實(shí)現(xiàn)視頻播放和彈幕的功能的相關(guān)資料,這里提供實(shí)現(xiàn)代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下
    2016-11-11
  • 定時(shí)器在頁面最小化時(shí)不執(zhí)行實(shí)現(xiàn)示例

    定時(shí)器在頁面最小化時(shí)不執(zhí)行實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了定時(shí)器在頁面最小化時(shí)不執(zhí)行的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Fabric.js?樣式不更新解決方法案例

    Fabric.js?樣式不更新解決方法案例

    這篇文章主要為大家介紹了Fabric.js?樣式不更新解決方法案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • 創(chuàng)建圖片對比slider滑塊示例詳解

    創(chuàng)建圖片對比slider滑塊示例詳解

    這篇文章主要為大家介紹了創(chuàng)建圖片對比slider滑塊示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • JavaScript中七種流行的開源機(jī)器學(xué)習(xí)框架

    JavaScript中七種流行的開源機(jī)器學(xué)習(xí)框架

    今天小編就為大家分享一篇關(guān)于JavaScript中五種流行的開源機(jī)器學(xué)習(xí)框架,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • ECharts框架分段視覺映射在移動(dòng)端適配

    ECharts框架分段視覺映射在移動(dòng)端適配

    這篇文章主要介紹了ECharts框架分段視覺映射在移動(dòng)端適配詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Dom-api MutationObserver使用方法詳解

    Dom-api MutationObserver使用方法詳解

    這篇文章主要為大家介紹了Dom-api MutationObserver使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11

最新評論