全網最詳bpmn.js教材-自定義contextPad篇

LinDaiDai_霖呆呆發表於2019-12-20

前言

Q: bpmn.js是什麼? ?️

bpmn.js是一個BPMN2.0渲染工具包和web建模器, 使得畫流程圖的功能在前端來完成.

Q: 我為什麼要寫該系列的教材? ?️

因為公司業務的需要因而要在專案中使用到bpmn.js,但是由於bpmn.js的開發者是國外友人, 因此國內對這方面的教材很少, 也沒有詳細的文件. 所以很多使用方式很多坑都得自己去找.在將其琢磨完之後, 決定寫一系列關於它的教材來幫助更多bpmn.js的使用者或者是期於找到一種好的繪製流程圖的開發者. 同時也是自己對其的一種鞏固.

由於是系列的文章, 所以更新的可能會比較頻繁, 您要是無意間刷到了且不是您所需要的還請諒解?.

不求贊?不求心❤️. 只希望能對你有一點小小的幫助.

自定義ContextPad篇

經過前面幾章的學習, 相信大家都已經掌握了自定義paletterenderer, 這一章節主要講解的是自定義contextPad.

先讓我們來回顧一下, contextPad是什麼?

如圖, 可以看到除了在左側的工具欄處能新增節點之外, 點選節點的時候也會出現一個小彈窗, 這裡面也可以新增節點. 這個小彈窗就是 contextPad.

那麼, 通過閱讀你可以學習到:

在預設的ContextPad基礎上修改

前期準備

讓我們接著在LinDaiDai/bpmn-vue-custom案例專案上進行開發.

components資料夾下新建一個custom-context-pad.vue檔案, 同時配置路由“自定義contextPad”.

components/custom資料夾下新建一個CustomContextPad.vue檔案, 用來自定義contextPad.

編寫CustomContextPad.vue程式碼

其實自定義contextPadpalette很像, 只不過是使用contextPad.registerProvider(this)來指定它是一個contextPad, 而自定義palette是用platette.registerProvider(this).

程式碼如下:

// CustomContextPad.js
export default class CustomContextPad {
    constructor(config, contextPad, create, elementFactory, injector, translate) {
        this.create = create;
        this.elementFactory = elementFactory;
        this.translate = translate;

        if (config.autoPlace !== false) {
            this.autoPlace = injector.get('autoPlace', false);
        }

        contextPad.registerProvider(this); // 定義這是一個contextPad
    }

    getContextPadEntries(element) {}
}

CustomContextPad.$inject = [
    'config',
    'contextPad',
    'create',
    'elementFactory',
    'injector',
    'translate'
];
複製程式碼

相信大家都已經看出來了, 重點還是在於getContextPadEntries這個方法, 接下來讓我們來構建這個方法.

編寫getContextPadEntries程式碼

其實這個方法, 需要返回的也是一個物件, 也就是你要在contextPad這個容器裡顯示哪些自定義的元素, 比如我這裡需要給容器裡新增一個lindaidai-task的元素, 那麼我們可以在返回的物件中新增上append.lindaidai-task這個屬性.

而屬性值就是這個元素的一系列配置, 和palette中一樣, 包括:

  • group: 屬於哪個分組, 比如tools、event、gateway、activity等等,用於分類
  • className: 樣式類名, 我們可以通過它給元素修改樣式
  • title: 滑鼠移動到元素上面給出的提示資訊
  • action: 使用者操作時會觸發的事件

大概是這樣:

// CustomContextPad.js
getContextPadEntries(element) {
    return {
        'append.lindaidai-task': {
            group: 'model',
            className: 'icon-custom lindaidai-task',
            title: translate('建立一個型別為lindaidai-task的任務節點'),
            action: {
                click: appendTask,
                dragstart: appendTaskStart
            }
        }
    };
}
複製程式碼

接下來就是構建appendTaskappendTaskStart

// CustomContextPad.js
getContextPadEntries(element) {
        const {
            autoPlace,
            create,
            elementFactory,
            translate
        } = this;

        function appendTask(event, element) {
            if (autoPlace) {
                const shape = elementFactory.createShape({ type: 'bpmn:Task' });
                autoPlace.append(element, shape);
            } else {
                appendTaskStart(event, element);
            }
        }

        function appendTaskStart(event) {
            const shape = elementFactory.createShape({ type: 'bpmn:Task' });
            create.start(event, shape, element);
        }

        return {
            'append.lindaidai-task': {
                group: 'model',
                className: 'icon-custom lindaidai-task',
                title: translate('建立一個型別為lindaidai-task的任務節點'),
                action: {
                    click: appendTask,
                    dragstart: appendTaskStart
                }
            }
        };
    }
}
複製程式碼

這裡和palette中有一點不同, 就是多了一層autoPlace的判斷, 其實我也沒太搞明白這個autoPlace的作用是什麼, 自動放置? 而且官方給的例子?就是這麼寫的, 有知道的小夥伴還請評論區留言哦, 謝謝~

修改contextPad的相關樣式

此時我們看看效果吧?...

