Connect 2 elements jointjs - jointjs

I'm a newbie in jointjs. Today I have a small example as below:
I have a start Activity
var startEndActivity = function (x, y, name, fillColor, textColor, size) {
fillColor = fillColor || '#007FBE';
textColor = textColor || "#000";
size = size || { width: 100, height: 40 };
var rect = new joint.shapes.basic.Rect({
position: { x: x, y: y },
size: size,
attrs: {
rect: { fill: fillColor, rx: 5, ry: 5, 'stroke-width': 1, stroke: '#002F5D' },
text: {
text: name, fill: textColor,
'font-size': 14, 'font-family': 'sans-serif'
}
}
});
graph.addCell(rect);
return rect;}
I have a condition Activity
var activityDecision = function (x, y, name, fillColor, textColor, size{
fillColor = fillColor || '#BF664C';
textColor = textColor || "#080808";
size = size || { width: 200, height: 60 };
var node = new joint.shapes.basic.Rhombus({
position: { x: x, y: y },
size: size,
});
node.attr({
rect: { fill: fillColor, 'stroke-width': 1, stroke: 'white' },
text: {
text: name, fill: textColor,
}
});
graph.addCell(node);
return node;}
I want to click on start activity and I can draw a arrow to connect between 2 elements. Thank you so much

The most common approach that I know of is to use ports on your elements. This link should get you started on that route:
WORKING WITH PORTS
If you prefer to have the entire element behave as a port you need to look into the "magnetic" attribute. This link should help you get started researching what you need (especially the first answer):
How to interactively create links in JointJS

I found solution for this. Thank you so much. Just add more attribute like this
el.attr('rect/magnet', true).attr('text/pointer-events', 'none');

function create(type) {
var link = new joint.dia.Link({
source: { x: 10, y: 20 },
target: { x: 350, y: 20 },
attrs: {}
});
link.prop({...});
link.addTo(graph)
}
//init connection:
new joint.dia.Link({
source: { id: 'source-id' },
target: { id: 'target-id', port: 'port_id'}
});

In order to connect two element you have to work with Ports (documentation):
My best advice for you is to learn how to implement ports by looking in the JointJS source code, as a reference look for object: joint.shapes.devs.Model (live demo + source code inside)
something like this:
var myRect = joint.shapes.devs.Model.extend({
portMarkup: '<circle class="port-body myCustomClass"/>',
defaults: _.defaultsDeep({
type: 'myRect',
}, joint.shapes.basic.Generic.prototype.defaults),
});
and inside of startEndActivity function change the var rect to:
var startRect = new myRect({
position: { x: x, y: y },
size: size,
attrs: {
rect: { fill: fillColor, rx: 5, ry: 5, 'stroke-width': 1, stroke: '#002F5D' },
text: {
text: name, fill: textColor,
'font-size': 14, 'font-family': 'sans-serif'
}
},
ports: {
groups: {
'out': {
position: {
name: 'right'
},
attrs: {
'.port-label': {
fill: '#000'
},
'.port-body': {
fill: '#fff',
stroke: '#000',
r: 10,
magnet: true
}
},
label: {
position: {
name: 'right',
args: {
y: 10
}
}
}
}
}
});
do the same for the second element.

Related

How to make jointJs rectangle text responsive so that the text remains inside a rectangle?

I am creating a rectangle and writing a text inside it, but the text comes out of the rectangle:
Is there any way to keep the text within the rectangle in jointJs?
Here is my code:
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({ el: $('#paper'), width: 650, height: 250, gridSize: 1, model: graph });
var r1 = new joint.shapes.basic.Rect({
position: { x: 20, y: 20 },
size: { width: 200, height: 200 },
attrs: { rect: { fill: '#E74C3C' }, text: { text: 'this text is coming out from rectangle' ,
fontSize: 14,
fill: '#2b7aff'} }
});
graph.addCells([r1]);
Actually i found the answer of my question from jointJs documentation
https://resources.jointjs.com/docs/jointjs/v2.0/joint.html#util.breakText
but there is a problem they(jointjs) described only two parameters
as
joint.util.breakText('this is quite a long text', { width: 50 })
// 'this is\nquite a\nlong\ntext'
but actually there is a third parameter "styles" that is also required
so actual solution is
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({ el: $('#paper'), width: 650, height: 250, gridSize: 1, model: graph });
var text = joint.util.breakText('This is very very very very very very very very very very very very very very very very very very very very very very long text', { width: 20, height:20}, {lineHeight: 1.2});
var r1 = new joint.shapes.basic.Rect({
position: { x: 70, y: 30 },
size: { width: 100, height: 80 },
attrs: { rect: { fill: '#F1C40F' }, text: { text: text } }
});
r1.embed(r1);
graph.addCells([r1]);

New on JOINT JS

When cloning Objects I know how to change attributes for example>
Clone Object 1 2 times var m5 = m1.clone().translate(300, 0).attr('rect/fill', '#F69F43').attr('.label/text', 'Model 2').addTo(graph);
here changing name to attr label/text
but having this element:
var m1 = new joint.shapes.devs.Model({
position: { x: 300, y: 50 },
size: { width: 120, height: 150 },
inPorts: ['in1','in2','in3','in4'],
outPorts: ['out'],
attrs: { '.label': { text: 'Model1', 'ref-x': .4, 'ref-y': .2 }, rect: { fill: '#2ECC71' },
'.inPorts circle': { fill: '#16A085', magnet: 'passive', type: 'input' },
'.outPorts circle': { fill: '#E74C3C', type: 'output' },
'.name': { name: 'Bloque1' } } }).addTo(graph);
How to clone changing .inPorts Circle fill ???
Thanks
var m5 = m1.clone().attr('.inPorts circle/fill', 'red').addTo(graph); changes color of each input ports to red. You can change color of particular port with m5.attr('.inPorts>.port3>circle/fill' ,'green')

JointjS: How to get attributes of a given element?

I have an element defined as this:
var m1 = new joint.shapes.devs.Model({
position: { x: 100, y: 50 },
size: { width: 190, height: 50 },
inPorts: ['in'],
outPorts: ['out'],
attrs: {
'.label': { text: 'Model','ref-x': .4, 'ref-y': .25 ,fill: '#fefefe',
'font-size': 14,
'font-weight': 'bold',
'font-variant': 'small-caps' },
rect: { fill: '#fefefe'},
'.inPorts circle': { r:5 ,fill: '#16A085' ,magnet: 'passive', type: 'input'},
'.outPorts circle': { r:5, fill: '#E74C3C',magnet: 'passive',type: 'output' },
}
THe question is how can I get the '.label' attribute?
E.g, I need to get the text "Model", what should I do?
If I want to get the 'fill' attr of 'rect' , I can simply use m1.get('attrs').rect.fill.
But I don't know HOW TO GET the '.label' attr.
Use the attr() method for both setting attributes and getting them back:
m1.attr('.label/text') // 'Model'
m1.attr('.label/text', 'New Model')
m1.attr('.label/text') // 'New Model'
'/' is a path separator into the nested attrs object.
var rootnode = new joint.shapes.basic.Circle({
position: { x: 20, y: 220 },
size: { width: 60, height: 30 },
attrs: {
text: { text: 'parent' },
circle: { fill: 'yellow', hasChildren:false }
},
name: 'parent'
});
graph.addCell(rootnode);

JointJs Top Bottom Ports

I'm trying to use JointJS with ports feature:
(...)
var model = joint.shapes.devs.Model({
size: { width: width, height: height },
label: node.label,
inPorts: node.inputPorts,
outPorts: node.outputPorts,
attrs: {
'.label': { text: node.label, 'ref-x': .4, 'ref-y': .2 },
rect: { fill: '#2ECC71' },
'.inPorts circle': { fill: '#16A085' },
'.outPorts circle': { fill: '#E74C3C' }
}
(...)
But input ports appears on the left and output ports on the right.
I want input ports on the top and output on the bottom.
Which is the best way to change the port position to Top-Bottom using joint.shapes.devs.Model ?
Thanks in advance.
The positions of ports are calculated in devs.Model.prototype.getPortAttrs. What you can do is just swap x and y port coordinates like in the example below.
joint.shapes.devs.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
markup: '<g class="rotatable"><g class="scalable"><rect class="body"/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port port<%= id %>"><circle class="port-body"/><text class="port-label"/></g>',
defaults: joint.util.deepSupplement({
type: 'devs.Model',
size: { width: 1, height: 1 },
inPorts: [],
outPorts: [],
attrs: {
'.': { magnet: false },
'.body': {
width: 150, height: 250,
stroke: 'black'
},
'.port-body': {
r: 10,
magnet: true,
stroke: 'black'
},
text: {
fill: 'black',
'pointer-events': 'none'
},
'.label': { text: 'Model', 'ref-x': 10, 'ref-y': .2, 'ref': '.body' },
// CHANGED: find better positions for port labels
'.inPorts .port-label': { dy:-30, x: 4 },
'.outPorts .port-label':{ dy: 15, x: 4 }
//
}
}, joint.shapes.basic.Generic.prototype.defaults),
getPortAttrs: function(portName, index, total, selector, type) {
var attrs = {};
var portClass = 'port' + index;
var portSelector = selector + '>.' + portClass;
var portLabelSelector = portSelector + '>.port-label';
var portBodySelector = portSelector + '>.port-body';
attrs[portLabelSelector] = { text: portName };
attrs[portBodySelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
// CHANGED: swap x and y ports coordinates ('ref-y' => 'ref-x')
attrs[portSelector] = { ref: '.body', 'ref-x': (index + 0.5) * (1 / total) };
// ('ref-dx' => 'ref-dy')
if (selector === '.outPorts') { attrs[portSelector]['ref-dy'] = 0; }
//
return attrs;
}
}));
JS Fiddle: http://jsfiddle.net/kumilingus/L2f73cbf/
Update:
Here is an example how to achieve the same with JointJS v1.0.1+.
There is no need for extending the class with PortsModelInterface anymore. The ports API is now implemented by joint.dia.Element i.e. arbitrary element can be enriched with ports easily.
var shape = new joint.shapes.devs.Model({
inPorts: ['in1', 'in2'],
outPorts: ['out1', 'out2'],
ports: {
groups: {
'in': { position: 'top'},
'out': { position: 'bottom' }
}
}
});
JSFiddle: http://jsfiddle.net/kumilingus/trk63agg/
For more information please see the docs:
ports API
port layouts
Just change position name in your joint.shapes.devs.Model creation as follow:
new joint.shapes.devs.Model({
position: { x: x, y: y },
size: { width: 90, height: 90 },
inPorts: ['in1'],
outPorts:['out1'],
attrs: {
rect: { fill: '#2ECC71' },
'.inPorts circle': {r:10, fill: '#16A085' },
'.outPorts circle': { fill: '#E74C3C' }
},
ports: {
groups: {
'in': {
position: {
name: 'top'
},
attrs: {
'.port-body': {
r: 1
}
}
},
'out': {
position: {
name: 'bottom'
},
attrs: {
'.port-body': {
r: 1
}
}
}
}
}
});
Consider the position name changed to top and bottom

How to mark discrete points on a time series graph using D3 / Rickshaw?

I'm using Rickshaw to create a live-updating time series graph.
Here is the demo: http://abhshkdz.github.io/icuvisualanalytics/prototypes/rickshaw.html
The data is in csv format (time,value), and this is the core javascript for the visualization:
var count = 0, index=0;
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = window.innerWidth - margin.right - margin.left - 100,
height = window.innerHeight - margin.top - margin.bottom - 100;
var graph = new Rickshaw.Graph( {
element: document.querySelector("#chart"),
width: width,
height: height,
renderer: 'line',
min: -300,
max: 500,
preserve: true,
series: new Rickshaw.Series.FixedDuration(
[
{
name: 'ECG',
color: palette.color()
}
],
undefined,
{
timeInterval: 12.5,
maxDataPoints: 400,
timeBase: data[index][count].x
})
})
var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
var y_axis = new Rickshaw.Graph.Axis.Y( {
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis')
} );
var hoverDetail = new Rickshaw.Graph.HoverDetail( {
graph: graph
} );
graph.render();
setInterval(function () {
if (count == 2397) {
count = 0;
index++;
}
var d = {'ECG': data[index][count+=3].y};
graph.series.addData(d);
graph.render();
}, 12.5);
Now there is another set of data which is generated by an algorithm. That data is also in csv format (time,value). It basically finds the peaks of this plot. Using that data, I want to mark those points on this visualization itself.
As far as I looked, Rickshaw does not natively support multiple series using different renderers (either both have to be line or both scatter plots etc.).
So how should I go about this?
The multi renderer feature was added about a month ago. This example shows how to combine several renderers in one chart. The relevant code of the example:
var graph = new Rickshaw.Graph( {
element: document.getElementById("chart"),
renderer: 'multi',
width: 900,
height: 500,
dotSize: 2,
series: [
{
name: 'temperature',
data: seriesData.shift(),
color: 'rgba(255, 0, 0, 0.4)',
renderer: 'stack'
}, {
name: 'heat index',
data: seriesData.shift(),
color: 'rgba(255, 127, 0, 0.4)',
renderer: 'stack'
}, {
name: 'dewpoint',
data: seriesData.shift(),
color: 'rgba(127, 0, 0, 0.3)',
renderer: 'scatterplot'
}, {
name: 'pop',
data: seriesData.shift().map(function(d) { return { x: d.x, y: d.y / 4 } }),
color: 'rgba(0, 0, 127, 0.4)',
renderer: 'bar'
}, {
name: 'humidity',
data: seriesData.shift().map(function(d) { return { x: d.x, y: d.y * 1.5 } }),
renderer: 'line',
color: 'rgba(0, 0, 127, 0.25)'
}
]
});

Resources