欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

vue+fabric.js實現簡易的圖文編輯器

freeflydom
2024年10月25日 10:40 本文熱度 692

前言

通過vue2和fabric.js實現一個簡易的圖文編輯器,可以在畫布上添加文字,圖片,設置背景圖,對文字,圖片的屬性進行修改。最后生成圖片。至于畫布上對選中的對象進行拖動,縮放,旋轉,這些能力fabric本身已經支持。

1 創建一個vue項目

2 安裝fabric.js

建議使用4或5版本,最新版學習成本較高,相關經驗文檔少。

npm install fabric@4.6.0

3核心代碼

頁面基本結構

頁面左側為添加元素區域,可添加文字,圖片等元素。中間為畫布。右側對選中的元素的屬性進行修改。

具體代碼可參考源碼。項目中我用的node版本是18.17.1。

<div class="editor">

    <div class="sidebar left">

      <button @click="addText">添加文本</button>

      <button @click="addImage">添加圖片</button>

      <button @click="setBackgroundImage">添加背景圖</button>

    </div>

    <canvas id="c" width="600" height="600" class="canvas"></canvas>

    <div class="sidebar right">

      <!-- 右側屬性面板 -->

       <div v-if="selectedObject">

        屬性修改...

       </div>

    </div>

</div>

 

初始化畫布

首先確保 頁面中已經有canvas標簽。

data中定義需要用到到參數

data() {

    return {

      canvas: null,

      selectedObject: null, // 當前選中的元素對象

      canvasWidth: 800, // 初始畫布寬度  

      canvasHeight: 600, // 初始畫布高度

      canvasBackgroundColor: '#FFF', // 初始畫布背景色

    };

},

在mounted鉤子函數中創建了Fabric.js畫布并監聽鼠標點擊

創建fabric畫布,并指定背景色,大小。

監聽mouse:up事件,點擊畫布上的元素時,更新selectedObject,selectedObject對象表示當前選中元素的屬性。

mounted() {

    this.$nextTick(() => {

      this.initCanvas();

    })

},

initCanvas() {

  // 創建畫布

  this.canvas = new fabric.Canvas('c',{

    backgroundColor: this.canvasBackgroundColor,

    width: 800,

    height: 576,

  });

  

  // 監聽點擊

  this.canvas.on('mouse:up', (e) => {

    if (e.target) {

      this.selectedObject = e.target;

    } else {

      this.selectedObject = null

    }

  });

},

添加文本

addText() {

  const text = new fabric.IText('點擊編輯', {

    left: 100,

    top: 100,

    fontSize: 30,

    fontFamily: 'arial', // 字體

    fill: '#333', // 顏色

    originX: 'left',

    originY: 'top',

    

  });

  this.canvas.add(text);

},

以上只添加了文本的基本屬性,除此之外還有一些常用屬性:

editable:是否可編輯,值為布爾值;

lockUniScaling:控制四個正方向縮放,值為布爾值;

lockScalingX: 禁止橫向縮放,值為布爾值;

lockScalingY: 禁止縱向縮放,值為布爾值;

同時還可以添加自定義的屬性,例如我在添加文本元素時,自定義了屬性system_name。

addText() {

  const text = new fabric.IText('當前日期', {

    ......

    system_name: 'current_date',

  });

  this.canvas.add(text);

},

添加圖片

addImage() {

  fabric.Image.fromURL('圖片url', (img) => {

    img.set({

      left: 100,

      top: 100,

      angle: 0,  // 你可以根據需要調整圖片的旋轉角度  

    });

    // 將圖片添加到畫布  

    this.canvas.add(img);

    // 重新渲染畫布以顯示新添加的圖片  

    this.canvas.renderAll();

  }, { crossOrigin: 'anonymous' });

},

fabric.Image.fromURL('圖片url', callback, options) 方法用于從指定的 URL 加載圖片。這個方法接受三個參數。

'圖片url':圖片的 URL 地址。

callback(img):一個回調函數,當圖片加載完成后執行。img 參數是加載后的 Fabric.js 圖片對象。

options:一個對象,包含加載圖片時的選項。在這個例子中,設置了 { crossOrigin: 'anonymous' },這允許跨域加載圖片,避免在加載跨域圖片時出現 CORS(跨源資源共享)錯誤。

