mxGraph是一個支持多種語言(Java、JavaScript、PHP、.NET)的畫圖框架,所繪製的圖形能夠在主流瀏覽器以及原生應用上使用。
mxGraph官方資料全英文,網上有幾篇mxGraph的教程,對於「入門」和「使用」講解得比較詳細。
因此這篇文章不是介紹如何畫一個圖形,寫一個hello world,而是重點介紹學習mxGraph時以爲比較重要的、難以理解的或者容易被忽略的知識點。
須要讀者對mxGraph的文檔有必定的瞭解或者使用mxGraph。css
mxGraph的使用場景有4個:圖形可視化、圖形交互、圖形佈局、圖形分析。html
圖形可視化是mxGraph的主打功能,這個很好理解,就是把一些抽象的概念用圖形來表示,好比常見的流程圖、思惟導圖、實體關係圖等。
須要注意的是mxGraph所繪製的圖主要是由「點」(也包括矩形、圓形這類基本形狀)和「邊」組成的,若是要用mxGraph來畫蒙娜麗莎那就確定是不合適的。
下圖是官方提供的一張樣圖。
做者猜想實現方式是用世界地圖做爲背景圖片,而後在此之上繪製點和線。
爲了驗證猜想,訪問了官方示例提供的網站,發現是一張jpg圖片,並且沒有連線。
多是後端生成導出的位圖,或者源圖片已經被網站替換了。前端
mxGraph除了繪製圖形以外還提供了豐富的編輯功能,好比拖拽、選擇、複製、調整大小等。
mxGraph甚至還專門提供了一個API類用來支持在線編輯器。
關於這一塊我沒有使用~git
很是重要的一個功能,能自動排列圖形元素。
mxGraph提供了多種佈局方式,好比樹形佈局、棧式佈局、圓形佈局。
這一塊後面重點介紹。github
支持圖相關的算法分析,好比找出圖中兩個節點的最短路徑。
關於這一塊我沒有使用~
不過我沒有找到相關API,估計須要開發者本身實現相關算法。算法
學習新技術或框架的時候首先須要弄清楚它是什麼,能作什麼。
若是和要實現的功能匹配再繼續學習研究。數據庫
前端繪製圖形有3種方式:canvas
canvas使用也比較普遍,好比百度的著名開源項目echarts就是經過canvas來繪製各類圖形。後端
mxGraph默認繪製的是svg圖形(看API文檔和源碼發現也支持canvas),因此支持後端語言進行預渲染,同時也支持保存和導出,轉化爲位圖也很是方便。
理解了這一點,對咱們瞭解mxGraph的功能特性,以及修改源代碼都會有幫助。瀏覽器
cell這個概念能夠理解成爲雙向數據綁定中的數據模型,咱們須要修改圖形的時候,應該經過mxGraph提供的API來修改mxCell實例的屬性,而後mxGraph的繪圖函數來根據數據模型來修改視圖。
mxGraph的其餘不少概念都是以cell做爲基礎的:樣式、佈局、內容文本、事件、位置......
beginUpdate
和endUpdate
函數,寫法上和數據庫的事務提交很像,也有文章說是進行批量處理,實際上只是爲了不屢次觸發而合併了change事件而已,若是不使用這兩個函數不會對繪圖結果產生什麼影響。至於回滾什麼的那是想多了。很多開發者看到「算法」這個詞就會犯怵,以爲很複雜、難以理解。
但其實mxGraph的佈局算法並無那麼難以理解。
不少時候咱們還須要對mxGraph繪製的圖形進行定製化開發,主要爲下面幾點。
mxGraph對樣式的支持是很是不完善的。
例以下面的代碼是用來實現一個高亮樣式的,若是支持CSS樣式類,咱們只須要寫個高亮樣式,增刪類名便可。
可是mxgraph就比較麻煩,要寫成對象,同時在取消高亮時要手動清除對應屬性。
var common_highlight = {} common_highlight[mxConstants.STYLE_FONTSTYLE] = mxConstants.FONT_BOLD var vertex_highlight = Object.assign({}, common_highlight) vertex_highlight[mxConstants.STYLE_FILLCOLOR] = '#00ffff' var edge_highlight = Object.assign({}, common_highlight) edge_highlight[mxConstants.STYLE_STROKECOLOR] = '#00ffff' if (hover) { if (!state.styleList) { if (state.cell.edge) { state.styleList = new mxStylesheetList(Object.assign({}, graph.getStylesheet().styles.defaultEdge, state.style)); } else if (state.cell.vertex) { state.styleList = new mxStylesheetList(Object.assign({}, graph.getStylesheet().styles.defaultVertex, state.style)); } } if (state.cell.vertex && state.cell.value) { state.styleList.add('highlight', vertex_highlight); } if (state.cell.edge) { state.styleList.add('highlight', edge_highlight); } } else { state.styleList.remove('highlight'); } state.style = state.styleList.get(); state.shape.apply(state); state.shape.redraw(); if (state.text != null) { state.text.apply(state); state.text.redraw(); }
mxGraph一個強大之處是支持在svg中插入HTML元素,官方給出的examples中有個htmllabel.html實現了相似功能。
歸納地說兩步實現:
相關代碼以下:
var obj = doc.createElement('UserObject'); obj.setAttribute('label', 'FASTQ files'); var v1 = graph.insertVertex(col[0], null, obj, 0, 0, width, height) ... graph.convertValueToString = function (cell) { let div = document.createElement('div') ... return div; }
mxGraph的邊都是自動繪製的,API支持對邊的樣式修改,好比箭頭、粗細等。
邊繪製成折線的時候爲兩種形式,默認是經過貝塞爾曲線繪製成帶圓角的折線,另外一種是直角折線。
mxGraph內部並無對這些邊進行優化,若是佈局不合理,交叉、穿過點的狀況就會發生。
在開發中我對邊的繪製方式進行了小小的修改,統一改成直接使用三次貝塞爾曲線鏈接,具體代碼以下:
// shap/mxShap.js mxShape.prototype.addPoints = function(c, pts, rounded, arcSize, close, exclude, initialMove) { if (pts != null && pts.length > 0) { initialMove = (initialMove != null) ? initialMove : true; var pe = pts[pts.length - 1]; // Adds virtual waypoint in the center between start and end point if (close && rounded) { pts = pts.slice(); var p0 = pts[0]; var wp = new mxPoint(pe.x + (p0.x - pe.x) / 2, pe.y + (p0.y - pe.y) / 2); pts.splice(0, 0, wp); } var pt = pts[0]; var i = 1; // Draws the line segments if (initialMove) { c.moveTo(pt.x, pt.y); } else { c.lineTo(pt.x, pt.y); } const midX = pt.x / 2 + pe.x / 2 // 調用內置函數繪製三次貝塞爾曲線 c.curveTo(midX, pt.y, midX, pe.y, pe.x, pe.y) // 忽略後面繪製折線的代碼 return; //... }
參考: