Hi
During migration to 3.0 i got s strange error while trying to replace a shape with a custom shape,
I get the following error :
My deafult Shape (RoundedRectangle) in my nodeTemplate has a width of 90.
and the node lokks like this :
But when i replace the RoundedRectangle, with my custom “CustomSquareArrowRight” shape, it crashes. In GOJS 2.3 it didnt crash and looked like that:
The width of the shape is the node templae is set to 90,
but when trying to replace the shape with the custom shape, it grows to 120, and GOJS crashes.
The problem is that the same code was running very good in 2.3 and crashes in 3.0
My node template looks like this
export class PathNodeTemplate extends GoJSAbstractTemplate {
override initTemplate() {
var GO = this.GO;
// let that = this;
this.template =
GO(go.Node, “Spot”,{ width: 150 },
new go.Binding(“visible”, “showPP”, function (showPP, obj) {
if (obj[“diagram”].model.modelData.diagramType != GoJSDiagramComponent.CONST_DIAGRAM_TYPE_DIRECTED_PATH)
return true;
return !obj[“part”].data.isPP || (obj[“part”].data.isPP && showPP);
}).ofModel(),
{
toolTip: this.nodeTooltip(GO),
groupable: true,
// background: “transparent”,
selectionObjectName: “BODY”,
mouseDragEnter: this.mouseDragEnterHandler,
mouseDragLeave: this.mouseDragLeaveHandler,
mouseDrop: null, // implemented by each componenet
shadowOffset: new go.Point(5, 5),
shadowBlur: 25,
shadowColor: “#a0e6d5”,
shadowVisible: false,
},
{
selectionAdornmentTemplate:
GO(go.Adornment, “Auto”,
{
},
GO(go.Shape, "RoundedRectangle",
{
fill: null,
stroke: "transparent",
strokeWidth: 1,
},
),
GO(go.Placeholder)
) // end Adornment
},
new go.Binding("position", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
new go.Binding("key"),
new go.Binding("group"),
new go.Binding("isShadowed", "isSelected").ofObject(),
GO(go.Panel, "Vertical",
// Panel to hold device id in front of RoundedRectangle
GO(go.Panel, "Auto", { margin: new go.Margin(0,0,10,0) },
GO(go.Shape, "RoundedRectangle",
{
fill: "#F8F8F8",
strokeWidth: 0,
}
),
// Vertical Panel to hold deviceid shelf/Rack/CardId right under each other
GO(go.Panel, "Vertical",
// Shelf Id
GO(go.TextBlock,
{
margin: new go.Margin(5,5,0,5),
isMultiline: false, editable: false,
stroke: GO(go.Brush, { color: GoJSAbstractTemplate.CONST_GREY_COLOR }),
font: GoJSAbstractTemplate.CONST_MEDIUM_FONT,
textAlign: "center",
},
new go.Binding("text"),
new go.Binding("visible", "isFullId").ofModel(),
new go.Binding("font")
),
// Shelf Id : rack + shelf no
GO(go.TextBlock,
{
isMultiline: false, editable: false,
stroke: GO(go.Brush, { color: GoJSAbstractTemplate.CONST_GREY_COLOR }),
font: GoJSAbstractTemplate.CONST_MEDIUM_FONT,
textAlign: "center",
},
new go.Binding("text"),
new go.Binding("font")
),
// Card Id
GO(go.TextBlock,
{
margin: new go.Margin(0,5,5,5),
isMultiline: false, editable: false,
stroke: GO(go.Brush, { color: GoJSAbstractTemplate.CONST_GREY_COLOR }),
font: GoJSAbstractTemplate.CONST_MEDIUM_FONT,
textAlign: "center",
},
new go.Binding("text", ""),
new go.Binding("font")
)
)) ,
GO(go.Panel, "Spot", // Panel for holding picture and deleted picture
{
alignment: go.Spot.Center,
cursor: "cell",
},
new go.Binding("alignment", "nodeAlignment"),
GO(go.Shape, "RoundedRectangle",
{
width: 90,
height: 130,
fill: "white",
stroke: "rgb(95,95,95)",
portId: "",
fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides,
name: "BODY",
},
new go.Binding("height", "nodeHeight"),
new go.Binding("fill"),
new go.Binding("stroke"),
new go.Binding("strokeWidth"),
new go.Binding("figure"),
),
GO(go.Shape, "LineH",
{
width: 90,
stroke: "rgb(95,95,95)",
alignment: new go.Spot(0.5,0.24),
},
new go.Binding("visible", "visibleLineH"),
new go.Binding("stroke","strokeLineH"),
),
// Device Type
GO(go.TextBlock,
{
alignment: new go.Spot(0.5,0.13),
textAlign: "center",
editable: false,
stroke: GO(go.Brush, { color: GoJSAbstractTemplate.CONST_DEFAULT_COLOR }),
font: GoJSAbstractTemplate.CONST_SMALL_FONT,
width: 50
},
new go.Binding("text", "deviceType"),
),
// Picture Panel
GO(go.Panel, "Vertical",
{
alignment: new go.Spot(0.5,0.5),
// scale : 0.7,
},
// the node icon
new go.Binding("alignment","picAlignment"),
GO(go.Picture,
new go.Binding("source"),
), // Picture
), // Picture Panel
// Monitor State
GO(go.TextBlock,
{
stroke: GO(go.Brush, { color: GoJSAbstractTemplate.CONST_DEFAULT_COLOR }),
font: GoJSAbstractTemplate.CONST_SMALL_FONT,
alignment: new go.Spot(0.5,0.95),
},
new go.Binding("alignment","monitorAlignment"),
new go.Binding("text", "monitorStatus"),
new go.Binding("stroke", "monitorColor"),
new go.Binding("visible", "monitorStatus", function (s) { return s != null && s != "" }),
)
), // Vertical Panel
GO(go.TextBlock, // Node alarmMessage
{
isMultiline: false, editable: false,
stroke: GO(go.Brush, { color: GoJSAbstractTemplate.CONST_DEFAULT_COLOR }),
font: AbstractLinkTemplate.CONST_MEDIUM_FONT,
name: "nodeAlarmMessage",
//background: "white"
},
new go.Binding("text", "alarmMessage"),
new go.Binding("stroke", "statusColor"),
new go.Binding("visible", "alarmMessage", function (s) { return s != null && s != "" })
)
),
// Port Array for UNconnected ports
new go.Binding("itemArray", "ports"),
{
name: "PortPanel",
itemTemplate:
GO(go.Panel, "Vertical",
new go.Binding("portId"),
new go.Binding("alignment", "spot", go.Spot.parse).makeTwoWay(go.Spot.stringify),
{
// fromLinkable: true, toLinkable: true,
toolTip: this.portTooltip(GO,"fullId",""),
cursor: "pointer",
name: "PortName",
},
GO(go.Panel, // panel to place the textbox (portId) and the port shape (circle) side by side horizontaly
new go.Binding("visible", "isConnected", function (c) { return !c }),
this.createPortName(), // port Name, which also construct the port shape
), // end port Template
this.createPortAlarm(GO) // port Alarm
)
},
)
}
/**
*
*/
nodeTooltip(GO) {
// var GO = this.GO;
var x =
GO(go.Adornment, “Auto”, GoJSAbstractTemplate.CONST_TOOLTIP_BASIC_ATTRIBUTES,
new go.Binding(“visible”, “showTT”).ofModel(),
GO(go.Shape, “RoundedRectangle”, GoJSAbstractTemplate.CONST_TOOLTIP_BACKGROUND_ATTRIBUTES),
GO(go.Panel, “Vertical”, { defaultStretch: go.GraphObject.Horizontal },
GO(go.TextBlock, " נתוני מכשיר", GoJSAbstractTemplate.CONST_TOOLTIP_HEADER_ATTRIBUTES ),
GO(go.TextBlock, “”, GoJSAbstractTemplate.CONST_TOOLTIP_TEXTBOX_ATTRIBUTES,
new go.Binding(“text”, “fullId”, function (txt) { return txt + " :זיהוי מלא" }),
),
GO(go.TextBlock, “”, GoJSAbstractTemplate.CONST_TOOLTIP_TEXTBOX_ATTRIBUTES_RIGHT,
new go.Binding(“text”, “deviceType”, function (txt) { return txt + " :סוג מכשיר"}),
),
GO(go.TextBlock, “”, GoJSAbstractTemplate.CONST_TOOLTIP_TEXTBOX_ATTRIBUTES_RIGHT,
new go.Binding(“text”, “sla”, function (txt) { return txt + " :SLA" }),
),
GO(go.TextBlock, “”, GoJSAbstractTemplate.CONST_TOOLTIP_TEXTBOX_ATTRIBUTES,
new go.Binding(“margin”, “alarmMessage”, function (txt) { return txt != null && txt != “” ? new go.Margin(4, 4, 4, 4) : 0 }),
new go.Binding(“visible”, “alarmMessage”, function (txt) { return txt != null && txt != “”; }),
new go.Binding(“text”, “alarmMessage”, function (txt) { return "אירוע: " + txt }),
),
GO(go.TextBlock, “”, GoJSAbstractTemplate.CONST_TOOLTIP_TEXTBOX_ATTRIBUTES_RIGHT,
new go.Binding(“margin”, “monitorStatus”, function (txt) { return txt != null && txt != “” ? new go.Margin(4, 4, 4, 4) : new go.Margin(0, 0, 0, 0) }),
new go.Binding(“visible”, “monitorStatus”, function (txt) { return txt != null && txt != “”; }),
new go.Binding(“text”, “monitorStatus”, function (txt) { return "סטטוס ניטור: " + txt }),
),
)
); // end of Adornment
return x;
}
/**
*
/
private createPortName() {
// let that = this;
var GO = this.GO;
var x =
GO(go.Panel, “Auto”,
GO(go.TextBlock,
{
font: GoJSAbstractTemplate.CONST_SMALL_FONT,
editable: false,
visible: true,
stroke: “black”,
background: “transparent”,
name: “portNameTextBox”,
},
new go.Binding(“stroke”, “portStatusColor”),
new go.Binding(“text”, “portName”), //.makeTwoWay(),
)
);
return x;
}
/*
*
*/
private createPortAlarm(GO) {
var x =
GO(go.TextBlock, {
font: GoJSAbstractTemplate.CONST_MEDIUM_FONT,
editable: false,
visible: false
},
new go.Binding(“text”, “alarmMessage”),
new go.Binding(“stroke”, “statusColor”),
new go.Binding(“visible”, “alarmMessage”, function (s) { return s != null && s != “”; }),
new go.Binding(“visible”, “isConnected”, function (c) { return !c }),
);
return x;
}
/**
*
*/
override setData(data): Object {
var device = data;
var deviceId = device.deviceId;
var icon = typeof (device.icon) !== “undefined” ? device.icon + “.svg” : device.source;
let lastIndex = icon.lastIndexOf(‘/’);
icon = GoJSAbstractTemplate.CONST_ICON_RELATIVE_PATH + icon.substring(lastIndex + 1);
var nodeData = {
key: device.key,
alarmMessage: null,
isDeleted: false,
source: icon,
deviceId: deviceId,
fullId: deviceId.fullId,
// used by netmap report
name: deviceId.fullId + ' | ' + deviceId.shortId + ' | ' + this.htmlDecode(device.site.name) + ' | ' + this.htmlDecode(device.networkType)
+ ' | ' + device.site.area
+ ' | ' + device.site.region,
site: device.site,
siteId: device.site.siteId,
siteName: this.htmlDecode(device.site.name),
shelfId: this.getShelfId(device),
shortId: deviceId.shortId,
ipAddress: this.getIpAddress(device),
ipAddressesInfo: device.ipAddressesInfo,
deviceLevel: device.deviceLevel,
deviceType: device.deviceType,
toolTip: device.toolTip,
connectionType: device.connectionType !== undefined ? device.connectionType : null,
ports: [],
picHeight: 50,
picWidth: 50,
lastPortPanel: -1,
rectangleWidth: 85,
statusColor: InventoryConfigurationConstants.CONST_DEFAULT_PORT_COLOR,
loc: null,
isTreeExpanded: null,
parent: null,
serviceId: null,
networkType: null,
networkTypeKey: null,
nt: this.htmlDecode(device.networkType),
area: device.site.area,
region: device.site.region,
rowNum: 0 // rowNum,
};
if (device.loc !== undefined && device.loc !== null)
nodeData.loc = device.loc; // device.loc.x + " " + device.loc.y;
if (typeof (device.isTreeExpanded) !== "undefined")
nodeData.isTreeExpanded = device.isTreeExpanded;
if (typeof (device.serviceId) !== "undefined")
nodeData.serviceId = device.serviceId;
if (typeof (device.group) !== "undefined")
nodeData['group'] = device.group;
if (device.deviceLevel === InventoryConfigurationConstants.CONST_DL_PHYSICALDEVICE) {
nodeData.networkType = device.networkType;
nodeData.networkTypeKey = device.networkTypeKey;
}
return nodeData;
};
getShelfId(device) {
return device.deviceType !== undefined ? device.deviceId.shelfId.substr(3 + device.deviceType.length + 1) : device.deviceId.shelfId.substr(3);
}
getIpAddress(device) {
return device.ipAddressesInfo !== undefined && device.ipAddressesInfo.length > 0 ? device.ipAddressesInfo[0].ipAddress : null;
}
override setContextMenu() {
let nodeContext = document.getElementById(‘nodeContextMenu’);
let that = this;
nodeContext.addEventListener(‘contextmenu’, (e) => {
e.preventDefault();
return false;
}, false)
let myNodeContextMenu = this.GO(go.HTMLInfo, {
show: showNodeContextMenu,
hide: hideNodeContextMenu,
mainElement: nodeContext
})
function hideCX() {
if (that.diagram.currentTool instanceof go.ContextMenuTool) {
setTimeout(() => {
that.diagram.currentTool.doCancel();
}, 0);
}
}
function showNodeContextMenu(obj, diagram, tool) {
diagram.scrollsPageOnFocus = true;
nodeContext.style.display = 'block';
// Ticket #654
GoJSAbstractTemplate.setContextMenuLocation(obj, nodeContext, 228, 520);
window.addEventListener("click", hideCX, true);
}
function hideNodeContextMenu(obj, diagram, tool) {
nodeContext.style.display = 'none';
window.removeEventListener("click", hideCX, true);
}
this.template.contextMenu = myNodeContextMenu;
this.setPortContextMenu("PortPanel");
}
setPortContextMenu(portPanelName) {
let portContext = document.getElementById('portContextMenu');
portContext.addEventListener('contextmenu', (e) => {
e.preventDefault();
return false;
}, false)
let myPortContextMenu = this.GO(go.HTMLInfo, {
show: showPortContextMenu,
mainElement: portContext
})
function showPortContextMenu(obj, diagram, tool) {
// enable port connection on ports on a node
let connectPortContextMenuItem = document.getElementById('connectPortContextMenuItem');
if (connectPortContextMenuItem != null)
connectPortContextMenuItem.style.display = 'block';
// disable port disconnection on none connected ports on a node
let disconnectPortContextMenuItem = document.getElementById('disconnectPortContextMenuItem');
if (disconnectPortContextMenuItem != null)
disconnectPortContextMenuItem.style.display = 'none';
let mousePt = diagram.lastInput.viewPoint;
portContext.style.display = 'block';
jsHelpers.setContextPosition(mousePt,portContext);
}
var portPanel = this.template.findObject(portPanelName);
if (portPanel.itemTemplate != null) // Node template has itemTemplate attribute, LinkTemplate does not
portPanel.itemTemplate.contextMenu = myPortContextMenu;
else
portPanel.contextMenu = myPortContextMenu;
}
}
The custom shape code is :
go.Shape.defineFigureGenerator(“CustomSquareArrowRight”, function (shape, w, h) {
var param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1) || param1 < 0) param1 = 5; // default corner
param1 = Math.min(param1, w / 3);
param1 = Math.min(param1, h / 3);
var rightLineHeight = h * 0.23;
var arrowHeight = rightLineHeight / 2;
var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
var cpOffset = param1 * KAPPA;
var geo = new go.Geometry()
.add(new go.PathFigure(param1, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, arrowHeight))
.add(new go.PathSegment(go.SegmentType.Line, w + 30, rightLineHeight))
.add(new go.PathSegment(go.SegmentType.Line, w, rightLineHeight))
.add(new go.PathSegment(go.SegmentType.Line, w, rightLineHeight))
.add(new go.PathSegment(go.SegmentType.Line, w, h - param1))
.add(new go.PathSegment(go.SegmentType.Bezier, w - param1, h, w, h - cpOffset, w - cpOffset, h))
.add(new go.PathSegment(go.SegmentType.Line, param1, h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0, h - param1, cpOffset, h, 0, h - cpOffset))
.add(new go.PathSegment(go.SegmentType.Line, 0, param1))
.add(new go.PathSegment(go.SegmentType.Bezier, param1, 0, 0, cpOffset, cpOffset, 0).close()));
if (cpOffset > 1) {
geo.spot1 = new go.Spot(0, 0, cpOffset, cpOffset);
geo.spot2 = new go.Spot(1, 1, -cpOffset, -cpOffset);
}
return geo;
});
Please advice
Tany