bpmnCustom16.png
bpmnCustom16.png

咿~ 好像可以耶, 但是, 這個小積木也太小了一點吧?, 而且滑鼠移上去之後, 黃色的背景色直接就覆蓋它了...

bpmnCustom17.png
bpmnCustom17.png

哇, 這不能忍啊...

得想法子解決它, 還我漂亮的小積木❤️...

接著讓我們開啟控制檯審查元素, 可以發現這個背景色是一個叫.djs-context-pad .entry的類提供的樣式, 也許, 我們可以全域性修改這個樣式, 讓我們試試看:

/* app.css */

/* 自定義 contextPad 的樣式 */ .djs-context-pad .lindaidai-task.entry:hover { background: url('hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/rules.png') center no-repeat!important; background-size: cover!important; }

.djs-context-pad .entry:hover { /* 重新修改了 hover 之後的樣式 */ border: 1px solid #1890ff; }

複製程式碼

.djs-context-pad .entry { box-sizing: border-box; background-size: 94%; transition: all 0.3s; } 複製程式碼

開啟頁面看看效果哈.

bpmnCustom18.png
bpmnCustom18.png

不錯, 解決了, 哈哈?.

(直接修改樣式雖然不是最好的解決辦法, 但這是目前我能想到的辦法, 而且它確實也能夠解決問題)

完全自定義ContextPad

前期準備

同樣的, 如果你已經學會了在預設的ContextPad基礎上修改, 那麼完全自定義ContextPad也就差不多了?.

不過完全自定義ContextPad不是叫contextPad, 而是contextPadProvider, 好像要更厲害一點?...

OK?, 讓我們在customModeler/custom資料夾下新建一個CustomContextPadProvider.js檔案.

編寫CustomContextPadProvider.js程式碼

先讓我們來看下主要的結構:

// CustomContextPadProvider.js
export default function ContextPadProvider(contextPad, config, injector, translate, bpmnFactory, elementFactory, create, modeling, connect) {
  this.create = create
  this.elementFactory = elementFactory
  this.translate = translate
  this.bpmnFactory = bpmnFactory
  this.modeling = modeling
  this.connect = connect
  config = config || {}
  if (config.autoPlace !== false) {
      this._autoPlace = injector.get('autoPlace', false)
  }
  contextPad.registerProvider(this)
}

ContextPadProvider.$inject = [
  'contextPad',
  'config',
  'injector',
  'translate',
  'bpmnFactory',
  'elementFactory',
  'create',
  'modeling',
  'connect'
]

ContextPadProvider.prototype.getContextPadEntries = function(element) {}
複製程式碼

別看上面程式碼很長的樣子, 其實沒啥東西:

  • 定義一個ContextPadProvider類, 然後引入一些我們後面要用到的方法或者屬性
  • 通過$inject注入進來
  • 重寫原型鏈上的getContextPadEntries方法

編寫getContextPadEntries程式碼

你應該也發現了, 重點還是重寫getContextPadEntries這個方法.

額, 這裡我先以一個簡單的為例, 先只是建立一個lindaidai-task. 因此可以直接把在預設的ContextPad基礎上修改案例中的getContextPadEntries中的程式碼複製過來:

// CustomContextPad.js
getContextPadEntries(element) {
        const {
            autoPlace,
            create,
            elementFactory,
            translate
        } = this;

        function appendTask(event, element) {
            if (autoPlace) {
                const shape = elementFactory.createShape({ type: 'bpmn:Task' });
                autoPlace.append(element, shape);
            } else {
                appendTaskStart(event, element);
            }
        }

        function appendTaskStart(event) {
            const shape = elementFactory.createShape({ type: 'bpmn:Task' });
            create.start(event, shape, element);
        }

        return {
            'append.lindaidai-task': {
                group: 'model',
                className: 'icon-custom lindaidai-task',
                title: translate('建立一個型別為lindaidai-task的任務節點'),
                action: {
                    click: appendTask,
                    dragstart: appendTaskStart
                }
            }
        };
    }
}
複製程式碼

此時讓我們先看看效果哈:

bpmnCustom19
bpmnCustom19

效果好像是實現了, 而且點選和拖拽它也能實現建立lindaidai-task的效果...

但總感覺好像少了什麼, 因為光建立task型別但元素是不夠的呀, 可不可以建立線或者實現編輯, 刪除元素的功能呢? 當然可以啦, 哈哈?.

不過這一章節先說這麼多, 如何建立線和實現編輯, 刪除我會把它放到一下章來細講哈?, 不用著急.

後語

上面?案例用的都是同一個專案?

專案案例Git地址: LinDaiDai/bpmn-vue-custom 喜歡的小夥伴請給個Star?呀, 謝謝?

系列相關推薦:

《全網最詳bpmn.js教材-基礎篇》

《全網最詳bpmn.js教材-http請求篇》

《全網最詳bpmn.js教材-事件篇》

《全網最詳bpmn.js教材-renderer篇》

《全網最詳bpmn.js教材-編輯、刪除節點篇》

相關文章