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
.
Dynamic properties of the component, such as label and icon, are mapped to optional selectors in the markup.
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
}
});