本文主要記錄如何使用 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);
});
}
代碼解釋:
image(url):在svg上繪制圖片loaded((loader)=>{}):圖片加載成功后的回調事件,loader參數返回的是圖像的信息,包括寬、高、鏈接group():繪制一個圖形組合panZoom():需引入 svg.pan-zoom.js 插件(npm install svg.pan-zoom.js -- save-dev),實現滾動鼠標,放大縮小圖形transform():可以獲取圖形移動和放大縮小的位置setPosition(x, y, scale):x,y表示位置,scale表示縮放比例
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);
}
front():表示在組合里顯示置前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) {
...
});
- 圖形拖拽:需引入 svg.draggable.js 插件(
npm install svg.draggable.js -- save-dev),實現圖形的拖拽draggable(boolean):支持拖拽,當boolean是false的時候禁止拖拽;dragend():拖拽后的事件
- 圖形選擇:需引入 svg.select.js 插件(
npm install svg.select.js -- save-dev),實現圖形的選擇和放大縮小的操作selectize():圖形變成選中狀態resize(param):圖形可放大縮小,當參數param是stop的時候,禁止放大縮小resizedone():圖形放大縮小后的操作
