Add attribute to SVG element

Hi there,

I’m styling the BPMN SVG using CSS and I need to add the type of the element in all corresponding svg elements. Something like that:

<g class="djs-element djs-shape" data-element-id="IntermediateThrowEvent_1w7puvt" data-element-type="bpmn:IntermediateCatchEvent">
	...
</g>

I could archive it by doing

bpmnModeler.importXML(xml, function(err) {
	var canvas = _this.bpmnModeler.get('canvas');
	var elements = canvas._elementRegistry._elements;
	for (elm in elements) {
		// Set the attribute with the element type, to apply css
		elements[elm].gfx.setAttribute("data-element-type", elements[elm].element.type);
	}
});

The problem is that when creating new elements, changing, etc. the solutions is no longer valid. So I came up with another solution that works for me. I change the method ElementRegistry.prototype.add direct in the .js file to set the new attribute the same way the attribute data-element-id is set.

...
var ELEMENT_TYPE = 'data-element-type';
ElementRegistry.prototype.add = function(element, gfx, secondaryGfx) {
	...
	attr$1(gfx, ELEMENT_TYPE, element.type);
	...
};

This works as expected, but I want to create a bundle for myself overriding the default behavior of ElementRegistry.prototype.add. I’ve already have my bundle generated using rollup using the umd format. I tried adding the following as module and did not work

import inherits from 'inherits';

import ElementRegistry from 'diagram-js/lib/core/ElementRegistry';

var ELEMENT_TYPE = 'data-element-type';

export default function AddElementType(eventBus) {
	ElementRegistry.call(this, eventBus);
}

inherits(AddElementType, ElementRegistry);

AddElementType.$inject = ['eventBus'];

AddElementType.prototype.add = function (element, gfx, secondaryGfx) {
	console.log(element);
};

How could I override this method? Is there a better approach?

Thank you!

What are you trying to achieve?

Apply real time color customization to the generated SVG, using svg filters. I have a open WebSocket connection that change some attributes of the svg in real time to apply different style for each element type.

In order to do so I need to differentiate all BPMN elements one of another by type. Each type will have your own custom CSS. Something like:

[data-element-type*="Task"][data-v-10] > g > rect { filter: url(#t10) !important; }
[data-element-type*="Task"][data-v-20] > g > rect { filter: url(#t20) !important; }
...
[data-element-type^="bpmn:Intermediate"][data-v-10] > g > circle:first-child { filter: url(#i10) !important; }
...

I know I can do it differently, but I think keeping it in CSS it will be easier to maintain by the design team and I also don’t want to redraw the svg every time a have I change returned by the WebSocket.

Thanks.

I manage to do it replacing the “elementRegistry” with my custom module implementation.

import CustomElementRegistry from './CustomElementRegistry';

export default {
	__init__: [
		'elementRegistry'
	],
	elementRegistry: ['type', CustomElementRegistry]
};

Module implementation is now:

import inherits from 'inherits';

import { attr as svgAttr } from 'tiny-svg';

import ElementRegistry from 'diagram-js/lib/core/ElementRegistry';

var ELEMENT_TYPE = 'data-element-type';

export default function CustomElementRegistry(eventBus) {
	ElementRegistry.call(this, eventBus);
}

inherits(CustomElementRegistry, ElementRegistry);

CustomElementRegistry.$inject = ['eventBus'];

CustomElementRegistry.prototype.add = function (element, gfx, secondaryGfx) {
	CustomElementRegistry.super_.prototype.add.call(this, element, gfx, secondaryGfx);

	// associate dom node with element
	svgAttr(gfx, ELEMENT_TYPE, element.type);

	if (secondaryGfx) {
		svgAttr(secondaryGfx, ELEMENT_TYPE, element.type);
	}
};

Thank you.

Have you discovered Modeling#setColor yet?

At first, when I was trying to archive what I want, I was testing all options shown on the project colors on bpmn-js-examples. I couldn’t make the option 2 Modeling#setColor work on both the Modeler and the Viewer, it worked only on the Modeler. I also tried to import modeling to my Viewer bundle but it didn’t worked, showing lots of errors (I don’t know if I did something wrong).

As I wanted the same solution for both the Viewer and the Modeler I decided to go with something like the option 3, that is working with CSS the way I showed here.

I appreciate the time you spent trying to help! Thank you!

The point of the viewer is that it’s not a modeler, therefore you cannot change the imported diagram in the viewer hence you can’t change an element’s color.

One solution to this is using the low-level APIs that are being used when changing an element’s color. Here’s an example: https://github.com/bpmn-io/bpmn-js-token-simulation/blob/master/lib/features/preserve-element-colors/PreserveElementColors.js#L52