we have a diagram like the above. second image show the drawer expanded state.
the blue bordersection is a grouptemplate
the green section is a taygroup template
within the green section there is trayRowGroup template (eg 12p, 22p)
within the trayRowGroup we have the positionCell template (small white squares)
within each posioncell we can drag and drop products.
the red section is the drawer group template
within that each row is a DrawerRowGroup Template
each row is expandable.
once we expand we have the drawer content group section.
within that we have positionCell template within each posioncell we can drag and drop products.
when we expan and collapse the diagram keep shifting to the left.
when we hover over the products in the palette we highlight the positions that it can be placed in. For the first time it works fine.(pic 3)
But after expanding and collapsing the drawer the diagram gets distorted.(pic 4)
after click on copy icon after expanding the drawer the diagram gets distorted.(pic 5)
private addBorderGroupTemplate(): void {
this.groupTemplateMap.add(Categories.BorderGroup,
$(go.Group, go.Group.Vertical, {
selectable: false,
movable: false,
// layout: $(TableLayout),
mouseDragEnter: (e: go.InputEvent, obj: go.GraphObject): void => {
e.diagram.currentCursor = 'not-allowed';
return;
},
mouseDrop: (e: go.InputEvent, obj: go.GraphObject): void => {
e.diagram.currentTool.doCancel();
}
},
new go.Binding('layout', '', data => {
return this.sensorLayoutService.is10KMachine ? $(TableLayout) : undefined;
}),
$(go.Panel, go.Panel.Auto, {},
$(go.Shape, 'RoundedRectangle', {
fill: COLORS.primary,
stroke: null,
parameter1: 5
}),
$(go.Placeholder, {
padding: new go.Margin(15, 0, 10, 0)// Default padding,
},
new go.Binding('padding', '', data => {
return this.sensorLayoutService.is10KMachine &&
this.sensorLayoutService.currentLayout!.vendingFixtureLayout.length > 1 ? new go.Margin(10, 0, 10, 0) : new go.Margin(15, 10, 10, 15);
}),
),
),
$(go.Panel, go.Panel.Table, {
stretch: go.GraphObject.Horizontal
},
$(go.RowColumnDefinition, { sizing: go.RowColumnDefinition.None }),
$(go.Shape, 'Rectangle', { column: 0, height: 30, width: 15, stroke: null, fill: COLORS.primary }),
$(go.Shape, 'Rectangle', { column: 1, height: 30, width: 15, stroke: null, fill: COLORS.primary }),
new go.Binding('visible', '', data => {
return !this.sensorLayoutService.is10KMachine;
}),
),
//group type binding
new go.Binding('type', 'groupType', this.parseGroupType),
)
);
}
private addTraysGroupTemplate(): void {
this.groupTemplateMap.add('TraysGroup',
$(go.Group, go.Group.Auto,
{
selectable: false,
movable: false,
row: 0,
margin: new go.Margin(0, 0, 10, 0),
stretch: go.GraphObject.Horizontal,
background: 'green',
alignment: go.Spot.Left,
},
new go.Placeholder()
),
);
}
private addTrayRowGroupTemplate(): void {
this.groupTemplateMap.add(Categories.TrayRowGroup,
$(go.Group, go.Group.Horizontal, {
selectable: false,
mouseDragEnter: (e: go.InputEvent, obj: go.GraphObject): void => {
e.diagram.currentCursor = 'not-allowed';
return;
},
mouseDrop: (e: go.InputEvent, obj: go.GraphObject): void => {
e.diagram.currentTool.doCancel();
}
},
// Layout name label - positioned outside the white tray, only visible when layout is selected
$(go.TextBlock, {
stroke: COLORS.secondary,
font: 'bold 1rem verdana',
width: 23,
height: 23,
textAlign: 'center',
verticalAlignment: go.Spot.Center,
background: 'transparent'
},
new go.Binding('visible', 'selectedModule', data => (data === '' ? false : true)),
new go.Binding('text', 'selectedModule')
),
// white tray
$(go.Panel, go.Panel.Auto,
$(go.Shape, 'RoundedRectangle', {
name: 'Row_Group_Shape',
stroke: null,
fill: COLORS.secondary,
parameter1: 3
},
new go.Binding('desiredSize', 'dimensions', dimensions => convertSize(dimensions,
{
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
}
)),
new go.Binding('fill', '', data => {
return data.isLayoutAdded ? 'transparent' : COLORS.secondary;
}),
),
//Add Button
$('Button', {
margin: new go.Margin(0, 0, 0, 2),
'ButtonBorder.stroke': COLORS.primary,
'\_buttonStrokeOver': COLORS.primary,
'\_buttonFillPressed': COLORS.light,
click: (e, obj: go.GraphObject) => {
e.handled = true;
if (!this.sensorLayoutService.inCopyMode) {
this.eventBusService.emit({ name: Actions.SelectLayoutSlider, value: obj.part?.data } as EventData);
}
},
},
$(go.TextBlock, 'ADD TRAY MODULE', {
stroke: COLORS.primary,
stretch: go.GraphObject.Fill,
font: 'bold 1rem verdana',
margin: new go.Margin(5, 5, 5, 5),
}),
// Hide the entire panel when no layout is selected
new go.Binding('visible', 'isLayoutAdded', isLayoutAdded => !isLayoutAdded)
),
$(go.Placeholder, { alignment: go.Spot.Left, padding: 0, margin: 0 })
),
// edit button
$(go.Panel, 'Auto', { width: 26 },
$(go.TextBlock, {
stroke: COLORS.secondary,
font: 'bold 1rem verdana',
width: 25,
height: 25,
textAlign: 'center',
verticalAlignment: go.Spot.Center,
},
new go.Binding('text', 'row'),
new go.Binding('visible', 'isLayoutAdded', isLayoutAdded => !isLayoutAdded)
),
$('Button', {
margin: new go.Margin(0, 0, 0, 2),
alignment: go.Spot.RightCenter,
alignmentFocus: go.Spot.LeftCenter,
'ButtonBorder.figure': 'Circle',
'ButtonBorder.stroke': COLORS.primary,
'\_buttonStrokeOver': COLORS.primary,
'\_buttonFillPressed': COLORS.light,
width: 25,
click: (e, obj: go.GraphObject) => {
e.handled = true;
if (!this.sensorLayoutService.inCopyMode) {
this.eventBusService.emit({ name: Actions.SelectLayoutSlider, value: obj.part?.data } as EventData);
}
},
},
$(go.TextBlock, '\\ue3c9', {
stroke: COLORS.primary,
stretch: go.GraphObject.Fill,
font: '1.5rem "Material Icons"',
margin: new go.Margin(3, 0, 0, 2),
}),
// Hide the edit button when no layout is selected
new go.Binding('visible', 'isLayoutAdded')
),
),
// binding group type
new go.Binding('type', 'diagramLayoutType', this.parseGroupType),
// ).bindTwoWay('position', '', this.toLocation.bind(this), this.fromLocation.bind(this))
).bindTwoWay('position', '', this.toLocation.bind(this), this.fromLocation.bind(this))
);
}
private addSensorPositionsTemplate(): void {
this.groupTemplateMap.add(Categories.SensorPositions,
$(go.Group, go.Group.Spot, {
selectable: false,
movable: false,
selectionAdorned: false,
alignment: go.Spot.Left,
mouseDrop: this.handleMouseDrop.bind(this),
mouseDragEnter: (e: go.InputEvent, obj: go.GraphObject) => {
this.updateSensorPositionCellFill(obj, COLORS.lightGray, 'SensorPositionCellShape');
},
mouseDragLeave: (e: go.InputEvent, obj: go.GraphObject) => {
this.updateSensorPositionCellFill(obj, COLORS.secondary, 'SensorPositionCellShape');
}
},
$(go.Panel, go.Panel.Auto,
// white rectangle
$(go.Shape, 'RoundedRectangle', {
name: 'SensorPositionCellShape',
fill: COLORS.secondary,
stroke: null
},
new go.Binding('fill', 'highlight', highlight => {
return highlight ? COLORS.positionHighlight : COLORS.secondary;
}
),
),
new go.Binding('desiredSize', 'dimensions', dimensions => convertSize(dimensions,
{
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
}
)),
this.addSkuPanel(),
),
// binding group type
new go.Binding('type', 'diagramLayoutType', this.parseGroupType),
).bindTwoWay('position', '', this.toLocation.bind(this), this.fromLocation.bind(this))
);
}
private createProductNodeTemplate(): go.Node {
return $(go.Node, go.Node.Vertical,
{
selectionAdorned: false,
background: 'transparent',
mouseDrop: (e: go.InputEvent) => { e.diagram.currentTool.doCancel(); },
mouseEnter: (e: go.InputEvent, obj: go.GraphObject): void => {
this.mouseEnterCell(e, obj);
this.showDeleteIcon(e, obj);
},
mouseLeave: (e: go.InputEvent, obj: go.GraphObject, next: go.GraphObject) => {
this.mouseLeaveCell(e, obj, next),
this.hideDeleteIcon(e, obj);
}
},
// binding this to show data in the center
new go.Binding('desiredSize', 'dimensions', dimensions =>
convertSize(dimensions,
{
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
}
)
),
$(go.Panel, go.Panel.Auto, {
margin: new go.Margin(2, 1, 1, 1),
background: 'transparent',
},
$(go.Picture, {
name: 'Picture',
imageStretch: go.GraphObject.Uniform,
alignment: go.Spot.Center,
desiredSize: new go.Size(40, 40),
errorFunction: (pic: go.Picture, e: Event) => {
pic.diagram?.commit(function () {
pic.source = CONSTANTS.NO_IMAGE_PATH;
}, null); // null means temporarily set skipsUndoManager to true
}
},
new go.Binding('source', 'imageThumbnail'),
new go.Binding('desiredSize', 'dimensions', dimensions =>
convertImageSize(dimensions,
{
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
}
)
),
),
this.displayCapacity(),
this.displayRemoveIcon(),
)
);
}
private toLocation(data: go.ObjectData): go.Point {
// console.log(data);
const x = inchesToScaledGoJSUnits(data.location?.x ?? 0, this.sensorLayoutService.widthScale);
const y = inchesToScaledGoJSUnits(data.location?.y ?? 0, this.sensorLayoutService.heightScale);
const loc = new go.Point(x, y);
if (data.group !== undefined) {
const groupdata = this.model.findNodeDataForKey(data.group);
if (groupdata) {
loc.add(this.toLocation(groupdata));
}
}
return loc;
}
private fromLocation(location: go.ObjectData, data: go.ObjectData): void {
if (data.group !== undefined) {
const group = this.findNodeForKey(data.group);
if (group) {
const relativeLoc = location.copy().subtract(group.location);
const x = scaledGoJSToInches(relativeLoc.x, this.sensorLayoutService.widthScale);
const y = scaledGoJSToInches(relativeLoc.y, this.sensorLayoutService.heightScale);
data.location = { x, y };
}
} else {
const x = scaledGoJSToInches(location.x, this.sensorLayoutService.widthScale);
const y = scaledGoJSToInches(location.y, this.sensorLayoutService.heightScale);
data.location = { x, y };
}
// Also update \`loc\` string if needed
data.loc = \`${location.x.toFixed(2)} ${location.y.toFixed(2)}\`;
}
private parseGroupType(type: string): go.PanelLayout {
switch (type) {
case 'Vertical': return go.Group.Vertical;
case 'Horizontal': return go.Group.Horizontal;
case 'Spot': return go.Group.Spot;
default: return go.Group.Auto;
}
}
private addDrawersGroupTemplate(): void {
this.groupTemplateMap.add('DrawersGroup',
$(go.Group, go.Group.Auto,
{
selectable: false,
movable: false,
layout: $(TableLayout),
row: 1,
background: 'red',
stretch: go.GraphObject.Horizontal,
},
new go.Placeholder({ alignment: go.Spot.LeftCenter })
),
);
}
private addDrawerRowGroupTemplate(): void {
// Row group template (expandable/collapsible drawers)
this.groupTemplateMap.add(Categories.DrawerRowGroup,
$(go.Group, go.Group.Horizontal, {
selectable: false,
margin: new go.Margin(5, 0, 5, 0),
mouseDragEnter: ((e: go.InputEvent, obj: go.GraphObject) => {
e.diagram.currentCursor = 'not-allowed';
return;
}),
mouseDrop: (e: go.InputEvent, obj: go.GraphObject) => e.diagram.currentTool.doCancel()
},
// Position and Size bindings
new go.Binding('row'),
new go.Binding('isSubGraphExpanded', 'isSubGraphExpanded').makeTwoWay(),
// Layout name label - positioned outside the white tray, only visible when layout is selected
$(go.TextBlock, {
stroke: COLORS.secondary,
font: 'bold 1rem verdana',
textAlign: 'center',
margin: 2,
verticalAlignment: go.Spot.Center,
background: 'transparent'
},
new go.Binding('text', 'drawerNo')
),
// Content panel
$(go.Panel, go.Panel.Auto,
$(go.Shape, 'RoundedRectangle', {
stroke: COLORS.primary,
fill: COLORS.secondary,
margin: new go.Margin(0, 15, 0, 0),
parameter1: 3,
spot1: new go.Spot(0, 0, 0, -1),
spot2: new go.Spot(1, 1, 0, -1),
},
new go.Binding('width', 'dimensions', dimensions => inchesToScaledGoJSUnits(dimensions\[0\].width)),
new go.Binding('fill', 'isDrawerOpenable', isDrawerOpenable => (isDrawerOpenable ? COLORS.secondary : '#6698CA'))
),
$(go.Panel, go.Panel.Vertical, {
name: DiagramGraphObjectNames.drawerPanel
},
new go.Binding('minSize', 'dimensions', dimensions => convertSize(dimensions,
{
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
}
)),
// Header panel
$(go.Panel, go.Panel.Horizontal, {
name: DiagramGraphObjectNames.headerPanel,
alignment: go.Spot.TopLeft,
stretch: go.GraphObject.Fill
},
// Bin count label
$(go.TextBlock, {
name: 'bin_name',
verticalAlignment: go.Spot.Center,
stroke: COLORS.primary,
margin: new go.Margin(0, 5, 0, 5),
font: 'bold 1.2rem verdana'
},
new go.Binding('minSize', 'dimensions', dimensions => {
return new go.Size(inchesToScaledGoJSUnits(dimensions\[0\].width / 2) - 45, inchesToScaledGoJSUnits(dimensions\[0\].height));
}),
new go.Binding('text', 'bin', bin => \`${bin} BINS\`),
),
// Expand/collapse button
$(go.Shape, 'Rectangle', {
stroke: null,
name: 'EXPAND_BUTTON',
strokeWidth: 0,
fill: COLORS.primary,
width: 60,
height: 12,
alignment: go.Spot.TopCenter,
margin: 0,
cursor: 'pointer',
mouseEnter: function (e: go.InputEvent, obj: go.GraphObject) {
(obj as go.Shape).fill = COLORS.primaryLight;
},
mouseLeave: function (e: go.InputEvent, obj: go.GraphObject) {
(obj as go.Shape).fill = COLORS.primary;
},
click: this.toggleDrawer.bind(this)
}),
$(go.Panel, go.Panel.Table,
new go.Binding('minSize', 'dimensions', dimensions => {
return new go.Size(inchesToScaledGoJSUnits(dimensions\[0\].width / 2) - 40, inchesToScaledGoJSUnits(dimensions\[0\].height));
}),
this.createButton(
'\\ue5cf',
COLORS.lightGray,
(e: go.InputEvent, obj: go.ObjectData) => this.toggleDrawer(e, obj.part),
)
)
).bind('visible', 'isDrawerOpenable'),
// Content placeholder
$(go.Placeholder, {
alignment: go.Spot.LeftCenter,
padding: 0,
})
)
),
)
);
}
public drawerContentGroup(): void {
// Drawer group template (contains the grid and action buttons)
this.groupTemplateMap.add(Categories.DrawerGroupContent,
$(go.Group, 'Vertical', {
selectable: false,
margin: 0,
mouseDrop: (e: go.InputEvent, obj: go.GraphObject) => e.diagram.currentTool.doCancel(),
mouseDragEnter: (e: go.InputEvent, obj: go.GraphObject): void => {
e.diagram.currentCursor = 'not-allowed';
return;
},
},
// Grid placeholder
$(go.Placeholder, {
padding: 1,
background: COLORS.primary
}),
// Action buttons panel
$(go.Panel, go.Panel.Table, {
margin: 10,
stretch: go.GraphObject.Fill,
},
$(go.Panel, {
alignment: go.Spot.Left
},
$(go.TextBlock, {
alignment: go.Spot.Left,
stroke: COLORS.primary,
font: 'bold 1.2rem verdana',
}).bind('text', 'bin', bin => \`${bin} BINS\`),
),
$(go.Panel, {
alignment: go.Spot.Right,
},
this.createButton(
'\\ue5ce',
COLORS.primary,
(e: go.InputEvent, obj: go.ObjectData) => this.toggleDrawer(e, obj.part.containingGroup),
)
)
)
)
);
}
public setupDrawerPosition(): void {
this.groupTemplateMap.add(Categories.DrawerGroupPositions,
$(go.Group, 'Auto', {
stretch: go.GraphObject.Horizontal,
selectable: false,
cursor: 'pointer',
background: COLORS.primary,
// Drag and drop functionality
mouseDrop: this.handleMouseDrop.bind(this),
mouseDragEnter: (e: go.InputEvent, obj: go.GraphObject) => {
this.updateSensorPositionCellFill(obj, COLORS.lightGray, 'Cell_Shape');
},
mouseDragLeave: (e: go.InputEvent, obj: go.GraphObject) => {
this.updateSensorPositionCellFill(obj, COLORS.secondary, 'Cell_Shape');
}
},
// Position bindings
new go.Binding('minSize', 'dimensions', dimensions => convertSize(dimensions,
{
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
}
)),
new go.Binding('location', 'location', location => convertPoint(location, {
widthScale: this.sensorLayoutService.widthScale,
heightScale: this.sensorLayoutService.heightScale
})),
// Inner area
$(go.Shape, 'RoundedRectangle', {
fill: COLORS.secondary,
stroke: COLORS.primary,
parameter1: 3,
name: 'Cell_Shape'
},
new go.Binding('fill', 'highlight', highlight => {
return highlight ? COLORS.positionHighlight : COLORS.secondary;
}
),
),
this.addSkuPanel()
)
);
}
Please can you help provide solution for the above issue. I have also attached sample code