如果我希望添加的圖片不超出畫布,同時居中。上述代碼可以這樣改進:

計算縮放因子scale并應用,保證圖片最長的邊不會超出畫布。 

addImage() {

  fabric.Image.fromURL('圖片url', (img) => {

    // 獲取畫布的寬高

    const canvasWidth = this.canvas.getWidth();

    const canvasHeight = this.canvas.getHeight();

    const maxWidth = canvasWidth * 0.6; // 計算圖片允許的最大寬度  

    const maxHeight = canvasHeight * 0.3; // 計算圖片允許的最大高度 

    // 計算縮放比例   

    let scale = Math.min(maxWidth / img.width, maxHeight / img.height);   

    // 應用縮放比例  

    img.scale(scale).set({

      left: (canvasWidth - img.width * scale) / 2, // 居中圖片  

      top: (canvasHeight - img.height * scale) / 2,

    });

    // 將圖片添加到畫布  

    this.canvas.add(img);

    // 重新渲染畫布以顯示新添加的圖片  

    this.canvas.renderAll();

  }, { crossOrigin: 'anonymous' });

},

設置背景圖

設置背景圖有兩種實現方式,

1 通過canvas.setBackgroundImage()設置;

2 添加一個圖片,寬高與畫布大小一致,將其放在所有其他對象的底層,并禁止選中、觸發事件。

我這里使用的是第二種方法。

setBackgroundImage(imageUrl) {

  fabric.Image.fromURL(imageUrl, (img) => {

    // 獲取畫布的寬度和高度  

    const canvasWidth = this.canvas.getWidth();  

    const canvasHeight = this.canvas.getHeight();  

    // 直接設置圖像的寬度和高度為畫布的寬度和高度  

    img.set({

      left: 0, 

      top: 0,

      scaleX: canvasWidth / img.width,

      scaleY: canvasHeight / img.height,  

      selectable: false, // 讓背景圖不可選  

      evented: false,     // 讓背景圖不觸發事件  

      is_background: true // 自定義屬性,背景圖標識 區別于普通圖片元素  

    }); 

    // 將背景圖添加到畫布上  

    this.canvas.add(img);

    // 將背景圖放在所有其他對象的底層  

    this.canvas.sendToBack(img);

    // 重新渲染畫布  

    this.canvas.renderAll();

  }, { crossOrigin: 'anonymous' });

},

上述方法可以實現設置背景圖,但如果我已經設置了背景圖,現在又想替換其他背景圖時。由于新添加的背景圖被放到了最底層,舊的背景圖還沒刪除掉,舊圖覆蓋在新的背景圖上,所以上述代碼需要優化,

解決方法:

因為我在添加背景圖時自定義了屬性is_background,所以每次添加背景圖先前遍歷畫布上的元素,如果is_background屬性為true則刪除它。然后再添加背景圖。完整邏輯如下

setBackgroundImage(imageUrl) {

  fabric.Image.fromURL(imageUrl, (img) => {

    // 獲取畫布的寬度和高度  

    const canvasWidth = this.canvas.getWidth();  

    const canvasHeight = this.canvas.getHeight();  

    // 直接設置圖像的寬度和高度為畫布的寬度和高度  

    img.set({

      left: 0, 

      top: 0,

      scaleX: canvasWidth / img.width,

      scaleY: canvasHeight / img.height,  

      selectable: false, // 讓背景圖不可選  

      evented: false,     // 讓背景圖不觸發事件  

      is_background: true // 背景圖標識  

    }); 

    // 遍歷畫布上的所有對象,查找并刪除已存在的背景圖  

    this.canvas.getObjects().forEach((obj) => {  

      if (obj.is_background) {  

        this.canvas.remove(obj);  

      }  

    });

    // 將背景圖添加到畫布上  

    this.canvas.add(img);

    // 將背景圖放在所有其他對象的底層  

    this.canvas.sendToBack(img);

    // 重新渲染畫布  

    this.canvas.renderAll();

  }, { crossOrigin: 'anonymous' });

},

修改屬性

選中元素時,selectedObject表示選中的對象,此時右側顯示相應的屬性值修改框。

