Custom Component Shapes
Fully customize appearance of components in diagrams.
Last updated
Fully customize appearance of components in diagrams.
Last updated
Shape registration in the Appmixer SDK:
var appmixer = new Appmixer({
componentShapes: {
action: myCustomComponentShape,
trigger: myCustomComponentShape,
myUniqueShape: myCustomComponentShape
},
});
Use "action" and "trigger" keys to override defaults. You can define a custom shape for any component in the system, shape reference in a component manifest looks like this:
{
shape: "myUniqueShape"
}
Built-in shapes are action
, trigger
, actionVertical
and triggerVertical
.
Key
Description
options.updateCallback
An optional method called before the component is updated. Accepts element
argument.
attributes
states
Definition for particular states of the component. The object structure is the same as the current scope (except for the "states" entry).
@active
- the component is being modified
@invalid
- the component configuration is invalid
@referenced
- the component is highlighted
@unchecked
- the component is selected
@checked
- the component is deselected
@running
- the flow is in a running state
ports.attributes
ports.states
Definition for particular states of individual ports.
The object structure is the same as the current scope (except for the "states" entry).
@connected
- the port is connected
link.attributes
Dynamic properties of the component, such as label and icon, are mapped to optional selectors in the markup.
Selector
tagName
Description
label
text
Contains a label of the component.
icon
image
Contains an icon of the component.
element-halo-copy-tooltip
title
"Copy" button tooltip.
element-halo-cut-tooltip
title
"Cut" button tooltip.
element-halo-remove-tooltip
title
"Remove" button tooltip.
Key
Value
Description
event
"remove"
The entry acts as a remove button.
var customComponentShape = {
attributes: {
size: {
height: 72,
width: 72
},
markup: [
{
tagName: 'rect',
selector: 'body'
},
{
tagName: 'text',
selector: 'label'
},
{
tagName: 'image',
selector: 'icon'
},
{
tagName: 'g',
selector: 'element-halo',
children: [
{
tagName: 'image',
selector: 'element-halo-copy',
children: [
{
tagName: 'title',
selector: 'element-halo-copy-tooltip'
}
]
},
{
tagName: 'image',
selector: 'element-halo-cut',
children: [
{
tagName: 'title',
selector: 'element-halo-cut-tooltip'
}
]
},
{
tagName: 'image',
selector: 'element-halo-remove',
children: [
{
tagName: 'title',
selector: 'element-halo-remove-tooltip'
}
]
}
]
}
],
attrs: {
body: {
fill: 'white',
stroke: 'black',
strokeWidth: 1,
refWidth: 1,
refHeight: 1
},
icon: {
ref: 'body',
refX: 0.5,
refY: 0.5,
xAlignment: 'middle',
yAlignment: 'middle',
width: 24,
height: 24,
clipPath: 'url(#icon-clip)'
},
label: {
ref: 'body',
textAnchor: 'middle',
refX: 0.5,
refY: '100%',
refY2: 12,
xAlignment: 'middle',
fontFamily: 'sans-serif',
fontWeight: 'bold',
fontSize: 14,
fill: 'black'
},
'element-halo': {
display: 'none',
ref: 'body',
width: 68,
height: 44,
refX: 0.5,
refY: 0,
refY2: -24,
xAlignment: 'middle'
},
'element-halo-copy': {
event: 'element-copy',
x: 0,
y: 0,
width: 20,
height: 20,
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii01IC0yIDI0IDI0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIiBjbGFzcz0iaWNvbl9faWNvbiI+PHBhdGggZD0iTTUgMnYyaDRWMkg1em02IDBoMWEyIDIgMCAwIDEgMiAydjE0YTIgMiAwIDAgMS0yIDJIMmEyIDIgMCAwIDEtMi0yVjRhMiAyIDAgMCAxIDItMmgxYTIgMiAwIDAgMSAyLTJoNGEyIDIgMCAwIDEgMiAyem0wIDJhMiAyIDAgMCAxLTIgMkg1YTIgMiAwIDAgMS0yLTJIMnYxNGgxMFY0aC0xek00IDhoNmExIDEgMCAwIDEgMCAySDRhMSAxIDAgMSAxIDAtMnptMCA1aDZhMSAxIDAgMCAxIDAgMkg0YTEgMSAwIDAgMSAwLTJ6Ij48L3BhdGg+PC9zdmc+',
cursor: 'pointer'
},
'element-halo-cut': {
event: 'element-cut',
x: 24,
y: 0,
width: 20,
height: 20,
cursor: 'pointer',
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0yLjUgLTIuNSAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiIgY2xhc3M9Imljb25fX2ljb24iPjxwYXRoIGQ9Ik05LjEwNyAxMC41NTRMNy4zNjMgMTIuNjNhMy45OTMgMy45OTMgMCAwIDEtLjE5MiA0Ljg5IDQuMDA0IDQuMDA0IDAgMCAxLTUuNjM1LjQ5MiAzLjk5MSAzLjk5MSAwIDAgMS0uNDkzLTUuNjI4IDQuMDA1IDQuMDA1IDAgMCAxIDQuNzg4LTEuMDM4TDcuODAxIDkgMi40MTMgMi41ODdhLjk5OC45OTggMCAwIDEgLjEyMy0xLjQwNyAxIDEgMCAwIDEgMS40MDkuMTIzbDUuMTYyIDYuMTQ0IDUuMTYxLTYuMTQ0YTEgMSAwIDAgMSAxLjQxLS4xMjMuOTk4Ljk5OCAwIDAgMSAuMTIzIDEuNDA3TDEwLjQxMiA5bDEuOTcgMi4zNDVhNC4wMDUgNC4wMDUgMCAwIDEgNC43ODggMS4wMzggMy45OTEgMy45OTEgMCAwIDEtLjQ5MyA1LjYyOCA0LjAwNCA0LjAwNCAwIDAgMS01LjYzNS0uNDkyIDMuOTkzIDMuOTkzIDAgMCAxLS4xOTItNC44OWwtMS43NDMtMi4wNzV6bS02LjI4NSA1LjkyN2EyIDIgMCAwIDAgMi41NzEtMy4wNiAyLjAwMiAyLjAwMiAwIDAgMC0yLjgxOC4yNDZjLS43MS44NDUtLjYgMi4xMDUuMjQ3IDIuODE0em0xMi41NyAwYTEuOTk2IDEuOTk2IDAgMCAwIC4yNDYtMi44MTQgMi4wMDIgMi4wMDIgMCAwIDAtMi44MTctLjI0NiAxLjk5NiAxLjk5NiAwIDAgMC0uMjQ3IDIuODE0Yy43MS44NDUgMS45NzIuOTU1IDIuODE4LjI0NnoiPjwvcGF0aD48L3N2Zz4'
},
'element-halo-remove': {
event: 'element-remove',
x: 48,
y: 0,
width: 20,
height: 20,
cursor: 'pointer',
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0zIC0yIDI0IDI0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIiBjbGFzcz0iaWNvbl9faWNvbiI+PHBhdGggZD0iTTYgMlYxYTEgMSAwIDAgMSAxLTFoNGExIDEgMCAwIDEgMSAxdjFoNGEyIDIgMCAwIDEgMiAydjFhMiAyIDAgMCAxLTIgMmgtLjEzM2wtLjY4IDEwLjJhMyAzIDAgMCAxLTIuOTkzIDIuOEg1LjgyNmEzIDMgMCAwIDEtMi45OTMtMi43OTZMMi4xMzcgN0gyYTIgMiAwIDAgMS0yLTJWNGEyIDIgMCAwIDEgMi0yaDR6bTEwIDJIMnYxaDE0VjR6TTQuMTQxIDdsLjY4NyAxMC4wNjhhMSAxIDAgMCAwIC45OTguOTMyaDYuMzY4YTEgMSAwIDAgMCAuOTk4LS45MzRMMTMuODYyIDdoLTkuNzJ6TTcgOGExIDEgMCAwIDEgMSAxdjdhMSAxIDAgMCAxLTIgMFY5YTEgMSAwIDAgMSAxLTF6bTQgMGExIDEgMCAwIDEgMSAxdjdhMSAxIDAgMCAxLTIgMFY5YTEgMSAwIDAgMSAxLTF6Ij48L3BhdGg+PC9zdmc+'
},
'element-halo-copy-tooltip': {
fontFamily: 'nunitosans-regular, Helvetica, Arial, sans-serif',
fontSize: 13
},
'element-halo-cut-tooltip': {
fontFamily: 'nunitosans-regular, Helvetica, Arial, sans-serif',
fontSize: 13
},
'element-halo-remove-tooltip': {
fontFamily: 'nunitosans-regular, Helvetica, Arial, sans-serif',
fontSize: 13
}
}
},
ports: {
attributes: {
in: {
position: {
name: 'left'
},
attrs: {
'.port-body': {
r: 5,
strokeWidth: 2,
stroke: 'black',
fill: 'white'
},
'connection-port-label': {
fill: 'black',
fontFamily: 'sans-serif',
fontSize: 12
}
},
label: {
position: {
name: 'left',
args: {
x: -8,
y: 14
}
},
markup: [
{
tagName: 'text',
selector: 'connection-port-label'
}
]
}
},
out: {
position: {
name: 'right'
},
attrs: {
'.port-body': {
r: 5,
strokeWidth: 2,
stroke: 'black',
fill: 'white'
},
'connection-port-label': {
fill: 'black',
fontFamily: 'sans-serif',
fontSize: 12
}
},
label: {
position: {
name: 'right',
args: {
x: 8,
y: 14
}
},
markup: [
{
tagName: 'text',
selector: 'connection-port-label'
}
]
}
}
}
},
link: {
attributes: {
router: {
name: 'metro'
},
connector: {
name: 'rounded',
args: {
radius: 8
}
},
markup: [
{
tagName: 'path',
selector: 'wrapper'
},
{
tagName: 'path',
selector: 'line'
}
],
labels: [
{
z: 100,
markup: [
{
tagName: 'image',
selector: 'link-halo'
}
],
attrs: {
'link-halo': {
display: 'none',
event: 'link-remove',
yAlignment: 'middle',
xAlignment: 'middle',
width: 20,
height: 20,
cursor: 'pointer',
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTAzMDAgLTE3MDYpIj48cGF0aCBkPSJNMCwwSDI0VjI0SDBaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDMwMCAxNzA2KSIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xMiwyQTEwLDEwLDAsMSwwLDIyLDEyLDkuOTkxLDkuOTkxLDAsMCwwLDEyLDJaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDMwMCAxNzA2KSIgZmlsbD0iIzE1MjNmZiIvPjxwYXRoIGQ9Ik0xNywxNS41OSwxNS41OSwxNywxMiwxMy40MSw4LjQxLDE3LDcsMTUuNTksMTAuNTksMTIsNyw4LjQxLDguNDEsNywxMiwxMC41OSwxNS41OSw3LDE3LDguNDEsMTMuNDEsMTJaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDMwMCAxNzA2KSIgZmlsbD0iI2ZmZiIvPjwvZz48L3N2Zz4='
}
},
position: {
distance: 0.5,
args: {
keepGradient: true
}
}
}
],
attrs: {
line: {
pointerEvents: 'none',
connection: true,
stroke: 'black',
strokeWidth: 1.5,
strokeDasharray: '4 4',
fill: 'transparent'
},
wrapper: {
connection: true,
cursor: 'pointer',
stroke: 'transparent',
strokeWidth: 24,
fill: 'transparent'
}
}
}
},
states: {
'@active': {
attributes: {
attrs: {
body: {
stroke: 'blue',
strokeWidth: 3
},
label: {
fill: 'black'
},
'element-halo': {
display: 'initial'
}
}
},
ports: {
attributes: {
in: {
attrs: {
'.port-body': {
stroke: 'blue'
}
}
},
out: {
attrs: {
'.port-body': {
stroke: 'blue'
}
}
}
}
},
link: {
attributes: {
attrs: {
line: {
strokeDasharray: 0,
stroke: 'blue'
}
},
labels: [
{
attrs: {
'link-halo': {
display: 'initial',
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTAzMDAgLTE3MDYpIj48cGF0aCBkPSJNMCwwSDI0VjI0SDBaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDMwMCAxNzA2KSIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xMiwyQTEwLDEwLDAsMSwwLDIyLDEyLDkuOTkxLDkuOTkxLDAsMCwwLDEyLDJaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDMwMCAxNzA2KSIgZmlsbD0iIzE1MjNmZiIvPjxwYXRoIGQ9Ik0xNywxNS41OSwxNS41OSwxNywxMiwxMy40MSw4LjQxLDE3LDcsMTUuNTksMTAuNTksMTIsNyw4LjQxLDguNDEsNywxMiwxMC41OSwxNS41OSw3LDE3LDguNDEsMTMuNDEsMTJaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDMwMCAxNzA2KSIgZmlsbD0iI2ZmZiIvPjwvZz48L3N2Zz4='
}
}
}
]
}
}
},
'@invalid': {
attributes: {
attrs: {
body: {
stroke: 'red',
strokeWidth: 2
},
label: {
fill: 'red'
}
}
},
ports: {
attributes: {
in: {
attrs: {
'.port-body': {
stroke: 'red'
}
}
},
out: {
attrs: {
'.port-body': {
stroke: 'red'
}
}
}
}
}
}
}
};
var customSelectionShape = {
attributes: {
markup: [
{
tagName: 'rect',
selector: 'body'
},
{
tagName: 'g',
selector: 'halo',
children: [
{
tagName: 'image',
selector: 'halo-copy'
},
{
tagName: 'image',
selector: 'halo-cut'
},
{
tagName: 'image',
selector: 'halo-remove'
}
]
}
],
attrs: {
body: {
pointerEvents: 'none',
fill: 'rgba(0, 0, 0, 0.1)',
stroke: 'black',
strokeWidth: 1
},
halo: {
ref: 'body',
width: 68,
height: 44,
refX: 0.5,
refY: 0,
refY2: -24,
xAlignment: 'middle'
},
'halo-copy': {
event: 'element-copy',
x: 0,
y: 0,
width: 20,
height: 20,
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii01IC0yIDI0IDI0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIiBjbGFzcz0iaWNvbl9faWNvbiI+PHBhdGggZD0iTTUgMnYyaDRWMkg1em02IDBoMWEyIDIgMCAwIDEgMiAydjE0YTIgMiAwIDAgMS0yIDJIMmEyIDIgMCAwIDEtMi0yVjRhMiAyIDAgMCAxIDItMmgxYTIgMiAwIDAgMSAyLTJoNGEyIDIgMCAwIDEgMiAyem0wIDJhMiAyIDAgMCAxLTIgMkg1YTIgMiAwIDAgMS0yLTJIMnYxNGgxMFY0aC0xek00IDhoNmExIDEgMCAwIDEgMCAySDRhMSAxIDAgMSAxIDAtMnptMCA1aDZhMSAxIDAgMCAxIDAgMkg0YTEgMSAwIDAgMSAwLTJ6Ij48L3BhdGg+PC9zdmc+',
cursor: 'pointer'
},
'halo-cut': {
event: 'element-cut',
x: 24,
y: 0,
width: 20,
height: 20,
cursor: 'pointer',
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0yLjUgLTIuNSAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiIgY2xhc3M9Imljb25fX2ljb24iPjxwYXRoIGQ9Ik05LjEwNyAxMC41NTRMNy4zNjMgMTIuNjNhMy45OTMgMy45OTMgMCAwIDEtLjE5MiA0Ljg5IDQuMDA0IDQuMDA0IDAgMCAxLTUuNjM1LjQ5MiAzLjk5MSAzLjk5MSAwIDAgMS0uNDkzLTUuNjI4IDQuMDA1IDQuMDA1IDAgMCAxIDQuNzg4LTEuMDM4TDcuODAxIDkgMi40MTMgMi41ODdhLjk5OC45OTggMCAwIDEgLjEyMy0xLjQwNyAxIDEgMCAwIDEgMS40MDkuMTIzbDUuMTYyIDYuMTQ0IDUuMTYxLTYuMTQ0YTEgMSAwIDAgMSAxLjQxLS4xMjMuOTk4Ljk5OCAwIDAgMSAuMTIzIDEuNDA3TDEwLjQxMiA5bDEuOTcgMi4zNDVhNC4wMDUgNC4wMDUgMCAwIDEgNC43ODggMS4wMzggMy45OTEgMy45OTEgMCAwIDEtLjQ5MyA1LjYyOCA0LjAwNCA0LjAwNCAwIDAgMS01LjYzNS0uNDkyIDMuOTkzIDMuOTkzIDAgMCAxLS4xOTItNC44OWwtMS43NDMtMi4wNzV6bS02LjI4NSA1LjkyN2EyIDIgMCAwIDAgMi41NzEtMy4wNiAyLjAwMiAyLjAwMiAwIDAgMC0yLjgxOC4yNDZjLS43MS44NDUtLjYgMi4xMDUuMjQ3IDIuODE0em0xMi41NyAwYTEuOTk2IDEuOTk2IDAgMCAwIC4yNDYtMi44MTQgMi4wMDIgMi4wMDIgMCAwIDAtMi44MTctLjI0NiAxLjk5NiAxLjk5NiAwIDAgMC0uMjQ3IDIuODE0Yy43MS44NDUgMS45NzIuOTU1IDIuODE4LjI0NnoiPjwvcGF0aD48L3N2Zz4'
},
'halo-remove': {
event: 'element-remove',
x: 48,
y: 0,
width: 20,
height: 20,
cursor: 'pointer',
xlinkHref: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0zIC0yIDI0IDI0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaW5ZTWluIiBjbGFzcz0iaWNvbl9faWNvbiI+PHBhdGggZD0iTTYgMlYxYTEgMSAwIDAgMSAxLTFoNGExIDEgMCAwIDEgMSAxdjFoNGEyIDIgMCAwIDEgMiAydjFhMiAyIDAgMCAxLTIgMmgtLjEzM2wtLjY4IDEwLjJhMyAzIDAgMCAxLTIuOTkzIDIuOEg1LjgyNmEzIDMgMCAwIDEtMi45OTMtMi43OTZMMi4xMzcgN0gyYTIgMiAwIDAgMS0yLTJWNGEyIDIgMCAwIDEgMi0yaDR6bTEwIDJIMnYxaDE0VjR6TTQuMTQxIDdsLjY4NyAxMC4wNjhhMSAxIDAgMCAwIC45OTguOTMyaDYuMzY4YTEgMSAwIDAgMCAuOTk4LS45MzRMMTMuODYyIDdoLTkuNzJ6TTcgOGExIDEgMCAwIDEgMSAxdjdhMSAxIDAgMCAxLTIgMFY5YTEgMSAwIDAgMSAxLTF6bTQgMGExIDEgMCAwIDEgMSAxdjdhMSAxIDAgMCAxLTIgMFY5YTEgMSAwIDAgMSAxLTF6Ij48L3BhdGg+PC9zdmc+'
}
}
}
};
new Appmixer({
componentShapes: {
action: customComponentShape,
trigger: customComponentShape,
selection: customSelectionShape
}
});
Element attributes, see:
orts attributes of
Link attributes, see: