Is there any way to know at what position the user right clicks on a link? In our application I need to add one or two adornments on a link based on where they click on the link, either to the left of link’s center or right of it. If that is possible would there be a way to add the adornment to that location? Thanks.
I hope this does something like what you are looking for:
myDiagram.linkTemplate =
$(go.Link,
{
routing: go.Link.Orthogonal, // also works when Normal (not Orthogonal)
click: function(e, link) {
var mousePoint = e.documentPoint;
var segment = link.findClosestSegment(mousePoint);
var startPoint = link.points.elt(segment);
var endPoint = link.points.elt(segment + 1);
var linePoint = new go.Point().projectOntoLineSegmentPoint(startPoint, endPoint);
var fraction = 0; // assume segment is linear
if (Math.abs(startPoint.x-endPoint.x) < Math.abs(startPoint.y-endPoint.y)) {
fraction = (mousePoint.y - startPoint.y) / (endPoint.y - startPoint.y);
} else {
fraction = (mousePoint.x - startPoint.x) / (endPoint.x - startPoint.x);
}
e.diagram.commit(function(diag) {
var ad = $(go.Adornment, "Link");
var shape = $(go.Shape, "Circle", { width: 8, height: 8 });
ad.add(shape);
ad.adornedObject = link;
shape.segmentIndex = segment;
shape.segmentFraction = fraction;
if (!link.RightAdornment) { // check last Adornment added
shape.segmentOffset = new go.Point(0, 8);
shape.fill = "red";
link.addAdornment("Right", ad);
} else {
shape.segmentOffset = new go.Point(0, -8);
shape.fill = "green";
link.addAdornment("Left", ad);
}
link.RightAdornment = !link.RightAdornment;
}, null);
}
},
$(go.Shape),
$(go.Shape, { toArrow: "OpenTriangle" })
);
Thanks Walter. This is a good start. I have to do this with the right click after user selects an option from the context menu. A quick check on that event I think this will work as the event in the command call back still has the click point. Also we are still using 1.7.11 so there is no commit. I am assuming I’ll have to use start transaction, end transaction instead?
Yes. But we aren’t really supporting 1.7 any more. Upgrading to 1.8 should be very easy.
Yes, we are aware of this and will be upgrading to the latest GoJs once product is released. I have one more question. Your solution works perfectly, however I am trying to figure out how to bind some of the adornment child objects properties to the link property isSelected. This is the code I am using now to add the adornment. Of course this would work if this was an static link template. I assigned a unique name to each link and using the link.name in the ofObject(). This don’t work so I am guessing I am not completely understanding the propose of ofObject(string).
const mousePoint = event.documentPoint;
const segment = link.findClosestSegment(mousePoint);
const startPoint = link.points.elt(segment);
const endPoint = link.points.elt(segment + 1);
const linePoint = new go.Point().projectOntoLineSegmentPoint(startPoint, endPoint);
let fraction = 0; // assume segment is linear
if (Math.abs(startPoint.x - endPoint.x) < Math.abs(startPoint.y - endPoint.y)) {
fraction = (mousePoint.y - startPoint.y) / (endPoint.y - startPoint.y);
} else {
fraction = (mousePoint.x - startPoint.x) / (endPoint.x - startPoint.x);
}
const ad = $(go.Adornment, 'Link',
$(go.Panel, 'Auto', {segmentIndex: segment, segmentFraction: fraction },
$(go.Shape, 'RoundedRectangle', { width: 20, height: 25, fill: 'white' },
new go.Binding('stroke', 'isSelected', function(h) { return h ? 'dodgerblue' : '#c0c0c0'; }).ofObject(link.name),
new go.Binding('strokeWidth', 'isSelected', function(h) { return h ? 3 : 2; }).ofObject(link.name)
),
$(go.TextBlock,
{ 'text': '\ue943', font: '14px pbi-icon-mini, pbi-icon-mini' },
new go.Binding('stroke', 'isSelected', function(h) { return h ? 'dodgerblue' : '#c0c0c0'; }).ofObject(link.name)
)
)
);
ad.adornedObject = link;
if (!link['RightAdornment']) { // check last Adornment added
link.addAdornment('Right', ad);
} else {
link.addAdornment('Left', ad);
}
link['RightAdornment'] = !link['RightAdornment'];
One normally does not give any Part a GraphObject.name, and all of those instances copied from a template would have the same name anyway.
Binding.ofObject with no arguments (or an empty string argument) will return the Part itself. However Adornments are never selected, so their Part.isSelected value will always be false. Instead you want the Binding source to be “adornedPart”, and the conversion function can return whether it isSelected.
new go.Binding("stroke", "adornedPart", function(p) { return p.isSelected; }).ofObject()
Fantastic, that worked. Thanks so much.