предисловие
В: Что такое bpmn.js?
"
bpmn.jsЭто набор инструментов рендеринга BPMN2.0 и средство веб-моделирования, которое позволяет выполнять функцию рисования блок-схем во внешнем интерфейсе.
В: Почему я пишу эту серию учебников? 🤔️
"
Из-за потребностей бизнеса компании его необходимо использовать в проектеbpmn.js
, Однако из-заbpmn.js
Разработчики игры зарубежные друзья,поэтому отечественных методических материалов мало и нет подробных документов.Поэтому много способов использования и много ям приходится искать самому.Поразмыслив,решил написать серию учебные материалы об этом. чтобы помочь большеbpmn.js
Пользователи или разработчики, которые ищут хороший способ рисовать блок-схемы, в то же время для них это еще и своего рода консолидация.
Поскольку это серия статей, она может часто обновляться.Пожалуйста, простите меня, если вы случайно смахнули его, и это не то, что вам нужно😊.
Не просите похвалы👍 не просите сердца❤️ Я просто надеюсь, что смогу вам немного помочь.
Статьи о пользовательском рендерере
Следуя предыдущей главе, мы уже знаем, как настроить панель инструментов (Палитру) слева, а те, кто не понимает, могут перемещаться:"Самый подробный учебный материал по bpmn.js во всей сети - пользовательская палитра".
Но в то же время мы также знаем, что только меняетсяPalette
недостаточно, потому что нарисованная фигура еще «голая»:
В этой главе давайте рассмотрим, как настроить графику на холсте, то есть добиться настройкиRenderer
функция.
Читая, вы узнаете:
- Изменить на основе средства визуализации по умолчанию
- Полностью настраиваемый рендерер
- Тег label настраивается под элементом
Изменить на основе средства визуализации по умолчанию
и обычайPalette
Точно так же давайте рассмотрим простейшую модификацию исходного элемента.
Предварительная подготовка
продолжимLinDaiDai/bpmn-vue-customразработка кейс-проекта.
существуетcomponents
создать новую папкуcustom-renderer.vue
файл и настройте маршрут «пользовательский рендерер».
существуетcomponents/custom
создать новую папкуCustomRenderer.js
файл для настройкиrenderer
.
существуетcomponents
создать новую папкуutils
Одновременно создайте новую папкуutil.js
файл, используемый для размещения некоторых общедоступных методов и конфигурации.
записыватьCustomRenderer.vue
код
из-заbpmn.js
Измените существующие элементы, поэтому сначала мы можем сначалаBaseRenderer
Этот класс импортируется, а затем пусть наш пользовательскийrenderer
унаследовать это:
import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer' // 引入默认的renderer
const HIGH_PRIORITY = 1500 // 最高优先级
export default class CustomRenderer extends BaseRenderer { // 继承BaseRenderer
constructor(eventBus, bpmnRenderer) {
super(eventBus, HIGH_PRIORITY)
this.bpmnRenderer = bpmnRenderer
}
canRender(element) {
// ignore labels
return !element.labelTarget
}
drawShape(parentNode, element) { // 核心函数就是绘制shape
const shape = this.bpmnRenderer.drawShape(parentNode, element)
return shape
}
getShapePath(shape) {
return this.bpmnRenderer.getShapePath(shape)
}
}
CustomRenderer.$inject = ['eventBus', 'bpmnRenderer']
Приведенный выше код 👆 очень прост, я думаю, его сможет понять каждый.
Примечание. Здесь есть небольшая яма, на которую следует обратить внимание, т.HIGH_PRIORITY
Его нельзя удалить, иначе вы обнаружите, что он не будет выполнять следующиеdrawShpe
функция
Когда вы придете сюда, могут быть некоторые друзья, которые захотят спросить. Я чувствую, что вы сделали так много, и это бесполезно. Я до сих пор не видел настройки.renderer
Эффект 😅!
Да, недостаточно просто выполнить вышеперечисленные действия, главное, как написатьdrawShape
Сюда.
записыватьdrawShape
код
Сначала мы можем создатьutils/util.js
Напишите этот код под файлом:
// util.js
const customElements = ['bpmn:Task']
export { customElements }
То есть создатьcustomElements
Массив , а затем экспортированный, почему в массиве только один элементbpmn:Task
?🤔️
Это потому, что в предыдущем случае я создалlindaidai-task
Типbpmn:Task
Тип.
Таким образом, функция этого массива состоит в том, чтобы указать, какие типы нам нужно настроить, чтобы мы могли отличить их от элементов, которые не нужно настраивать при рендеринге.
Вы даже можете сделать некоторую настройку:
const customElements = ['bpmn:Task'] // 自定义元素的类型
const customConfig = { // 自定义元素的配置(后面会用到)
'bpmn:Task': {
'url': 'https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/rules.png',
'attr': { x: 0, y: 0, width: 48, height: 48 }
}
}
export { customElements, customConfig }
впусти насCustomRenderer.js
используйте и напишите его в:
import { customElements, customConfig } from '../utils/util'
...
drawShape(parentNode, element) {
const type = element.type // 获取到类型
if (customElements.includes(type)) { // or customConfig[type]
const { url, attr } = customConfig[type]
const customIcon = svgCreate('image', { // 在这里创建了一个image
...attr,
href: url
})
element['width'] = attr.width // 这里我是取了巧, 直接修改了元素的宽高
element['height'] = attr.height
svgAppend(parentNode, customIcon)
return customIcon
}
const shape = this.bpmnRenderer.drawShape(parentNode, element)
return shape
}
...
Как видите, способ заставить страницу отображать нужный эффект — использоватьsvgCreate
метод созданияimage
и добавлен к родительскому узлу.
экспортировать и использоватьCustomRenderer
такая же настройкаrenderer
Необходимо экспортировать, чтобы использовать, модифицироватьcustom/index.js
документ:
import CustomPalette from './CustomPalette'
import CustomRenderer from './CustomRenderer'
export default {
__init__: ['customPalette', 'customRenderer'],
customPalette: ['type', CustomPalette],
customRenderer: ['type', CustomRenderer]
}
Уведомление:__init__
именование атрибутов вcustomRenderer
Все они имеют фиксированное написание и не могут быть изменены, иначе не будет никакого эффекта.
если ты читал это раньшеcustom-palette.vue
Если это так, вы знаете, что можете применить его прямо на странице:
<!--custom-renderer.vue-->
<script>
...
import customModule from './custom'
...
this.bpmnModeler = new BpmnModeler({
...
additionalModules: [
// 左边工具栏以及节点
propertiesProviderModule,
// 自定义的节点
customModule
]
})
Примечание: В случае с проектом для удобства демонстрации вcustom-palette
Представлен вImportJS/onlyRenderer.js
, а рассмотренный выше случай основан на введенииcustom/index.js
Для того, чтобы объяснить, это надо самому понять, как различать.
На данный момент вы можете увидеть эффект при открытии страницы, типbpmn:Task
Узел отображается как пользовательский «золотой строительный блок» 😝:
Полностью настраиваемый рендерер
полностью настраиваемыйRenderer
означает, что первоначальное использованиеnew BpmnModeler
Способ создания холста изменился на использованиеnew CustomModeler
создавать.
Эта часть находится в"Самый подробный учебный материал по bpmn.js во всей сети - пользовательская палитра"Это объясняется очень подробно, поэтому я не буду вдаваться в подробности.
Также вcustomModeler/custom
создать папку вcustomRender.js
файл, а затем напишите следующий код:
/* eslint-disable no-unused-vars */
import inherits from 'inherits'
import BaseRenderer from 'diagram-js/lib/draw/BaseRenderer'
import {
append as svgAppend,
create as svgCreate
} from 'tiny-svg'
import { customElements, customConfig } from '../../utils/util'
/**
* A renderer that knows how to render custom elements.
*/
export default function CustomRenderer(eventBus, styles) {
BaseRenderer.call(this, eventBus, 2000)
var computeStyle = styles.computeStyle
this.drawCustomElements = function(parentNode, element) {
console.log(element)
const type = element.type // 获取到类型
if (customElements.includes(type)) { // or customConfig[type]
const { url, attr } = customConfig[type]
const customIcon = svgCreate('image', {
...attr,
href: url
})
element['width'] = attr.width // 这里我是取了巧, 直接修改了元素的宽高
element['height'] = attr.height
svgAppend(parentNode, customIcon)
return customIcon
}
const shape = this.bpmnRenderer.drawShape(parentNode, element)
return shape
}
}
inherits(CustomRenderer, BaseRenderer)
CustomRenderer.$inject = ['eventBus', 'styles']
CustomRenderer.prototype.canRender = function(element) {
// ignore labels
return !element.labelTarget;
}
CustomRenderer.prototype.drawShape = function(p, element) {
return this.drawCustomElements(p, element)
}
CustomRenderer.prototype.getShapePath = function(shape) {
console.log(shape)
}
Изменять непосредственно в цепочке прототиповdrawShape
метода достаточно.
тогда не забудьтеcustomModeler/custom/index.js
чтобы экспортировать его.
Тег label настраивается под элементом
Из-за вопроса, поднятого небольшим партнером в области комментариев: какlabel
Пользовательский ярлык ниже элемента?
Итак, Лин был ошеломлен, и я вернулся и потратил некоторое время на его изучение.label
Этикетка.
первыйlabel
Этикетка на самом делеxml
Имя на каждой этикетке вname
свойства, как показано ниже:
начальный узел иlindaidai-task
в целомname
свойства, но вbpmn:StartEvent
может этоlabel
отображается, потому что естьbpmndi:BPMNLabel
Тег.
В результате график выглядит так:
Итак, как мы поместимlabel
покажи это?
Сначала положимShape
Распечатайте и посмотрите:
можно найти вbusinessObject
есть одинname
Атрибуты...
В этом случае мы, безусловно, можемdrawShape
получить этоname
свойства, которые можно использовать позжеsvgCreate
Метод добавляет метку текстового типа к родительскому узлу.
// CustomRenderer.js
import { hasLabelElements } from '../../utils/util'
drawShape(parentNode, element) {
const type = element.type // 获取到类型
if (customElements.includes(type)) { // or customConfig[type]
const { url, attr } = customConfig[type]
const customIcon = svgCreate('image', {
...attr,
href: url
})
element['width'] = attr.width // 这里我是取了巧, 直接修改了元素的宽高
element['height'] = attr.height
svgAppend(parentNode, customIcon)
// 判断是否有name属性来决定是否要渲染出label
if (!hasLabelElements.includes(type) && element.businessObject.name) {
const text = svgCreate('text', {
x: attr.x,
y: attr.y + attr.height + 20, // y取的是父元素的y+height+20
"font-size": "14",
"fill": "#000"
})
text.innerHTML = element.businessObject.name
svgAppend(parentNode, text)
console.log(text)
}
return customIcon
}
const shape = this.bpmnRenderer.drawShape(parentNode, element)
return shape
}
потому что некоторые элементы имеютlabel
атрибуты, такие какbpmn:StartEvent
, так что нет необходимости повторно рендерить, поэтому я используюutil.js
добавил одинhasLabelElements
множество:
// utils/util.js
const hasLabelElements = ['bpmn:StartEvent', 'bpmn:EndEvent'] // 一开始就有label标签的元素类型
Я хотел пройти мимоelement.labels.length<=0
чтобы отфильтровать началоlabel
Элемент метки, но обнаружил, что он недоступен на этапе рендерингаlabels
, поэтому длина всегда будет0
, просто определитеhasLabelElements
Приходите судить 😓...
Эффект от открытия страницы следующий:
Похоже, это сработало! Молодец! 😄
но когда я дважды щелкаю, хочу перейти к редактированиюlabel
При записи появляется такой эффект:
Он создал новое поле ввода прямо поверх моего исходного графика...
Эх😅... На самом деле, я не придумал никакого хорошего способа решить эту проблему. Здесь я предлагаю решение, которое кажется возможным:При двойном щелчке по элементуtext
быть удалены или егоinnerHTML
Установить как''
.
Конечно, если вы чувствуете, что можете смотреть это в таком виде, ничего страшного, если мы не возимся с этим, ведь здесь вы редактируете контент.label
Он также будет меняться синхронно.
Если нет, вы можете изменить его глобальноdjs-direct-editing-parent
Для стиля этого класса также можно прикрыть текст ниже... Конечно, я чувствую, что это не очень хороший способ.
существуетapp.css
написать в:
.djs-direct-editing-parent {
top: 130px!important;
width: 60px!important;
}
Суммировать
Вышеупомянутый подход в основном используется дляsvgCreate
создаватьtext
элемент добавлен вparentNode
в, на самом делеbpmn.js
использовал многоting-svg
Я никогда раньше не сталкивался с такими вещами, а потом я также узнал, ища информацию.svgCreate
использование...
Волна научно-популярного это хорошо, ха-ха 😄:Основы SVG
послесловие
В приведенных выше 👆 случаях используется один и тот же проект🦐
Git-адрес кейса проекта:LinDaiDai/bpmn-vue-customЕсли вам это нравится, пожалуйста, дайтеStar
🌟 Да, спасибо😊
Полный каталог серии можно найти здесь:"Самый подробный учебник по bpmn.js во всей сети"
Рекомендации по сериалу:
"Самый подробный учебник по bpmn.js во всей сети - основы"
"Самый подробный учебный материал по bpmn.js во всей сети - http запрос"
"Самый подробный учебный материал по bpmn.js во всей сети - мероприятия"
"Самый подробный учебник по bpmn.js во всей сети - contextPad"
"Самый подробный учебник по bpmn.js во всей сети - редактирование и удаление узлов"