Add Custom Element in Task only by click event

So far I have created a custom icon in the Context Pad as well as a Custom Element/Renderer (based on custom rendering example). Currently the custom element gets rendered in each Task Element and on initial load. I only want the custom element to be displayed after having clicked the custom icon in the Context Pad and only for the corresponding Task Element, not for each Task.
How can I trigger/call the Custom Element only after clicking the custom icon in the context pad, respectively from any function in my app?

image

La classe !
Very nice indeed; how did you do ?

By following this: for custom rendering and for context pad.

Hi @ccius ,

this looks good!

How to you persist the information for your custom tasks at the moment?
You could simply create a model extension which holds the custom information of whether a task is / is not one of your “custom tasks with a red box”: GitHub - bpmn-io/bpmn-js-example-custom-elements: An example of how to support custom elements in bpmn-js while ensuring BPMN 2.0 compatibility.

Based on that extension, you could then either use the defaultRenderer or the customRenderer (by implementing the canRender function: GitHub - bpmn-io/bpmn-js-example-custom-rendering: An example of creating custom rendering for bpmn-js

Hi @maxtru thanks for your suggestions.

import inherits from 'inherits';
import { attr as svgAttr } from 'tiny-svg';
import BpmnRenderer from 'bpmn-js/lib/draw/BpmnRenderer';
import { is } from 'bpmn-js/lib/util/ModelUtil';

export default function CustomRenderer(eventBus, styles, pathMap, canvas) {
  BpmnRenderer.call(this, eventBus, styles, pathMap, canvas, 1400);

  this.canRender = function(element) {
    return is(element, 'bpmn:Task') && element.color;
  };

  this.drawShape = function(parent, shape) {
    var bpmnShape = this.drawBpmnShape(parent, shape);

    svgAttr(bpmnShape, { fill: shape.color });

    return bpmnShape;
  };
}

inherits(CustomRenderer, BpmnRenderer);

CustomRenderer.prototype.drawBpmnShape = BpmnRenderer.prototype.drawShape;

CustomRenderer.$inject = ['eventBus', 'styles', 'pathMap', 'canvas'];

You see in the code snippet the customRenderer file, and I want to call ONLY the drawShape function from a React Component. In my React component I am creating an instance of the CustomRenderer: const custom = new CustomRenderer() so that I can use the drawShape function from anywhere within the component by doing: custom.drawShape(), but the app throws me an error, which is in BaseRenderer.js file. (see screenshot)

I was debugging and the issue comes from BpmnRenderer.call(this, eventBus, styles, pathMap, canvas, 1400) from the CustomRenderer file.

The purpose why I want to first draw the custom renderer from a react component, is because I want to send an icon to drawShape as argument, the icon is chosen from the system.

@nikku @Niklas_Kiefer @philippfromme How can I call only the function drawShape from a React component?
How can I get rid of that error and why the error seems to be because of calling BpmnRenderer?

Firstly, please try to avoid directly mentioning forum users, this won’t get your questions answered quicker.

const custom = new CustomRenderer()

this won’t work as the error reveals. You need to initiate it with an eventBus. Inside our toolkits, we use didi for that so there is actually no need to initiate services on your own. Why not using

const renderer = modeler.get('customRenderer');

This assumes you register this service via additionalModules.

However, I still not understand why you need to call drawShape manually. As you see, there are events flying around making sure elements got rendered with the information they deliver. If you somehow want to execute a rendering, try to use this events via eventBus.

Thanks so much for your quick answer.

As mentioned before, I want the custom renderer to contain an icon which has to be loaded dynamically.
As I am quite new with bpmn-js, I did not think of other solution.

I have the eventBus available.
Would you please give me an example/syntax how to call the drawShape function manually via the event eventBus ?

To be honest it sounds like you’d be better off using overlays for what you’re trying to achieve. The renderer is supposed to render the state of the diagram. What you’re trying to achieve sounds more like rendering some kind of menu. Is that the case?

Thank you for your reply.
Yes, my first approach was with Overlays API, and it works just nice. But, with Overlays I am not able to same the icon in XML, am I?
I need the uploaded icon to be kept persistent.

You can save an overlay’s HTML, too, but I don’t think it makes a lot of sense.

Have you had a look at this example: bpmn-js-examples/custom-elements at master · bpmn-io/bpmn-js-examples · GitHub

Whether you want to save image data or any other data doesn’t make a difference. However, I don’t think that saving image data in a BPMN diagram is a good approach. Instead, save the actual data that an icon is supposed to represent and customize the renderer so it can render an icon representing that data. The only exception would be a scenario where you want to support arbitrary icons that you don’t know in advance. But then I’d wonder what the use case is.