1. 程式人生 > >基於svg.js實現對圖形的拖拽、選擇和編輯操作

基於svg.js實現對圖形的拖拽、選擇和編輯操作

鼠標移出 strong lse 方便 jquery cap .cn sta plot

本文主要記錄如何使用 svg.js 實現對圖形的拖拽,選擇,圖像渲染及各類形狀的繪制操作。

1、關於SVG

SVG 是可縮放的矢量圖形,使用XML格式定義圖像,可以生成對應的DOM節點,便於對單個圖形進行交互操作。比CANVAS更加靈活一點。關於SVG的基礎知識,請參考SVG學習地址。

2、SVG.js

今天要說的主角是 SVG.js,它是對SVG本身的一個封裝庫,提供各種API使對SVG的使用更加方便,相當於JQuery對於JS,它的自我介紹是 輕量級,速度快,更具易讀性。SVG.js官網介紹的很詳細,不過這裏還是簡單的進行一些匯總。

2.1 初始化

<div id="svgDemo"></div>
this.draw = SVG("svgDemo").size("100%", "100%");
  • SVG(domId) 初始化dom結點。轉成 svg 元素
  • size() 是svg.js中的改變畫板大小的方法,其中參數可以是像素:size(‘100px‘, ‘100px‘);,也可以是百分比size(‘100%‘, ‘100%‘);

2.2 一些基本形狀

如圖所示,我們可以很快速的繪制出一些基本圖形。具體的API詳見對應的代碼塊。
技術分享圖片

// 畫線
let line = this.draw
.line(10, 10, 10, 150) // 起點xy,終點xy
.stroke({ width: 5, linecap: "round", color: "blue" }); // 線條樣式

// 畫矩形
let rect = this.draw
.rect(100, 100) // 寬高
.radius(10) // 圓角
.fill("red") //填充
.move(20, 20); // 位移

// 畫圓
let circle = this.draw
.circle(100) // 圓直徑
.fill("green") 
.move(130, 20);

// 畫橢圓
let ellipse = this.draw
.ellipse(150, 100) // 寬直徑,高直徑
.move(240, 20)
.fill("pink");

// 折線
let polyline = this.draw
.polyline(‘450, 10, 400, 100, 500, 100‘) // 點的位置,也可以使用數組替換[[450,10],[400,100],[500,100]]
.fill("#f06")
.stroke({ width: 1, color: "black" });

// 多邊形
let polygon = this.draw.polygon([[550,10],[600,10],[630,50],[600,100],[550,100],[520,50]]) // 點的位置
.fill("#71f5ea")
.stroke({ width: 1 });

3、實現效果

介紹了簡單的使用方法,現闡述如何使用 svg.js 及對應的一些拓展插件,實現對圖片的標註操作。效果如下,我們可以對圖片進行放大、縮小、拖拽操作,也可以在圖片上繪制不同的圖形。當鼠標放在圖片上時,會出現輔助線。(圖片源於網絡)

  • 圖片縮小效果
    技術分享圖片

  • 圖片放大效果
    技術分享圖片

  • 圖片拖拽效果
    技術分享圖片

  • 在圖片上繪制圖形效果
    技術分享圖片

3.1 繪制圖像

這裏說一下,下面的代碼只是粘貼出核心的代碼。並不能直接粘貼復制實現效果。
技術分享圖片

{
    //...省略代碼
    let that = this;
    this.mainImage = this.draw
    .image(imgurl)
    .loaded(function(loader) {
        // 圖片加載後,設置圖片大小
        this.size(loader.width, loader.height);

        // 繪制一個圖形組合,之後的圖形都在這個組合上操作
        that.drawGroup = that.draw.group();

        // 給圖形組合加邊框
        let borderRect = that.drawGroup
        .rect(loader.width, loader.height)
        .stroke(DeomSet.imageBorder) // DeomSet下都是一些配置項,這裏不再羅列。
        .fill("none");

        // 給圖形組合加輔助線,只有鼠標移入地時候才顯示,先繪制dom
        that.lineX = that.drawGroup.line(0, 0, 0, 0).stroke(DeomSet.imageLine);
        that.lineY = that.drawGroup.line(0, 0, 0, 0).stroke(DeomSet.imageLine);

        // 將圖像也放入組合中
        that.drawGroup.add(this).attr(DeomSet.groupId);

        // 使圖像組合可以放大縮小
        that.groupZoom = that.drawGroup.panZoom(DeomSet.zoomOpt);

        // 鼠標移動事件
        that.drawGroup.on("mousemove", that.mousemoveEvt, that);

        // 鼠標移出事件
        that.drawGroup.on("mouseleave", that.mouseleaveEvt, that);

        // 鼠標點下
        that.drawGroup.on("mousedown", that.mousedownEvt, that);

        // 鼠標松開
        that.drawGroup.on("mouseup", that.mouseupEvt, that);
    });
}