通過selectedObject.type區分文本或圖片。i-text為文本,image為圖片

文字常見屬性修改:

字體顏色:fill;

字體大小:fontSize;

字體粗細:fontWeight,常規為normal,加粗bold;

字體風格:fontStyle,常規為normal,斜體italic;

下劃線:underline,布爾值;

刪除線:linethrough,布爾值;

 

<!-- 字體屬性修改 -->

<div v-if="selectedObject.type === 'i-text'">

    <div class="style-title">顏色:</div>

    <el-color-picker style="width: 100%;" v-model="selectedObject.fill" @change="updateColor"></el-color-picker>

    <div class="style-title">字體大小:</div>

    <el-input-number  size="small" v-model="selectedObject.fontSize" controls-position="right" @change="canvasRender" :min="1"></el-input-number>

    <div class="style-title">常用屬性:</div>

    <!-- 加粗,斜體,下劃線,刪除線 -->

    <div class="font-style">

      <i class="fa fa-bold" @click="updateTextProps('bold')"></i>

      <i class="fa fa-italic" @click="updateTextProps('italic')"></i>

      <i class="fa fa-underline" @click="updateTextProps('underline')"></i>

      <i class="fa fa-strikethrough" @click="updateTextProps('linethrough')"></i>

    </div>

</div>

......

methods: {

    // 修改顏色

    updateColor(newColor) {

      this.selectedObject.fill = newColor

      this.selectedObject.dirty = true;

      this.canvas.renderAll();

    },

    

    // 渲染畫布

    canvasRender(e) {

      this.canvas.renderAll();

    },

    

    // 修改文字屬性

    updateTextProps(type) {

      if(type == 'bold') {

      // 加粗

        this.selectedObject.fontWeight = this.selectedObject.fontWeight == 'normal' ? 'bold' : 'normal'

      }

      if(type == 'italic') {

      // 斜體

        this.selectedObject.fontStyle = this.selectedObject.fontStyle == 'normal' ? 'italic' : 'normal'

      }

      if(type == 'linethrough') {

      // 刪除線

        this.selectedObject.linethrough = !this.selectedObject.linethrough

      }

      if(type == 'underline') {

      // 下劃線

        this.selectedObject.underline = !this.selectedObject.underline

      }

      this.selectedObject.dirty = true;

      this.canvas.renderAll();

    },

}

圖片常見屬性修改

圖片我主要做了尺寸的修改。

 

直接修改width,height并不能改變圖片的大小。這是圖片本身的物理大小,不能修改的。畫布上展現的圖片實際大小為物理大小*縮放比,例如寬默認為:width*scaleX,高為height*scaleY。修改圖片尺寸,實際上就是修改縮放比scale。因此,在添加圖片時,我需要為圖片添加兩個自定義屬性,來表示圖片在畫布上的實際大小。添加自定義屬性scaleWidth,scaleHeight,表示縮放后圖片的實際大小。上述添加圖片的方法可做以下優化:

addImage() {

  fabric.Image.fromURL('圖片url', (img) => {

    ......

    img.scale(scale).set({

      ......

      scaleWidth: img.width * scale,

      scaleHeight: img.height * scale

    });

    ......

  }, { crossOrigin: 'anonymous' });

},

接下來,在右側屬性編輯區修改圖片尺寸,實際上要根據修改后的尺寸scaleWidth去計算新的縮放比scaleX,height同理。然后更新圖片屬性的scaleX,scaleY屬性即可。直接用鼠標拖拽圖片的邊去進行縮放也是在修改scaleX,scaleY。

<!-- 圖片屬性修改 -->

<div v-if="selectedObject.type === 'image'">

    <div class="style-title">尺寸:</div>  

    <div class="place-line">

      <el-input-number v-model="selectedObject.scaleWidth" size="small" placeholder="寬度" controls-position="right" @change="updateImgScale" :min="1" :max="1000" :precision="0" /> 

      <el-input-number v-model="selectedObject.scaleHeight" size="small" placeholder="高度" controls-position="right" @change="updateImgScale" :min="1" :max="1000" :precision="0" /> 

    </div>

</div>

