In JointJS, links come with a handy responsive tool for removing links (when you hover over the link, an \"x\" appears, and clicking it removes the link). Elements, on the
In my project I define a custom shape - toolElement - that encapsulates this behaviour and then extend this with other custom shapes as required.
Full disclosure: This technique leans heavily on the jointjs code for links - I just adapted it :o)
Here is a jsfiddle showing it working:
http://jsfiddle.net/kj4bqczd/3/
The toolElement is defined like this:
joint.shapes.tm.toolElement = joint.shapes.basic.Generic.extend({
toolMarkup: ['',
' ',
' ',
'Remove this element from the model ',
' ',
' '].join(''),
defaults: joint.util.deepSupplement({
attrs: {
text: { 'font-weight': 400, 'font-size': 'small', fill: 'black', 'text-anchor': 'middle', 'ref-x': .5, 'ref-y': .5, 'y-alignment': 'middle' },
},
}, joint.shapes.basic.Generic.prototype.defaults)
});
You can add more markup if you need other tools as well as the remove button.
The remove behaviour is encapsulated in a custom view:
joint.shapes.tm.ToolElementView = joint.dia.ElementView.extend({
initialize: function() {
joint.dia.ElementView.prototype.initialize.apply(this, arguments);
},
render: function () {
joint.dia.ElementView.prototype.render.apply(this, arguments);
this.renderTools();
this.update();
return this;
},
renderTools: function () {
var toolMarkup = this.model.toolMarkup || this.model.get('toolMarkup');
if (toolMarkup) {
var nodes = V(toolMarkup);
V(this.el).append(nodes);
}
return this;
},
pointerclick: function (evt, x, y) {
this._dx = x;
this._dy = y;
this._action = '';
var className = evt.target.parentNode.getAttribute('class');
switch (className) {
case 'element-tool-remove':
this.model.remove();
return;
break;
default:
}
joint.dia.CellView.prototype.pointerclick.apply(this, arguments);
},
});
You can then extend these to make your custom shapes. In my project, I am doing data flow diagrams and here is the definition of the Process shape:
joint.shapes.tm.Process = joint.shapes.tm.toolElement.extend({
markup: ' ',
defaults: joint.util.deepSupplement({
type: 'tm.Process',
attrs: {
'.element-process': { 'stroke-width': 1, r: 30, stroke: 'black', transform: 'translate(30, 30)' },
text: { ref: '.element-process'}
},
size: { width: 100, height: 100 }
}, joint.shapes.tm.toolElement.prototype.defaults)
});
and view:
joint.shapes.tm.ProcessView = joint.shapes.tm.ToolElementView;
I show and hide the tool markup, depending whether the element is highlighted using CSS. You could do the same when hovering (like the links do) if you like:
.element .element-tools {
display: none;
cursor: pointer
}
.element.highlighted .element-tools {
display: inline;
}
When rendered, it looks like this (note: in my case, I have another button in the tools, not just the remove - that is what the green chevron button is. I removed this from the code samples above to make them simpler):
When the element is not highlighted:

When it is highlighted:

I can then define other shapes really easily by extending toolElement. Here are the data flow diagram shapes for data stores:

and external actors:
