mxGraph使用經驗總結

mxGraph是一個支持多種語言(Java、JavaScript、PHP、.NET)的畫圖框架,所繪製的圖形能夠在主流瀏覽器以及原生應用上使用。
mxGraph官方資料全英文,網上有幾篇mxGraph的教程,對於「入門」和「使用」講解得比較詳細。
因此這篇文章不是介紹如何畫一個圖形,寫一個hello world,而是重點介紹學習mxGraph時以爲比較重要的、難以理解的或者容易被忽略的知識點。
須要讀者對mxGraph的文檔有必定的瞭解或者使用mxGraph。css

mxGraph的使用場景

mxGraph的使用場景有4個:圖形可視化、圖形交互、圖形佈局、圖形分析。html

圖形可視化

圖形可視化是mxGraph的主打功能,這個很好理解,就是把一些抽象的概念用圖形來表示,好比常見的流程圖、思惟導圖、實體關係圖等。
須要注意的是mxGraph所繪製的圖主要是由「點」(也包括矩形、圓形這類基本形狀)和「邊」組成的,若是要用mxGraph來畫蒙娜麗莎那就確定是不合適的。
下圖是官方提供的一張樣圖。
做者猜想實現方式是用世界地圖做爲背景圖片,而後在此之上繪製點和線。
爲了驗證猜想,訪問了官方示例提供的網站,發現是一張jpg圖片,並且沒有連線。
多是後端生成導出的位圖,或者源圖片已經被網站替換了。前端

{% asset_img vis.png %}

圖形交互

mxGraph除了繪製圖形以外還提供了豐富的編輯功能,好比拖拽、選擇、複製、調整大小等。
mxGraph甚至還專門提供了一個API類用來支持在線編輯器。
關於這一塊我沒有使用~git

{% asset_img interaction.png %}

圖形佈局

很是重要的一個功能,能自動排列圖形元素。
mxGraph提供了多種佈局方式,好比樹形佈局、棧式佈局、圓形佈局。
這一塊後面重點介紹。github

{% asset_img layout.png %}

圖形分析

支持圖相關的算法分析,好比找出圖中兩個節點的最短路徑。
關於這一塊我沒有使用~
不過我沒有找到相關API,估計須要開發者本身實現相關算法。算法

{% asset_img analysis.png %}

小結

學習新技術或框架的時候首先須要弄清楚它是什麼,能作什麼。
若是和要實現的功能匹配再繼續學習研究。數據庫

mxGraph的繪圖方式

前端繪製圖形有3種方式:canvas

  1. HTML + CSS。
  2. canvas。
  3. svg。

HTML+ CSS

優勢

  • 前端工程師最熟悉最經常使用的方式,開發起來很是簡單。
  • 藉助CSS3能夠實現炫酷的動畫效果。

缺點

  • 很是依賴瀏覽器環境,若是要遷移到原生應用上或者客戶端就會比較麻煩。
  • HTML、CSS沒有合適的模塊機制,因此圖形的複用也不方便。

canvas

canvas使用也比較普遍,好比百度的著名開源項目echarts就是經過canvas來繪製各類圖形。後端

優勢

  • 強大的API,能夠實現複雜的圖形和效果。
  • 渲染速度快,能夠利用顯卡加速。

缺點

  • 也很是依賴瀏覽器環境,並且低版本的瀏覽器不支持。
  • 代碼邏輯比較複雜。
  • 不方便保存和導出。

svg

優勢

  • 寬泛的運行環境。瀏覽器、繪圖工具、編輯器裏均可以正常顯示。
  • 良好的可編輯性。svg能夠在前端經過JavaScript修改,也能夠經過後端語言修改,還可讓設計師經過軟件修改。
  • 使用簡單。svg是xml的語法,沒有複雜的邏輯,全都是配置出來
  • 矢量圖。相對於位圖,無分辨率要求,縮放清晰。

缺點

  • 複雜圖形渲染速度較慢。

小結

mxGraph默認繪製的是svg圖形(看API文檔和源碼發現也支持canvas),因此支持後端語言進行預渲染,同時也支持保存和導出,轉化爲位圖也很是方便。
理解了這一點,對咱們瞭解mxGraph的功能特性,以及修改源代碼都會有幫助。瀏覽器

mxGraph的核心概念cell

cell這個概念能夠理解成爲雙向數據綁定中的數據模型,咱們須要修改圖形的時候,應該經過mxGraph提供的API來修改mxCell實例的屬性,而後mxGraph的繪圖函數來根據數據模型來修改視圖。
mxGraph的其餘不少概念都是以cell做爲基礎的:樣式、佈局、內容文本、事件、位置......

誤區

  1. 前面提到mxGraph的圖形分爲兩類:vertex(點)和edge(邊),但實際上它們都屬於mxCell類的實例,只是一些屬性值不一樣而已。
  2. 官方文檔提供的beginUpdateendUpdate函數,寫法上和數據庫的事務提交很像,也有文章說是進行批量處理,實際上只是爲了不屢次觸發而合併了change事件而已,若是不使用這兩個函數不會對繪圖結果產生什麼影響。至於回滾什麼的那是想多了。

mxGraph的佈局算法

很多開發者看到「算法」這個詞就會犯怵,以爲很複雜、難以理解。
但其實mxGraph的佈局算法並無那麼難以理解。

  • 全部的佈局算法類都是「繼承」自基類mxGraphLayout,自定義了一些屬性,同時實現API函數execute,mxGraph在繪製圖形的時候會調用這個函數。
  • 佈局算法只涉及到vertex(點)的操做,當vertex(點)被調整以後,mxGraph會自動調整它們之間edge(邊)的關係,或是顯示隱藏或是彎曲。
  • 若是須要繪製大量的圖形容易形成性能問題,不該該在算法中實現這。而能夠藉助mxGraph提供的幾種默認方式實現:1.摺疊/展開;2. 鑽取/彈出;3.分層過濾顯示

mxGraph的定製化

不少時候咱們還須要對mxGraph繪製的圖形進行定製化開發,主要爲下面幾點。

樣式

mxGraph對樣式的支持是很是不完善的。

  • 首先不支持使用css,。這樣也就意味着沒法使用樣式繼承,樣式類這些特性了。
  • 修改的時候須要經過API函數,傳入JSON對象。
  • mxGraph內部操做樣式的時候並無使用defs標籤來聲明樣式類,而是直接修改標籤的style、fill這些屬性。這樣會致使不少重複樣式代碼,同時不方便樣式覆蓋。

例以下面的代碼是用來實現一個高亮樣式的,若是支持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();
}

HTML元素

mxGraph一個強大之處是支持在svg中插入HTML元素,官方給出的examples中有個htmllabel.html實現了相似功能。
歸納地說兩步實現:

  1. 在建立點的時候插入一個 UserObject 對象聲明,代表此處能夠插入DOM元素。
  2. 重載 convertValueToString 函數,返回DOM元素。

相關代碼以下:

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;
    //...
  }

參考:

相關文章
相關標籤/搜索