methods: {

    // 縮放圖片

    updateImgScale() { 

      const newScaleX = this.selectedObject.scaleWidth / this.selectedObject.width; 

      const newScaleY = this.selectedObject.scaleHeight / this.selectedObject.height; 

      this.selectedObject.set({

        scaleX: newScaleX,

        scaleY: newScaleY,

      })

      this.canvas.renderAll();

    },

}

刪除

將當前選中的對象或對象的集合刪除。我這里用到的是getActiveObjects,獲取所有選中的對象,遍歷并通過canvas.remove()全部刪除,如果想獲取單個對象,可以用this.canvas.getActiveObject()。

<i class="el-icon-delete" style="color: red;" @click="deleteSelectedObjects"> 

刪除</i>

......

// 刪除元素

deleteSelectedObjects() {

  const selectedObjects = this.canvas.getActiveObjects();

  if (selectedObjects.length > 0) {

    selectedObjects.forEach(obj => {

      this.canvas.remove(obj);

    });

    this.canvas.renderAll();

    // 清除 selectedObject 引用,如果你需要在其他地方使用它  

    this.selectedObject = null;

  }

},

生成JSON

 

將畫布上的所有內容生成JSON文件。通過canvas.toJSON將畫布上的圖形對象轉為JSON對象,生成的JSON對象默認情況下是包含對象的所有屬性,但自定義屬性我們需要手動指定。this.canvas.toJSON(['屬性A', '屬性B',...])

<el-button type="primary" size="small" @click="exportCanvasAsJSON">生成JSON</el-button>

......

exportCanvasAsJSON() {

  // 獲取畫布上所有對象的JSON表示  

  const jsonData = this.canvas.toJSON(['selectable', 'evented', 'is_background', 'scaleX', 'scaleY', 'scaleWidth', 'scaleHeight']); // 你可以根據需要包含或排除屬性

  // 將JSON對象轉換為字符串  

  const jsonString = JSON.stringify(jsonData, null, 2);

    

  // 以下是下載的邏輯=====================

  // 創建一個Blob對象  

  const blob = new Blob([jsonString], { type: 'text/json' });

  // 創建一個指向blob的URL  

  const url = window.URL.createObjectURL(blob);

  // 創建一個臨時的a標簽用于下載  

  const a = document.createElement('a');

  a.href = url;

  a.download = 'canvas_data.json'; // 指定下載的文件名  

  document.body.appendChild(a);

  a.click(); // 模擬點擊以觸發下載  

  // 清理  

  document.body.removeChild(a);

  window.URL.revokeObjectURL(url);

},

生成圖片

通過canvas.toDataURL將畫布內容導出為數據 URL,并指定為圖像格式(如 PNG 或 JPEG)。

<el-button type="primary" size="small" @click="exportCanvasAsImage">下載圖片</el-button>

......

exportCanvasAsImage() {

  // 設置圖片的質量和格式,這里以PNG格式為例,質量為0.8  

  const imageUrl = this.canvas.toDataURL({  

      format: 'png',  

      quality: 0.8  

  });

  

  // 以下是下載的邏輯=====================

  // 創建一個指向該DataURL的a標簽用于下載

  const a = document.createElement('a');

  a.href = imageUrl;

  a.download = 'canvas_image.png'; // 指定下載的文件名

  document.body.appendChild(a);

  a.click(); // 模擬點擊以觸發下載

  document.body.removeChild(a);

  window.URL.revokeObjectURL(imageUrl);

}

渲染JSON為圖像

前面生成的JSON文件,我們通常會保存到本地或傳給后端。一般二次編輯時,是需要回顯畫布的。回顯畫布可通過canvas.loadFromJSON(json, [callback])來實現。

json (String): 描述畫布狀態的 JSON 字符串。

callback (Function, 可選): 當 JSON 數據加載完成并渲染到畫布上后調用的函數

mounted() {

    this.initData()

    // 如果是編輯時

    if(isEdit) {

      // 請求接口,或讀取本地的JSON文件...

      // jsonData為需要渲染的JSON

      this.canvas.loadFromJSON(jsonData, this.canvas.renderAll.bind(this.canvas))

    }

},

?轉自https://juejin.cn/post/7427513979639496741



該文章在 2024/10/25 10:41:56 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved