278 lines
12 KiB
HTML
278 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Regrouping Demo with shrinking members</title>
|
|
<meta name="description" content="Define and modify groups just as the Regrouping sample does, but nested groups are automatically scaled smaller and smaller." />
|
|
<!-- Copyright 1998-2017 by Northwoods Software Corporation. -->
|
|
<meta charset="UTF-8">
|
|
<script src="../release/go.js"></script>
|
|
<script src="../assets/js/goSamples.js"></script> <!-- this is only for the GoJS Samples framework -->
|
|
<script id="code">
|
|
function init() {
|
|
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
|
|
var $ = go.GraphObject.make;
|
|
|
|
myDiagram =
|
|
$(go.Diagram, "myDiagramDiv",
|
|
{
|
|
allowDrop: true, // from Palette
|
|
// what to do when a drag-drop occurs in the Diagram's background
|
|
mouseDrop: function(e) { finishDrop(e, null); },
|
|
layout: // Diagram has simple horizontal layout
|
|
$(go.GridLayout,
|
|
{ wrappingWidth: Infinity, alignment: go.GridLayout.Position, cellSize: new go.Size(1, 1) }),
|
|
initialContentAlignment: go.Spot.Center,
|
|
"commandHandler.archetypeGroupData": { isGroup: true, category: "OfNodes" },
|
|
"undoManager.isEnabled": true
|
|
});
|
|
|
|
// when the document is modified, add a "*" to the title and enable the "Save" button
|
|
myDiagram.addDiagramListener("Modified", function(e) {
|
|
var button = document.getElementById("saveModel");
|
|
if (button) button.disabled = !myDiagram.isModified;
|
|
var idx = document.title.indexOf("*");
|
|
if (myDiagram.isModified) {
|
|
if (idx < 0) document.title += "*";
|
|
} else {
|
|
if (idx >= 0) document.title = document.title.substr(0, idx);
|
|
}
|
|
});
|
|
|
|
// There are two templates for Groups, "OfGroups" and "OfNodes".
|
|
|
|
// this function is used to highlight a Group that the selection may be dropped into
|
|
function highlightGroup(e, grp, show) {
|
|
if (!grp) return;
|
|
e.handled = true;
|
|
if (show) {
|
|
// cannot depend on the grp.diagram.selection in the case of external drag-and-drops;
|
|
// instead depend on the DraggingTool.draggedParts or .copiedParts
|
|
var tool = grp.diagram.toolManager.draggingTool;
|
|
var map = tool.draggedParts || tool.copiedParts; // this is a Map
|
|
// now we can check to see if the Group will accept membership of the dragged Parts
|
|
if (grp.canAddMembers(map.toKeySet())) {
|
|
grp.isHighlighted = true;
|
|
return;
|
|
}
|
|
}
|
|
grp.isHighlighted = false;
|
|
}
|
|
|
|
// Upon a drop onto a Group, we try to add the selection as members of the Group.
|
|
// Upon a drop onto the background, or onto a top-level Node, make selection top-level.
|
|
// If this is OK, we're done; otherwise we cancel the operation to rollback everything.
|
|
function finishDrop(e, grp) {
|
|
var ok = (grp !== null
|
|
? grp.addMembers(grp.diagram.selection, true)
|
|
: e.diagram.commandHandler.addTopLevelParts(e.diagram.selection, true));
|
|
if (!ok) e.diagram.currentTool.doCancel();
|
|
}
|
|
|
|
myDiagram.groupTemplateMap.add("OfGroups",
|
|
$(go.Group, go.Panel.Auto,
|
|
{
|
|
background: "transparent",
|
|
// highlight when dragging into the Group
|
|
mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
|
|
mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
|
|
computesBoundsAfterDrag: true,
|
|
// when the selection is dropped into a Group, add the selected Parts into that Group;
|
|
// if it fails, cancel the tool, rolling back any changes
|
|
mouseDrop: finishDrop,
|
|
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
|
|
// Groups containing Groups lay out their members horizontally
|
|
layout:
|
|
$(go.GridLayout,
|
|
{ wrappingWidth: Infinity, alignment: go.GridLayout.Position,
|
|
cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4) })
|
|
},
|
|
{ // automatically adjust the scale of the HEADER, depending on the nesting depth
|
|
containingGroupChanged:
|
|
function(part, oldgroup, newgroup) { part.findObject("HEADER").scale = 1 / (1+part.findSubGraphLevel()); }
|
|
},
|
|
new go.Binding("background", "isHighlighted", function(h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
|
|
$(go.Shape, "Rectangle",
|
|
{ fill: null, stroke: "#E69900", strokeWidth: 2 }),
|
|
$(go.Panel, go.Panel.Vertical, // title above Placeholder
|
|
$(go.Panel, go.Panel.Horizontal, // button next to TextBlock
|
|
{ name: "HEADER" },
|
|
{ stretch: go.GraphObject.Horizontal, background: "#FFDD33", margin: 1 },
|
|
$("SubGraphExpanderButton",
|
|
{ alignment: go.Spot.Right, margin: 5 }),
|
|
$(go.TextBlock,
|
|
{
|
|
alignment: go.Spot.Left,
|
|
editable: true,
|
|
margin: 5,
|
|
font: "bold 18px sans-serif",
|
|
stroke: "#9A6600"
|
|
},
|
|
new go.Binding("text", "text").makeTwoWay())
|
|
), // end Horizontal Panel
|
|
$(go.Placeholder,
|
|
{ padding: 5, alignment: go.Spot.TopLeft })
|
|
) // end Vertical Panel
|
|
)); // end Group and call to add to template Map
|
|
|
|
myDiagram.groupTemplateMap.add("OfNodes",
|
|
$(go.Group, go.Panel.Auto,
|
|
{
|
|
background: "transparent",
|
|
ungroupable: true,
|
|
// highlight when dragging into the Group
|
|
mouseDragEnter: function(e, grp, prev) { highlightGroup(e, grp, true); },
|
|
mouseDragLeave: function(e, grp, next) { highlightGroup(e, grp, false); },
|
|
computesBoundsAfterDrag: true,
|
|
// when the selection is dropped into a Group, add the selected Parts into that Group;
|
|
// if it fails, cancel the tool, rolling back any changes
|
|
mouseDrop: finishDrop,
|
|
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
|
|
// Groups containing Nodes lay out their members vertically
|
|
layout:
|
|
$(go.GridLayout,
|
|
{ wrappingColumn: 1, alignment: go.GridLayout.Position,
|
|
cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4) })
|
|
},
|
|
{ // automatically adjust the scale of the HEADER, depending on the nesting depth
|
|
containingGroupChanged:
|
|
function(part, oldgroup, newgroup) { part.findObject("HEADER").scale = 1 / (1+part.findSubGraphLevel()); }
|
|
},
|
|
new go.Binding("background", "isHighlighted", function(h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
|
|
$(go.Shape, "Rectangle",
|
|
{ fill: null, stroke: "#0099CC", strokeWidth: 2 }),
|
|
$(go.Panel, go.Panel.Vertical, // title above Placeholder
|
|
$(go.Panel, go.Panel.Horizontal, // button next to TextBlock
|
|
{ name: "HEADER" },
|
|
{ stretch: go.GraphObject.Horizontal, background: "#33D3E5", margin: 1 },
|
|
$("SubGraphExpanderButton",
|
|
{ alignment: go.Spot.Right, margin: 5 }),
|
|
$(go.TextBlock,
|
|
{
|
|
alignment: go.Spot.Left,
|
|
editable: true,
|
|
margin: 5,
|
|
font: "bold 16px sans-serif",
|
|
stroke: "#006080"
|
|
},
|
|
new go.Binding("text", "text").makeTwoWay())
|
|
), // end Horizontal Panel
|
|
$(go.Placeholder,
|
|
{ padding: 5, alignment: go.Spot.TopLeft })
|
|
) // end Vertical Panel
|
|
)); // end Group and call to add to template Map
|
|
|
|
// Nodes have a trivial definition
|
|
myDiagram.nodeTemplate =
|
|
$(go.Node, go.Panel.Auto,
|
|
{ // dropping on a Node is the same as dropping on its containing Group, even if it's top-level
|
|
mouseDrop: function(e, nod) { finishDrop(e, nod.containingGroup); }
|
|
},
|
|
{ // automatically adjust the scale of the HEADER, depending on the nesting depth
|
|
containingGroupChanged:
|
|
function(part, oldgroup, newgroup) { part.scale = 1 / (1+part.findSubGraphLevel()); }
|
|
},
|
|
$(go.Shape, "Rectangle",
|
|
{ fill: "#ACE600", stroke: "#558000", strokeWidth: 2 },
|
|
new go.Binding("fill", "color")),
|
|
$(go.TextBlock,
|
|
{
|
|
margin: 5,
|
|
editable: true,
|
|
font: "bold 13px sans-serif",
|
|
stroke: "#446700"
|
|
},
|
|
new go.Binding("text", "text").makeTwoWay())
|
|
);
|
|
|
|
// initialize the Palette and its contents
|
|
myPalette =
|
|
$(go.Palette, "myPaletteDiv",
|
|
{
|
|
nodeTemplateMap: myDiagram.nodeTemplateMap,
|
|
groupTemplateMap: myDiagram.groupTemplateMap,
|
|
layout: $(go.GridLayout, { wrappingColumn: 1, alignment: go.GridLayout.Position })
|
|
});
|
|
myPalette.model = new go.GraphLinksModel([
|
|
{ text: "lightgreen", color: "#ACE600" },
|
|
{ text: "yellow", color: "#FFDD33" },
|
|
{ text: "lightblue", color: "#33D3E5" }
|
|
]);
|
|
|
|
var slider = document.getElementById("levelSlider");
|
|
slider.addEventListener('change', reexpand);
|
|
slider.addEventListener('input', reexpand);
|
|
|
|
load();
|
|
}
|
|
|
|
function expandGroups(g, i, level) {
|
|
if (!(g instanceof go.Group)) return;
|
|
g.isSubGraphExpanded = i < level;
|
|
g.memberParts.each(function(m) {
|
|
expandGroups(m, i + 1, level);
|
|
})
|
|
}
|
|
function reexpand(e) {
|
|
myDiagram.startTransaction("reexpand");
|
|
var level = parseInt(document.getElementById("levelSlider").value);
|
|
myDiagram.findTopLevelGroups().each(function(g) { expandGroups(g, 0, level); })
|
|
myDiagram.commitTransaction("reexpand");
|
|
}
|
|
|
|
// save a model to and load a model from JSON text, displayed below the Diagram
|
|
function save() {
|
|
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
|
|
myDiagram.isModified = false;
|
|
}
|
|
function load() {
|
|
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
|
|
}
|
|
</script>
|
|
</head>
|
|
<body onload="init()">
|
|
<div id="sample">
|
|
<div style="width:100%; white-space:nowrap;">
|
|
<span style="display: inline-block; vertical-align: top; width:100px">
|
|
<div id="myPaletteDiv" style="border: solid 1px black; height: 500px"></div>
|
|
</span>
|
|
<span style="display: inline-block; vertical-align: top; width:80%">
|
|
<div id="myDiagramDiv" style="border: solid 1px black; height: 500px"></div>
|
|
</span>
|
|
</div>
|
|
<p>
|
|
This sample is just like the <a href="regrouping.html">Regrouping</a> sample,
|
|
but the members of each Group are scaled with smaller values as their nesting increases.
|
|
</p>
|
|
<div id="buttons">
|
|
<button id="saveModel" onclick="save()">Save</button>
|
|
<button id="loadModel" onclick="load()">Load</button>
|
|
Semantic zoom level: <input id="levelSlider" type="range" min="0" max="5" value="3" />
|
|
</div>
|
|
<textarea id="mySavedModel" style="width:100%;height:300px">
|
|
{ "class": "go.GraphLinksModel",
|
|
"nodeDataArray": [
|
|
{"key":1, "text":"Main 1", "isGroup":true, "category":"OfGroups"},
|
|
{"key":2, "text":"Main 2", "isGroup":true, "category":"OfGroups"},
|
|
{"key":3, "text":"Group A", "isGroup":true, "category":"OfNodes", "group":1},
|
|
{"key":4, "text":"Group B", "isGroup":true, "category":"OfNodes", "group":1},
|
|
{"key":5, "text":"Group C", "isGroup":true, "category":"OfNodes", "group":2},
|
|
{"key":6, "text":"Group D", "isGroup":true, "category":"OfNodes", "group":2},
|
|
{"key":7, "text":"Group E", "isGroup":true, "category":"OfNodes", "group":6},
|
|
{"text":"first A", "group":3, "key":-7},
|
|
{"text":"second A", "group":3, "key":-8},
|
|
{"text":"first B", "group":4, "key":-9},
|
|
{"text":"second B", "group":4, "key":-10},
|
|
{"text":"third B", "group":4, "key":-11},
|
|
{"text":"first C", "group":5, "key":-12},
|
|
{"text":"second C", "group":5, "key":-13},
|
|
{"text":"first D", "group":6, "key":-14},
|
|
{"text":"first E", "group":7, "key":-15}
|
|
],
|
|
"linkDataArray": [ ]}
|
|
</textarea>
|
|
</div>
|
|
</body>
|
|
|
|
</html>
|