代碼解釋:

  1. image(url) :在svg上繪制圖片
  2. loaded((loader)=>{}):圖片加載成功後的回調事件,loader 參數返回的是圖像的信息,包括寬、高、鏈接
  3. group():繪制一個圖形組合
  4. panZoom():需引入 svg.pan-zoom.js 插件(npm install svg.pan-zoom.js -- save-dev),實現滾動鼠標,放大縮小圖形
    • transform():可以獲取圖形移動和放大縮小的位置
    • setPosition(x, y, scale):x,y表示位置,scale表示縮放比例
  5. on(eventname,event,context) 事件綁定,eventname:事件名,event:事件,context:上下文

3.2 繪制指示參考線

鼠標在圖片上移動的時候,會顯示提示的參考線,這樣更加方便繪制圖形。
技術分享圖片

{       
    //...省略代碼
    // mousemove事件
    // getPointer()這是獲取點的位置的方法,不是API
    let { zx, zy } = this.getPointer(e);
    // 獲取圖片的寬高
    let w = this.mainImage.width();
    let h = this.mainImage.height();
    // 畫線
    this.lineX.front().plot(0, zy + 1, w, zy + 1);
    this.lineY.front().plot(zx + 1, 0, zx + 1, h);
}
  1. front() :表示在組合裏顯示置前
  2. plot():圖形移動繪制

3.3 繪制圖形

技術分享圖片

/**
 * 繪制移動的矩形
 */
//...省略代碼
let currentDraw = this.currentDraw;
if (!currentDraw) {
    this.currentDraw = this.drawGroup
    .rect(0, 0)
    .move(x, y) // 這裏的xy表示矩形的位置
    .fill(OcrSet.rect)
    .stroke(OcrSet.rectStroke)
    .attr({ id: id });
} else {
    let width = Math.abs(zx - x),
    height = Math.abs(zy - y),
    mx = Math.min(zx, x),
    my = Math.min(zy, y); // zx,zy表示移動的鼠標的位置
    this.currentDraw.size(width, height).move(mx, my);
}
/**
 * 繪制多邊形-過程
 */
//...省略代碼 
let currentDraw = this.currentDraw;
if (!currentDraw) {
    points.push([zx, zy]); // points表示當前多邊形的點
    this.currentDraw = this.drawGroup
    .polygon(points)
    .fill(OcrSet.polygo)
    .stroke(OcrSet.rectStroke)
    .attr({ id: id });
} else {
    points = this.currentDraw.array().value.slice(0);
    points.push([zx, zy]);
    this.currentDraw.plot(points);
}
  • array():可以獲取到多邊形的點信息

3.4 圖形選中拖拽事件


// 圖形可拖拽
this.selectShape.draggable();

// 圖形禁止拖拽
this.selectShape.draggable(false);

// 圖形選中並可放大縮小
this.selectShape.selectize(OcrSet.selectOpt).resize();

// 圖形去除選中並禁止放大縮小
this.selectShape.selectize(false, { deepSelect: true }).resize("stop");


// 圖形位置修改後的事件
this.selectShape.on("resizedone", function() {
  ...
});

// 圖形拖拽後的事件
this.selectShape.off("dragend").on("dragend", function(e) {
    ...
});
  1. 圖形拖拽:需引入 svg.draggable.js 插件(npm install svg.draggable.js -- save-dev),實現圖形的拖拽
    • draggable(boolean):支持拖拽,當 booleanfalse 的時候禁止拖拽;
    • dragend():拖拽後的事件
  2. 圖形選擇:需引入 svg.select.js 插件(npm install svg.select.js -- save-dev),實現圖形的選擇和放大縮小的操作
    • selectize():圖形變成選中狀態
    • resize(param):圖形可放大縮小,當參數paramstop的時候,禁止放大縮小
    • resizedone():圖形放大縮小後的操作

基於svg.js實現對圖形的拖拽、選擇和編輯操作