1 | <!DOCTYPE html>
|
2 | <html lang="en">
|
3 | <head>
|
4 | <meta charset="utf-8"/>
|
5 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
|
6 |
|
7 | <link rel="stylesheet" href="../assets/css/style.css"/>
|
8 | <title> GoJS Coordinate Systems-- Northwoods Software </title>
|
9 | <link rel="stylesheet" href="../assets/css/prism.css" />
|
10 | </head>
|
11 | <script>
|
12 |
|
13 | window.diagrams = [];
|
14 | window.goCode = function(pre, w, h, parentid, animation) {
|
15 | window.diagrams.push([pre, w, h, parentid, animation]);
|
16 | }
|
17 | </script>
|
18 | <body>
|
19 | <nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
|
20 | <div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
|
21 | <div class="md:pl-4">
|
22 | <a class="text-white hover:text-white no-underline hover:no-underline
|
23 | font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
|
24 | <h1 class="mb-0 p-1 ">GoJS</h1>
|
25 | </a>
|
26 | </div>
|
27 | <button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
|
28 | <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
|
29 | <path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
30 | <path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
|
31 | </svg>
|
32 | </button>
|
33 | <div id="topnavList" class="hidden sm:block items-center w-auto mt-0 text-white p-0 z-20">
|
34 | <ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
|
35 | <li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
|
36 | <li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
|
37 | <li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
|
38 | <li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
|
39 | <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
|
40 | <li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
|
41 | <li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
|
42 | <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
|
43 | target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
|
44 | <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
|
45 | target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
|
46 | </ul>
|
47 | </div>
|
48 | </div>
|
49 | <hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
|
50 | </nav>
|
51 |
|
52 | <div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
|
53 |
|
54 | <div id="navSide" class="flex flex-col w-full md:w-40 lg:w-48 text-gray-700 bg-white flex-shrink-0">
|
55 | <div class="flex-shrink-0 px-8 py-4">
|
56 | <button id="navButton" class="rounded-lg md:hidden focus:outline-none focus:ring" aria-label="Navigation">
|
57 | <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
|
58 | <path id="navOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
59 | <path id="navClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
|
60 | </svg>
|
61 | </button>
|
62 | </div>
|
63 | <nav id="navList" class="min-h-screen hidden md:block sidebar-nav flex-grow px-1 lg:px-4 pb-4 md:pb-0 md:overflow-y-auto break-words">
|
64 | <a href="index.html">Basics</a>
|
65 | <a href="buildingObjects.html">Building Parts</a>
|
66 | <a href="usingModels.html">Using Models</a>
|
67 | <a href="dataBinding.html">Data Binding</a>
|
68 | <a href="react.html">GoJS with React</a>
|
69 | <a href="angular.html">GoJS with Angular</a>
|
70 | <a href="textBlocks.html">TextBlocks</a>
|
71 | <a href="shapes.html">Shapes</a>
|
72 | <a href="pictures.html">Pictures</a>
|
73 | <a href="panels.html">Panels</a>
|
74 | <a href="tablePanels.html">Table Panels</a>
|
75 | <a href="brush.html">Brushes</a>
|
76 | <a href="sizing.html">Sizing Objects</a>
|
77 | <a href="itemArrays.html">Item Arrays</a>
|
78 | <a href="changedEvents.html">Changed Events</a>
|
79 | <a href="transactions.html">Transactions</a>
|
80 | <a href="viewport.html">Coordinates</a>
|
81 | <a href="initialView.html">Initial View</a>
|
82 | <a href="collections.html">Collections</a>
|
83 | <a href="links.html">Links</a>
|
84 | <a href="linkLabels.html">Link Labels</a>
|
85 | <a href="connectionPoints.html">Link Points</a>
|
86 | <a href="ports.html">Ports</a>
|
87 | <a href="nodes.html">Nodes</a>
|
88 | <a href="debugging.html">Debugging</a>
|
89 | <a href="layouts.html">Layouts</a>
|
90 | <a href="trees.html">Trees</a>
|
91 | <a href="subtrees.html">SubTrees</a>
|
92 | <a href="groups.html">Groups</a>
|
93 | <a href="subgraphs.html">SubGraphs</a>
|
94 | <a href="sizedGroups.html">Sized Groups</a>
|
95 | <a href="selection.html">Selection</a>
|
96 | <a href="highlighting.html">Highlighting</a>
|
97 | <a href="animation.html">Animation</a>
|
98 | <a href="toolTips.html">ToolTips</a>
|
99 | <a href="contextmenus.html">Context Menus</a>
|
100 | <a href="events.html">Diagram Events</a>
|
101 | <a href="tools.html">Tools</a>
|
102 | <a href="commands.html">Commands</a>
|
103 | <a href="permissions.html">Permissions</a>
|
104 | <a href="validation.html">Validation</a>
|
105 | <a href="HTMLInteraction.html">HTML Interaction</a>
|
106 | <a href="layers.html">Layers & Z-ordering</a>
|
107 | <a href="palette.html">Palette</a>
|
108 | <a href="overview.html">Overview</a>
|
109 | <a href="resizing.html">Resizing Diagrams</a>
|
110 | <a href="replacingDeleting.html">Replacing and Deleting</a>
|
111 | <a href="buttons.html">Buttons</a>
|
112 | <a href="templateMaps.html">Template Maps</a>
|
113 | <a href="legends.html">Legends and Titles</a>
|
114 | <a href="extensions.html">Extensions</a>
|
115 | <a href="geometry.html">Geometry Strings</a>
|
116 | <a href="grids.html">Grid Patterns</a>
|
117 | <a href="graduatedPanels.html">Graduated Panels</a>
|
118 | <a href="makingImages.html">Diagram Images</a>
|
119 | <a href="makingSVG.html">Diagram SVG</a>
|
120 | <a href="printing.html">Printing</a>
|
121 | <a href="serverSideImages.html">Server-side Images</a>
|
122 | <a href="nodeScript.html">GoJS in Node.js</a>
|
123 | <a href="testing.html">Testing</a>
|
124 | <a href="storage.html">Storage</a>
|
125 | <a href="performance.html">Performance</a>
|
126 | <a href="source.html">Building from Source</a>
|
127 | <a href="platforms.html">Platforms</a>
|
128 | <a href="deployment.html">Deployment</a>
|
129 | </nav>
|
130 | </div>
|
131 | <div class="pt-4 px-2 md:px-0 lg:px-4 pb-16 w-full overflow-hidden">
|
132 |
|
133 | <h1>Coordinate Systems</h1>
|
134 | <p>
|
135 | A <a>Diagram</a> uses two major coordinate systems when drawing <a>Part</a>s: document coordinates and view coordinates.
|
136 | Furthermore each <a>Panel</a> within a <a>Part</a> has its own coordinate system that its elements use.
|
137 | </p>
|
138 | <p>
|
139 | All coordinate systems in <b>GoJS</b> have <a>Point</a>s with increasing values of X going rightwards and
|
140 | increasing values of Y going downwards.
|
141 | </p>
|
142 |
|
143 | <h2 id="DocumentAndViewCoordinates">Document and View coordinates</h2>
|
144 | <p>
|
145 | The <a>Part.location</a> and <a>GraphObject.actualBounds</a> and <a>GraphObject.position</a> of Parts are in document coordinates.
|
146 | Thus the <a>Point</a> that may be saved for a Node's location in the model's node data object are normally in document coordinates:
|
147 | </p>
|
148 | <pre class="lang-js"><code>
|
149 | diagram.model.nodeDataArray = [
|
150 | { key: "Alpha", loc: "0 0" },
|
151 | { key: "Beta", loc: "100 50" }
|
152 | ];
|
153 | </code></pre>
|
154 | <p>
|
155 | The union of all of the Nodes and Links in a Diagram form the <a>Diagram.documentBounds</a>.
|
156 | This <a>Rect</a> has values that are in document coordinates.
|
157 | Depending on where the Nodes and Links are, the document bounds may cover a very large area.
|
158 | The range of the document bounds might be entirely positive x and y values, or that might be entirely negative,
|
159 | or more likely they may cover both negative and positive values.
|
160 | </p>
|
161 | <p>
|
162 | But a Part with a <a>Part.location</a> of (0, 0) in document coordinates is not always drawn at the top-left corner of
|
163 | the HTML Div element that the user sees in the page.
|
164 | When the user scrolls the diagram the part will need to be drawn elsewhere on the canvas.
|
165 | And if the user zooms in to make the parts appear larger, the parts will be drawn at different points in the canvas.
|
166 | Yet the <a>Part.location</a> does not change value as the user scrolls or zooms the diagram.
|
167 | </p>
|
168 | <p>
|
169 | The <i>viewport</i> is the area of the document that is visible in the canvas.
|
170 | That area is available as the <a>Diagram.viewportBounds</a>.
|
171 | Note that the viewport bounds is in document coordinates, not in view coordinates!
|
172 | The top-left corner of the viewport is (0,0) in view coordinates but is at <a>Diagram.position</a> in document coordinates.
|
173 | The bottom-right corner of the viewport is at the canvas's (width,height) in view coordinates.
|
174 | The bottom-right corner of the viewport in document coordinates depends on the <a>Diagram.scale</a>.
|
175 | </p>
|
176 | <p>
|
177 | Points in the canvas are in view coordinates, which are independent of document coordinates.
|
178 | View coordinates are distances from the top-left corner of the canvas in device-independent pixels.
|
179 | The differences between document coordinates and view coordinates are primarily controlled by two <a>Diagram</a> properties:
|
180 | <a>Diagram.position</a> and <a>Diagram.scale</a>.
|
181 | Scrolling and panning change the Diagram.position.
|
182 | Zooming in or out changes the Diagram.scale.
|
183 | You can also convert between coordinate systems by calling <a>Diagram.transformDocToView</a> and <a>Diagram.transformViewToDoc</a>.
|
184 | However very few properties or method arguments or return values are in view coordinates -- almost everything is in document
|
185 | coordinates or in panel coordinates.
|
186 | </p>
|
187 | <p>
|
188 | As an example of showing the viewport in the context of the whole document, an <a>Overview</a> does exactly that.
|
189 | Take a look at the overview that is in the <a href="../samples/orgChartStatic.html">Org Chart sample</a>.
|
190 | The overview shows the whole document of the main diagram.
|
191 | The magenta box shows the main diagram's viewport within the whole document.
|
192 | As you scroll or pan the main diagram, the viewport moves.
|
193 | As you zoom out, the viewport gets larger.
|
194 | </p>
|
195 | <p>
|
196 | To better understand the difference between document and viewport coordinates, look at this diagram:
|
197 | </p>
|
198 | <pre class="lang-js" id="diffCoordSystems" style="display:none"><code>
|
199 | diagram.nodeTemplate =
|
200 | $(go.Node, "Auto",
|
201 | { scale : 1.3},
|
202 | new go.Binding("location", "loc", gridPointParse),
|
203 | new go.Binding("scale", "scale"),
|
204 | { locationSpot: go.Spot.Center, portId: "NODE" },
|
205 | $(go.Shape, "RoundedRectangle",
|
206 | { fill: "white", portId: "SHAPE" },
|
207 | new go.Binding("fill", "color"),
|
208 | new go.Binding("strokeWidth", "strokeW")),
|
209 | $(go.TextBlock,
|
210 | { margin: 4, portId: "TEXTBLOCK" },
|
211 | new go.Binding("text", "text"),
|
212 | new go.Binding("stroke", "textColor"))
|
213 | );
|
214 |
|
215 | diagram.linkTemplate =
|
216 | $(go.Link,
|
217 | $(go.Shape, { stroke: "darkgray", strokeWidth: 2 }),
|
218 | $(go.Shape, { toArrow: "Standard", stroke: "darkgray", fill: "darkgray" })
|
219 | );
|
220 |
|
221 | // colors
|
222 | var docGridStroke = "rgba(70, 130, 180, 0.5)";
|
223 | var viewGridStroke = "rgba(255, 128, 128, 1)";
|
224 | var commentStroke = "brown";
|
225 |
|
226 | var cellSide = 20; // side length of one grid cell
|
227 | var cellSize = new go.Size(cellSide * 5, cellSide * 5);
|
228 | var pointSize = 7;
|
229 |
|
230 | function gridSizeParse(size) {
|
231 | if (!(size instanceof go.Size)) {
|
232 | size = go.Size.parse(size);
|
233 | }
|
234 | size.setTo(size.width * cellSide, size.height * cellSide);
|
235 | return size;
|
236 | }
|
237 | function gridPointParse(point) {
|
238 | if (!(point instanceof go.Point)) {
|
239 | point = go.Point.parse(point);
|
240 | }
|
241 | point.setTo(point.x * cellSide, point.y * cellSide);
|
242 | return point;
|
243 | }
|
244 |
|
245 | function LabelledPoint(x, y, label) {
|
246 | return {
|
247 | x: x,
|
248 | y: y,
|
249 | label: label
|
250 | }
|
251 | }
|
252 |
|
253 | diagram.nodeTemplateMap.add("Description", // Template for comment node
|
254 | $(go.Node, "Auto",
|
255 | new go.Binding("location", "loc", gridPointParse),
|
256 | new go.Binding("scale", "scale"),
|
257 | { locationSpot: go.Spot.Center, portId: "NODE" },
|
258 | $(go.Shape, "RoundedRectangle",
|
259 | { fill: "white", portId: "SHAPE" },
|
260 | new go.Binding("fill", "color"),
|
261 | new go.Binding("strokeWidth", "strokeW")),
|
262 | $(go.Panel, "Vertical",
|
263 | $(go.TextBlock,
|
264 | {font: "bold 11pt sans-serif", margin: new go.Margin(3, 0, 0, 0)},
|
265 | new go.Binding("text", "header"),
|
266 | new go.Binding("stroke", "textColor")),
|
267 | $(go.TextBlock,
|
268 | { margin: 3, portId: "TEXTBLOCK" },
|
269 | new go.Binding("text", "text"),
|
270 | new go.Binding("stroke", "textColor"))
|
271 | )
|
272 | ));
|
273 |
|
274 | diagram.nodeTemplateMap.add("DeltaDescription", // Template for comment node
|
275 | $(go.Node, "Auto",
|
276 | new go.Binding("location", "loc", gridPointParse),
|
277 | new go.Binding("scale", "scale"),
|
278 | { locationSpot: go.Spot.Center, portId: "NODE" },
|
279 | $(go.Shape, "RoundedRectangle",
|
280 | { fill: "white", portId: "SHAPE" },
|
281 | new go.Binding("fill", "color"),
|
282 | new go.Binding("strokeWidth", "strokeW")),
|
283 | $(go.Panel, "Vertical",
|
284 | $(go.TextBlock,
|
285 | {font: "bold 11pt sans-serif", margin: new go.Margin(3, 0, 0, 0)},
|
286 | new go.Binding("text", "header"),
|
287 | new go.Binding("stroke", "textColor")),
|
288 | $(go.TextBlock,
|
289 | { margin: 3, portId: "TEXTBLOCK", alignment: go.Spot.Left },
|
290 | new go.Binding("text", "text"),
|
291 | new go.Binding("stroke", "textColor")),
|
292 | $(go.TextBlock,
|
293 | { margin: 3, portId: "TEXTBLOCK", font: "italic 10pt sans-serif" },
|
294 | new go.Binding("text", "desc"),
|
295 | new go.Binding("stroke", "textColor"))
|
296 | )
|
297 | ));
|
298 |
|
299 | diagram.nodeTemplateMap.add("Point", // template for denoting points on the grid
|
300 | $(go.Node, "Vertical",
|
301 | { movable: false },
|
302 | new go.Binding("location", "point", function gridPointLocation(point) {
|
303 | label = point.label;
|
304 | // measure the longest line's width
|
305 | textLines = label.split("\n");
|
306 | width = 0
|
307 | textLines.forEach(function(text) {
|
308 | var textBlock = $(go.TextBlock, { text: text, font: "bold 10pt sans-serif"});
|
309 | if (textBlock.naturalBounds.right > width) {
|
310 | width = textBlock.naturalBounds.right;
|
311 | }
|
312 | });
|
313 |
|
314 | // text block with entire string to measure height
|
315 | var textBlock = $(go.TextBlock, { text: label, font: "bold 10pt sans-serif" });
|
316 | point = new go.Point(point.x, point.y);
|
317 |
|
318 | // convert from grid coordinates to diagram coordinates
|
319 | gridPointParse(point);
|
320 |
|
321 | // offset
|
322 | point.setTo(point.x - width / 2, point.y - pointSize / 2 - textBlock.naturalBounds.bottom); // align to center of circle to intersection instead of top left corner
|
323 | return point;
|
324 | }),
|
325 |
|
326 | $(go.TextBlock,
|
327 | {position: new go.Point(0, -pointSize - 7), textAlign: "center", font : "bold 10pt sans-serif"},
|
328 | new go.Binding("text", "point", function getLabel(point) {
|
329 | return point.label;
|
330 | }), new go.Binding("margin", "margin")),
|
331 | $(go.Shape,
|
332 | "Circle",
|
333 | {width: pointSize, height: pointSize, alignment: go.Spot.Center})
|
334 | ));
|
335 |
|
336 | diagram.linkTemplateMap.add("Comment", // Template for links from comments
|
337 | $(go.Link,
|
338 | { curve: go.Link.Bezier },
|
339 | new go.Binding("curviness"),
|
340 | new go.Binding("fromSpot", "fromSpot"),
|
341 | new go.Binding("toSpot", "toSpot"),
|
342 | $(go.Shape, { stroke: commentStroke },
|
343 | new go.Binding("stroke", "stroke")),
|
344 | $(go.Shape, { toArrow: "OpenTriangle", stroke: commentStroke },
|
345 | new go.Binding("stroke", "stroke"))
|
346 | ));
|
347 |
|
348 | diagram.groupTemplateMap.add("Grid",
|
349 | $(go.Group, "Position",
|
350 | { movable: false },
|
351 | $(go.Shape, "Rectangle", { fill: "transparent", strokeWidth: 2},
|
352 | new go.Binding("fill", "fill"),
|
353 | new go.Binding("stroke", "border"),
|
354 | new go.Binding("desiredSize", "size", gridSizeParse).makeTwoWay(go.Size.stringify)),
|
355 | $(go.Panel, "Grid",
|
356 | { name: "DOCGRID", desiredSize: cellSize, gridCellSize: new go.Size(cellSide, cellSide) },
|
357 | new go.Binding("desiredSize", "size", gridSizeParse).makeTwoWay(go.Size.stringify),
|
358 | new go.Binding("gridCellSize", "cell", go.Size.parse).makeTwoWay(go.Size.stringify),
|
359 | $(go.Shape, "LineV",
|
360 | new go.Binding("stroke")),
|
361 | $(go.Shape, "LineH",
|
362 | new go.Binding("stroke"))
|
363 | ),
|
364 | new go.Binding("location", "loc", gridPointParse)
|
365 | ));
|
366 |
|
367 | diagram.initialContentAlignment = go.Spot.Center;
|
368 |
|
369 | var model = new go.GraphLinksModel();
|
370 | model.linkFromPortIdProperty = "fPID";
|
371 | model.linkToPortIdProperty = "tPID"
|
372 |
|
373 | model.nodeDataArray = [
|
374 | { key: "docGrid", isGroup: true, category: "Grid", stroke: docGridStroke, fill: "transparent", size: "24 20", border: docGridStroke },
|
375 | { key: "viewGrid", isGroup: true, group: "docGrid", category: "Grid", fill: "rgb(248,248,248)",stroke: viewGridStroke, size: "13.7 9.95", loc: "5.8 5.2", cell: "25 25", border: viewGridStroke},
|
376 | { key: "alpha", group: "docGrid", text: "Alpha", loc: "1.95 6.95"},
|
377 | { key: "beta", group: "docGrid", text: "Beta", loc: "12.4 1.25"},
|
378 | { key: "gamma", group: "docGrid", text: "Gamma", loc: "10 7.95"},
|
379 | { key: "delta", group: "docGrid", text: "Delta", loc: "14.5 11.95"},
|
380 | { key: "epsilon", group: "docGrid", text: "Epsilon", loc: "7.9 17.95"},
|
381 | { key: "zeta", group: "docGrid", text: "Zeta", loc: "12.35 18.7"},
|
382 | { key: "eta", group: "docGrid", text: "Eta", loc: "22.5 11.95"},
|
383 | { key: "point1", group: "docGrid", category: "Point", point: LabelledPoint(5.8, 5.2, "(300, 250) Document Coordinates\n(0, 0) Viewport Coordinates")},
|
384 | { key: "point2", group: "docGrid", category: "Point", point: LabelledPoint(19.3, 14.9, "(850, 650) Document Coordinates\n(550, 400) Viewport Coordinates"), margin: new go.Margin(0, 0, 4, 0)},
|
385 | { key: "point1", group: "docGrid", category: "Point", point: LabelledPoint(0, 0, "(0, 0) Document Coordinates")},
|
386 | { key: "point1", group: "docGrid", category: "Point", point: LabelledPoint(24, 20, "(1200, 1000) Document Coordinates")},
|
387 | { key: "viewportDesc", category: "Description", header: "Viewport", text: "position: (300, 250)\nviewportBounds: (550, 400)\nscale: 1.25", textColor: "brown", loc: "0 17"},
|
388 | { key: "documentDesc", category: "Description", header: "Document", text: "documentBounds: (1200, 1000)\npadding: (5, 5, 5, 5)", textColor: "rgb(50, 120, 160)", loc: "22 -3"},
|
389 | { key: "deltaDesc", category: "DeltaDescription", header: "Delta", text: "location: (650, 550)", desc: "Location is in document\ncoordinates, and does not\nchange with viewport\nmovement or scaling.", textColor: "black", loc: "26 6"}
|
390 | ];
|
391 | model.linkDataArray = [
|
392 | { to: "viewGrid", from: "viewportDesc", category: "Comment", stroke: "brown"},
|
393 | { to: "docGrid", from: "documentDesc", category: "Comment", stroke: "rgb(50, 120, 160)"},
|
394 | { to: "delta", from: "deltaDesc", category: "Comment", stroke: "black", curviness: -10},
|
395 | { to: "gamma", from: "alpha"},
|
396 | { to: "gamma", from: "beta"},
|
397 | { to: "delta", from: "gamma"},
|
398 | { to: "epsilon", from: "delta"},
|
399 | { to: "zeta", from: "delta"},
|
400 | { to: "eta", from: "delta"}
|
401 | ];
|
402 |
|
403 | diagram.model = model;
|
404 |
|
405 |
|
406 | // Formatting
|
407 | function headerStyle() {
|
408 | return {
|
409 | margin: 3,
|
410 | font: "bold 12pt sans-serif",
|
411 | minSize: new go.Size(140, 16),
|
412 | maxSize: new go.Size(120, NaN),
|
413 | textAlign: "center"
|
414 | };
|
415 | }
|
416 | function textStyle() {
|
417 | return {
|
418 | margin: 3,
|
419 | font: "italic 10pt sans-serif",
|
420 | minSize: new go.Size(16, 16),
|
421 | maxSize: new go.Size(160, NaN),
|
422 | textAlign: "left"
|
423 | };
|
424 | }
|
425 | </code></pre>
|
426 | <script>goCode("diffCoordSystems", 750, 650)</script>
|
427 |
|
428 | <h2 id="CoordinateSystemsExample">Coordinate systems example</h2>
|
429 | <p>
|
430 | This example shows three Parts at three different locations in document coordinates.
|
431 | Pass the mouse over each of the parts to see where those locations are in view coordinates.
|
432 | Initially you will see that the only difference between document and view coordinates are a constant offset.
|
433 | That offset is due to the <a>Diagram.padding</a> that puts a little space between the edge of the canvas and
|
434 | the edge of where the diagram's objects are.
|
435 | It is also due to <a>Part.locationSpot</a> having the location be at the center of the "+" Shape,
|
436 | not at the top-left corner of the whole Part.
|
437 | </p>
|
438 | <pre class="lang-js" id="coordsystems"><code>
|
439 | // read-only to avoid accidentally moving any Part in document coordinates
|
440 | diagram.isReadOnly = true;
|
441 |
|
442 | diagram.nodeTemplate =
|
443 | $(go.Part, // no links or grouping, so use the simpler Part class instead of Node
|
444 | {
|
445 | locationSpot: go.Spot.Center, locationObjectName: "SHAPE",
|
446 | layerName: "Background",
|
447 | mouseOver: function (e, obj) { showPoint(obj.part.location); },
|
448 | click: function (e, obj) { showPoint(obj.part.location); }
|
449 | },
|
450 | new go.Binding("location", "loc", go.Point.parse),
|
451 | $(go.Shape, "PlusLine",
|
452 | { name: "SHAPE", width: 8, height: 8 }),
|
453 | $(go.TextBlock,
|
454 | { position: new go.Point(6, 6), font: "8pt sans-serif" },
|
455 | new go.Binding("text", "loc"))
|
456 | );
|
457 |
|
458 | diagram.model.nodeDataArray = [
|
459 | { loc: "0 0" },
|
460 | { loc: "100 0" },
|
461 | { loc: "100 50" }
|
462 | ];
|
463 |
|
464 | function showPoint(loc) {
|
465 | var docloc = diagram.transformDocToView(loc);
|
466 | var elt = document.getElementById("Message1");
|
467 | elt.textContent = "Selected node location,\ndocument coordinates: " + loc.x.toFixed(2) + " " + loc.y.toFixed(2) +
|
468 | "\nview coordinates: " + docloc.x.toFixed(2) + " " + docloc.y.toFixed(2);
|
469 | }
|
470 | // make accessible to the HTML buttons:
|
471 | myDiagram = diagram;
|
472 | </code></pre>
|
473 | <script>goCode("coordsystems", 300, 150)</script>
|
474 | <textarea id="Message1" style="width: 300px; height: 70px">(move mouse over node to see points in document and in view coordinates)</textarea>
|
475 | <input id="ZoomOut" type="button" onclick="myDiagram.commandHandler.decreaseZoom()" value="Zoom Out" />
|
476 | <input id="ZoomIn" type="button" onclick="myDiagram.commandHandler.increaseZoom()" value="Zoom In" />
|
477 | <p>
|
478 | Then try scrolling or zooming in and looking at the locations of those parts in view coordinates.
|
479 | Zooming in increases the <a>Diagram.scale</a> by a small factor.
|
480 | That changes the locations in view coordinates, even though the locations in document coordinates did not change.
|
481 | </p>
|
482 | <p class="box bg-info">
|
483 | To "move" a node one must change its <a>GraphObject.position</a> or <a>Part.location</a> in document coordinates.
|
484 | To "scroll" a diagram one must change the <a>Diagram.position</a>.
|
485 | Either way will cause a node to appear at a different point in the viewport.
|
486 | </p>
|
487 |
|
488 | <h2 id="DocumentBounds">Document bounds</h2>
|
489 | <p>
|
490 | All of the <a>Part</a>s of a diagram have positions and sizes (i.e. their <a>GraphObject.actualBounds</a>) in document coordinates.
|
491 | The union of all of those parts' actualBounds constitutes the <a>Diagram.documentBounds</a>.
|
492 | If all of the parts are close together, the document bounds might be small.
|
493 | If some or all of the parts are far apart from each other, the document bounds might be large, even if there are only two parts
|
494 | or if there is just one really large part.
|
495 | The <a>Diagram.documentBounds</a> value is independent of the <a>Diagram.viewportBounds</a>.
|
496 | The former only depends on the bounds of the parts; the latter only depends on the size of the canvas and the diagram's
|
497 | position and scale.
|
498 | </p>
|
499 | <p>
|
500 | <a>Diagram.computeBounds</a>, which is responsible for the bounds computation,
|
501 | also adds the <a>Diagram.padding</a> Margin so that no Parts appear directly up against the edge of the diagram when scrolled to that side.
|
502 | You may want to keep some parts, particularly background decorations, from being included in the document bounds computation.
|
503 | Just set <a>Part.isInDocumentBounds</a> to false for such parts.
|
504 | </p>
|
505 | <p>
|
506 | The diagram does not compute a new value for <a>Diagram.documentBounds</a> immediately upon any change to any part
|
507 | or the addition or removal of a part.
|
508 | Thus the <a>Diagram.documentBounds</a> property value may not be up-to-date until after a transaction completes.
|
509 | </p>
|
510 | <p>
|
511 | The relative sizes of the <a>Diagram.documentBounds</a> and <a>Diagram.viewportBounds</a> control whether or not
|
512 | scrollbars are needed.
|
513 | You can set <a>Diagram.hasHorizontalScrollbar</a> and/or <a>Diagram.hasVerticalScrollbar</a> to false to
|
514 | make sure no scrollbar appears even when needed.
|
515 | </p>
|
516 | <p>
|
517 | If you do not want the <a>Diagram.documentBounds</a> to always reflect the sizes and locations of all of the nodes and links,
|
518 | you can set the <a>Diagram.fixedBounds</a> property.
|
519 | However if there are any nodes that are located beyond the fixedBounds, the user may be unable to scroll the diagram to see them.
|
520 | </p>
|
521 | <p>
|
522 | If you want to be notified whenever the document bounds changes, you can register a "DocumentBoundsChanged" <a>DiagramEvent</a> listener.
|
523 | </p>
|
524 |
|
525 | <h2 id="ViewportBounds">Viewport bounds</h2>
|
526 | <p>
|
527 | The <a>Diagram.viewportBounds</a> always has x and y values that are given by the <a>Diagram.position</a>.
|
528 | It always has width and height values that are computed from the canvas size and the <a>Diagram.scale</a>.
|
529 | </p>
|
530 | <p>
|
531 | Users can scroll the document contents using keyboard commands, scrollbars or panning.
|
532 | Programmatically, you can scroll using several means:
|
533 | </p>
|
534 | <ul>
|
535 | <li>setting <a>Diagram.position</a></li>
|
536 | <li>calling <a>Diagram.scrollToRect</a> or <a>Diagram.centerRect</a> or <a>Diagram.scroll</a></li>
|
537 | <li>calling <a>Diagram.alignDocument</a></li>
|
538 | <li>setting <a>Diagram.contentAlignment</a></li>
|
539 | <li>calling <a>CommandHandler.scrollToPart</a></li>
|
540 | </ul>
|
541 | <p>
|
542 | Furthermore, scrolling may happen automatically as nodes or links are added to or removed from or change visibility in the diagram.
|
543 | Also, zooming will typically result in scrolling as well.
|
544 | </p>
|
545 | <p>
|
546 | When scrolling, the <a>Diagram.position</a> normally will be limited to the range specified by the <a>Diagram.documentBounds</a>.
|
547 | The short or "line" scrolling distance is controlled by <a>Diagram.scrollHorizontalLineChange</a> and <a>Diagram.scrollVerticalLineChange</a>.
|
548 | The long or "page" scrolling distance is controlled by the size of the viewport.
|
549 | If you want to control the precise values that the <a>Diagram.position</a> may have,
|
550 | you can specify a <a>Diagram.positionComputation</a> function. See the example below.
|
551 | </p>
|
552 | <p>
|
553 | User can zoom in or out using keyboard commands, mouse wheel, or pinching.
|
554 | Programmatically, you can zoom using several means:
|
555 | </p>
|
556 | <ul>
|
557 | <li>setting <a>Diagram.scale</a></li>
|
558 | <li>calling <a>Diagram.zoomToFit</a> or <a>Diagram.zoomToRect</a></li>
|
559 | <li>setting <a>Diagram.autoScale</a></li>
|
560 | <li>calling <a>CommandHandler.decreaseZoom</a>, <a>CommandHandler.increaseZoom</a>, <a>CommandHandler.resetZoom</a>, or
|
561 | <a>CommandHandler.zoomToFit</a></li>
|
562 | </ul>
|
563 | <p>
|
564 | When zooming in or out, the <a>Diagram.scale</a> normally will be limited to the range given by <a>Diagram.minScale</a> and <a>Diagram.maxScale</a>.
|
565 | If you want to control the precise values that the <a>Diagram.scale</a> may have,
|
566 | you can specify a <a>Diagram.scaleComputation</a> function. See the example below.
|
567 | </p>
|
568 | <p>
|
569 | If you want to be notified whenever the viewport bounds changes, you can register a "ViewportBoundsChanged" <a>DiagramEvent</a> listener.
|
570 | </p>
|
571 |
|
572 | <h2 id="ScrollMargin">Scroll margin</h2>
|
573 | <p>
|
574 | <a>Diagram.scrollMargin</a> allows the user to scroll into empty space at the edges of the viewport,
|
575 | when the document bounds (including its <a>Diagram.padding</a> margin) is greater than the viewport bounds.
|
576 | This can be useful when users need extra space at the edges of a Diagram,
|
577 | for instance to have an area to create new nodes with the <a>ClickCreatingTool</a>.
|
578 | </p>
|
579 | <p>
|
580 | <a>Diagram.padding</a> is added as if part of the document bounds,
|
581 | whereas <code>scrollMargin</code> makes sure you can scroll to empty space beyond the document bounds.
|
582 | Because of this, <code>scrollMargin</code> does not create additional scrollable empty space if none
|
583 | is needed to scroll the margin distance beyond, such as when the document bounds are very small in the viewport.
|
584 | </p>
|
585 | <p>
|
586 | Below is a Diagram with <code>scrollMargin</code> set to <code>100</code>.
|
587 | As you drag to the boundary, you will find the additional space created by the margin.
|
588 | </p>
|
589 |
|
590 | <pre class="lang-js" id="scrollmargin" style="display: none;"><code>
|
591 | diagram.grid = $(go.Panel, "Grid",
|
592 | $(go.Shape, "LineH", { stroke: "gray", strokeWidth: 0.5 }),
|
593 | $(go.Shape, "LineH", { stroke: "darkslategray", strokeWidth: 1.5, interval: 10 }),
|
594 | $(go.Shape, "LineV", { stroke: "gray", strokeWidth: 0.5 }),
|
595 | $(go.Shape, "LineV", { stroke: "darkslategray", strokeWidth: 1.5, interval: 10 })
|
596 | );
|
597 | diagram.scrollMargin = 100;
|
598 |
|
599 | diagram.nodeTemplate =
|
600 | $(go.Node, "Auto",
|
601 | $(go.Shape, "RoundedRectangle",
|
602 | new go.Binding("fill", "color")),
|
603 | $(go.TextBlock,
|
604 | { margin: 3 },
|
605 | new go.Binding("text", "key"))
|
606 | );
|
607 |
|
608 | var nodes = [];
|
609 | for (var i = 0; i < 99; i++) {
|
610 | nodes.push({ key: "Alpha", color: "lightblue" });
|
611 | }
|
612 | diagram.model = new go.GraphLinksModel(nodes,[]);
|
613 |
|
614 | </code></pre>
|
615 | <script>goCode("scrollmargin", 400, 400)</script>
|
616 |
|
617 |
|
618 | <h2 id="ScrollingModes">Scrolling modes</h2>
|
619 | <p>
|
620 | <a>Diagram.scrollMode</a> allows the user to either scroll to document bound borders with <a>Diagram,DocumentScroll</a> (the default),
|
621 | or scroll endlessly with <a>Diagram,InfiniteScroll</a>.
|
622 | </p>
|
623 | <p>
|
624 | <a>Diagram.positionComputation</a> and <a>Diagram.scaleComputation</a> allow you to determine what positions
|
625 | and scales are acceptable to be scrolled to.
|
626 | For instance, you could allow only integer position values, or only allow scaling to the values of 0.5, 1, or 2.
|
627 | </p>
|
628 | <p>
|
629 | The <a href="../samples/scrollModes.html">Scroll Modes sample</a> displays all the code for the example below,
|
630 | which lets you toggle these three properties.
|
631 | </p>
|
632 |
|
633 | <pre class="lang-js" id="scrollmodes" style="display: none;"><code>
|
634 | diagram.minScale = 0.25;
|
635 | diagram.grid = $(go.Panel, "Grid",
|
636 | $(go.Shape, "LineH", { stroke: "gray", strokeWidth: 0.5 }),
|
637 | $(go.Shape, "LineH", { stroke: "darkslategray", strokeWidth: 1.5, interval: 10 }),
|
638 | $(go.Shape, "LineV", { stroke: "gray", strokeWidth: 0.5 }),
|
639 | $(go.Shape, "LineV", { stroke: "darkslategray", strokeWidth: 1.5, interval: 10 })
|
640 | );
|
641 | diagram.toolManager.draggingTool.isGridSnapEnabled = true;
|
642 | diagram.undoManager.isEnabled = true;
|
643 |
|
644 |
|
645 | diagram.nodeTemplate =
|
646 | $(go.Node, "Auto",
|
647 | $(go.Shape, "RoundedRectangle",
|
648 | new go.Binding("fill", "color")),
|
649 | $(go.TextBlock,
|
650 | { margin: 3 },
|
651 | new go.Binding("text", "key"))
|
652 | );
|
653 |
|
654 | // create the model data that will be represented by Nodes and Links
|
655 | diagram.model = new go.GraphLinksModel(
|
656 | [
|
657 | { key: "Alpha", color: "lightblue" },
|
658 | { key: "Beta", color: "orange" },
|
659 | { key: "Gamma", color: "lightgreen" },
|
660 | { key: "Delta", color: "pink" }
|
661 | ],
|
662 | [
|
663 | { from: "Alpha", to: "Beta" },
|
664 | { from: "Alpha", to: "Gamma" },
|
665 | { from: "Gamma", to: "Delta" },
|
666 | { from: "Delta", to: "Alpha" }
|
667 | ]);
|
668 |
|
669 | // make accessible to the HTML buttons
|
670 | myDiagram2 = diagram;
|
671 | </code></pre>
|
672 | <script>goCode("scrollmodes", 400, 400)</script>
|
673 | <p>
|
674 | <label><input id="infscroll" type="checkbox" />Enable Infinite Scrolling, setting <a>Diagram.scrollMode</a></label>
|
675 | </p>
|
676 | <pre class="lang-js"><code>
|
677 | myDiagram.scrollMode = checked ? go.Diagram.InfiniteScroll : go.Diagram.DocumentScroll;
|
678 | </code></pre>
|
679 |
|
680 | <p>
|
681 | <label><input id="poscomp" type="checkbox" />Enable <a>Diagram.positionComputation</a> function</label>
|
682 | </p>
|
683 | <pre class="lang-js"><code>
|
684 | function positionfunc(diagram, pos) {
|
685 | var size = diagram.grid.gridCellSize;
|
686 | return new go.Point(
|
687 | Math.round(pos.x / size.width) * size.width,
|
688 | Math.round(pos.y / size.height) * size.height);
|
689 | }
|
690 | </code></pre>
|
691 |
|
692 | <p>
|
693 | <label><input id="scalecomp" type="checkbox" />Enable <a>Diagram.scaleComputation</a> function</label>
|
694 | </p>
|
695 | <pre class="lang-js"><code>
|
696 | function scalefunc(diagram, scale) {
|
697 | var oldscale = diagram.scale;
|
698 | if (scale > oldscale) {
|
699 | return oldscale + 0.25;
|
700 | } else if (scale < oldscale) {
|
701 | return oldscale - 0.25;
|
702 | }
|
703 | return oldscale;
|
704 | }
|
705 | </code></pre>
|
706 | <script type="text/javascript">
|
707 | function positionfunc(diagram, pos) {
|
708 | var size = diagram.grid.gridCellSize;
|
709 | return new go.Point(
|
710 | Math.round(pos.x / size.width) * size.width,
|
711 | Math.round(pos.y / size.height) * size.height);
|
712 | }
|
713 |
|
714 | function scalefunc(diagram, scale) {
|
715 | var oldscale = diagram.scale;
|
716 | if (scale > oldscale) {
|
717 | return oldscale + 0.25;
|
718 | } else if (scale < oldscale) {
|
719 | return oldscale - 0.25;
|
720 | }
|
721 | return oldscale;
|
722 | }
|
723 |
|
724 | var infscroll = document.getElementById('infscroll');
|
725 | infscroll.addEventListener('change', function(e) {
|
726 | myDiagram2.commit(function(d) { d.scrollMode = infscroll.checked ? go.Diagram.InfiniteScroll : go.Diagram.DocumentScroll; });
|
727 | });
|
728 |
|
729 | var poscomp = document.getElementById('poscomp');
|
730 | poscomp.addEventListener('change', function(e) {
|
731 | myDiagram2.commit(function(d) { d.positionComputation = poscomp.checked ? positionfunc : null; });
|
732 | });
|
733 |
|
734 | var scalecomp = document.getElementById('scalecomp');
|
735 | scalecomp.addEventListener('change', function(e) {
|
736 | myDiagram2.commit(function(d) { d.scaleComputation = scalecomp.checked ? scalefunc : null; });
|
737 | });
|
738 | </script>
|
739 |
|
740 | <h2 id="PanelCoordinates">Panel coordinates</h2>
|
741 | <p>
|
742 | A <a>GraphObject</a> that is not a <a>Part</a> but is an element of a <a>Panel</a> has measurements
|
743 | that are in panel coordinates, not in document coordinates.
|
744 | That means that <a>GraphObject.position</a>, <a>GraphObject.actualBounds</a>, <a>GraphObject.maxSize</a>,
|
745 | <a>GraphObject.minSize</a>, <a>GraphObject.measuredBounds</a>, <a>GraphObject.margin</a>, and
|
746 | <a>RowColumnDefinition</a> properties apply to all elements of a panel using the same coordinate system.
|
747 | </p>
|
748 | <p>
|
749 | Some <a>GraphObject</a> properties use units that have values before they are transformed for use by
|
750 | the containing <a>Panel</a>'s coordinate system.
|
751 | In particular, <a>GraphObject.desiredSize</a> (which means <a>GraphObject.width</a> and <a>GraphObject.height</a>),
|
752 | <a>GraphObject.naturalBounds</a>, <a>Shape.geometry</a>, and <a>Shape.strokeWidth</a> are in "local" coordinates,
|
753 | before the object is scaled and rotated by the value of <a>GraphObject.scale</a> and <a>GraphObject.angle</a>.
|
754 | </p>
|
755 | <p>
|
756 | <a>GraphObject.actualBounds</a> will tell you the position and size of an element within its panel.
|
757 | If you want to get the document position of some object that is within a Node,
|
758 | call <a>GraphObject.getDocumentPoint</a>.
|
759 | </p>
|
760 | <p>
|
761 | For examples of the sizes of elements in a panel, see <a href="sizing.html">Sizing GraphObjects</a>.
|
762 | </p>
|
763 |
|
764 | <h3 id="NestedPanelCoordinates">Nested Panel coordinates</h3>
|
765 | <pre class="lang-js" id="nestedpanelcoords" style="display: none;"><code>
|
766 | // read-only to avoid accidentally moving any Part in document coordinates
|
767 | diagram.isReadOnly = true;
|
768 | diagram.allowSelect = false;
|
769 | diagram.initialPosition = new go.Point(-5, -5);
|
770 | diagram.initialScale = 0.45;
|
771 |
|
772 | // data objects for data tables.
|
773 | function InfoBox(key,gro,loc) {
|
774 | this.category = "info";
|
775 | this.key = key;
|
776 | this.location = go.Point.parse(loc);
|
777 | this.gro = gro;
|
778 | }
|
779 |
|
780 | // alignment properties for TextBlocks in data tables.
|
781 | function AlignmentObject(column,columnSpan) {
|
782 | this.column = column;
|
783 | this.columnSpan = columnSpan;
|
784 | this.verticalAlignment = go.Spot.Center;
|
785 | this.textAlign = "center";
|
786 | this.alignment = go.Spot.Center;
|
787 | this.height = 24;
|
788 | }
|
789 |
|
790 | // creates functions which have limited precision return values.
|
791 | function prec(conv) { return function (g) { return conv(g).toPrecision(3) }}
|
792 |
|
793 | // generates cells in data tables
|
794 | function dataBlock(conv, alo1, alo2) {
|
795 | return $(go.TextBlock, "", new go.Binding("text", "gro", prec(conv)), new AlignmentObject(alo1, alo2));
|
796 | }
|
797 |
|
798 | var nodeTemplates = new go.Map();
|
799 |
|
800 | // Template for data tables
|
801 | nodeTemplates.add("info",
|
802 | $(go.Node, "Auto",
|
803 | // Allows location to be set in data object
|
804 | new go.Binding("location"), { padding: 0, scale: 2 },
|
805 | $(go.Panel, "Table",
|
806 | {name: "table",
|
807 | defaultRowSeparatorStroke: "black", defaultColumnSeparatorStroke: "black",
|
808 | defaultAlignment: go.Spot.Center, background: "white"
|
809 | },
|
810 | // sets a different look for the defining row.
|
811 | $(go.RowColumnDefinition,
|
812 | {row: 0,
|
813 | background: "lightgray", separatorStrokeWidth: 0,
|
814 | separatorPadding: 0, coversSeparators: true,
|
815 | height: 24
|
816 | }),
|
817 | // sets a different look for the defining column.
|
818 | $(go.RowColumnDefinition,
|
819 | {column: 0,
|
820 | coversSeparators: true, separatorStrokeWidth: 0,
|
821 | separatorPadding: 0, background: "lightgray",
|
822 | width: 45
|
823 | }),
|
824 | // necessary to keep weirdness involving the columnSpan of certain elements in the table
|
825 | // from causing separators to go through elements.
|
826 | $(go.RowColumnDefinition, {column: 1, width: 28}),
|
827 | $(go.RowColumnDefinition, {column: 2, separatorStroke: "transparent", width: 28}),
|
828 | $(go.RowColumnDefinition, {column: 3, width: 28}),
|
829 | $(go.RowColumnDefinition, {column: 4, separatorStroke: "transparent", width: 28}),
|
830 | // defining row
|
831 | $(go.Panel, "TableRow", {row: 0},
|
832 | $(go.TextBlock, "Container", new AlignmentObject(1,2)),
|
833 | $(go.TextBlock, "Diagram", new AlignmentObject(3,2))),
|
834 |
|
835 | // angle row
|
836 | $(go.Panel, "TableRow", {row: 1},
|
837 | $(go.TextBlock, "angle", {column: 0}),
|
838 | // container angle
|
839 | dataBlock(function (g) { return g.angle }, 1, 2),
|
840 | // document angle
|
841 | dataBlock(function (g) { return g.getDocumentAngle() }, 3, 2)),
|
842 |
|
843 | // scale row
|
844 | $(go.Panel, "TableRow", {row: 2},
|
845 | $(go.TextBlock, "scale", {column: 0}),
|
846 | // container scale
|
847 | dataBlock(function (g) { return g.scale }, 1, 2),
|
848 | // document scale
|
849 | dataBlock(function (g) { return g.getDocumentScale() }, 3, 2)),
|
850 |
|
851 | // position row
|
852 | $(go.Panel, "TableRow", {row: 3},
|
853 |
|
854 | $(go.TextBlock, "X Y", {column: 0}),
|
855 |
|
856 | // container x and y values
|
857 | dataBlock(function (g) { return g.actualBounds.x }, 1, 1),
|
858 | dataBlock(function (g) { return g.actualBounds.y }, 2, 1),
|
859 |
|
860 | // document x and y values
|
861 | dataBlock(function (g) { return g.getDocumentBounds().x }, 3, 1),
|
862 | dataBlock(function (g) { return g.getDocumentBounds().y }, 4, 1)),
|
863 |
|
864 | // dimension row
|
865 | $(go.Panel, "TableRow", {row: 4},
|
866 | $(go.TextBlock, "size", {column: 0}),
|
867 |
|
868 | // container width and height
|
869 | dataBlock(function (g) { return g.actualBounds.width }, 1, 1),
|
870 | dataBlock(function (g) { return g.actualBounds.height }, 2, 1),
|
871 |
|
872 | // document width and height
|
873 | dataBlock(function (g) { return g.getDocumentBounds().width }, 3, 1),
|
874 | dataBlock(function (g) { return g.getDocumentBounds().width }, 4, 1)))));
|
875 |
|
876 |
|
877 | // data object for labels on data tables
|
878 | function WordBubble(key,width,loc,desc,color) {
|
879 | this.key = key; this.category = "words"; this.width = width;
|
880 | this.desc = desc; this.location = go.Point.parse(loc); this.color = color;
|
881 | }
|
882 |
|
883 | // template for wordbubble objects
|
884 | nodeTemplates.add("words",
|
885 | $(go.Node, "Auto",
|
886 | new go.Binding("location"),
|
887 | $(go.TextBlock, "",
|
888 | new go.Binding("text", "desc"),
|
889 | new go.Binding("stroke","color"),
|
890 | new go.Binding("width"),
|
891 | { textAlign: "left", font: "24pt sans-serif" })));
|
892 |
|
893 | // creating the main node's template, adding the nested Panels to it, and adding it to the node template map.
|
894 | let vertPanel = posPanel = spotPanel = vertLabel = topLabel = {};
|
895 | var BigNode =
|
896 | $(go.Node, "Auto",
|
897 | {
|
898 | location: new go.Point(300,0),
|
899 | },
|
900 | vertPanel =
|
901 | $(go.Panel, "Vertical",
|
902 | {portId: "vertPanel",
|
903 | angle: 165, scale: 1.5,
|
904 | background: "lightblue",
|
905 | padding: 20
|
906 | },
|
907 | vertLabel =
|
908 | $(go.TextBlock, "Vertical Panel", {font: "bold 12pt sans-serif"}),
|
909 | posPanel =
|
910 | $(go.Panel, "Position",
|
911 | {portId: "posPanel",
|
912 | angle: 120, scale: 0.8, padding: 50,
|
913 | background: go.Brush.mix("brown", "lightyellow", 0.4)},
|
914 | $(go.Panel, "Auto", { position: new go.Point(25,0), desiredSize: new go.Size(60,90)},
|
915 | $(go.Shape, "Triangle", { fill: "transparent" }),
|
916 | $(go.TextBlock, "This Side Up")),
|
917 | $(go.TextBlock, "Position Panel", { position: new go.Point(0,100), font: "bold 12pt sans-serif" }),
|
918 | ),
|
919 | spotPanel =
|
920 | $(go.Panel, "Spot",
|
921 | {portId: "spotPanel",
|
922 | angle: 30, scale: 1.5,
|
923 | background: "lightgreen" },
|
924 | $(go.Shape, "RoundedRectangle", {strokeWidth: 0, desiredSize: new go.Size(50,100), fill: "transparent"}),
|
925 | $(go.TextBlock, "Spot Panel",
|
926 | {
|
927 | font: "bold 12pt sans-serif",
|
928 | alignment: go.Spot.Center,
|
929 | }
|
930 | ),
|
931 | $(go.TextBlock, "Top",
|
932 | {
|
933 | margin: 5,
|
934 | font: "bold 12pt sans-serif",
|
935 | alignment: go.Spot.Top,
|
936 | }
|
937 | ),
|
938 | bottomLabel =
|
939 | $(go.TextBlock, "Bottom",
|
940 | {portId: "bottomLabel",
|
941 | font: "bold 12pt sans-serif",
|
942 | alignment: go.Spot.Bottom
|
943 | }))));
|
944 | nodeTemplates.add("", BigNode);
|
945 |
|
946 | diagram.nodeTemplateMap = nodeTemplates;
|
947 |
|
948 | diagram.linkTemplate =
|
949 | $(go.Link,
|
950 | new go.Binding("fromNode", "from", diagram.findNodeForKey),
|
951 | new go.Binding("to"), new go.Binding("toPortId"),
|
952 | $(go.Shape, {strokeWidth: 5}),
|
953 | $(go.Shape, {scale: 3,toArrow: "Standard"}));
|
954 |
|
955 | diagram.model = new go.GraphLinksModel(
|
956 | [
|
957 | {key: "bn"},
|
958 | // creating infoboxes
|
959 | new InfoBox(0,vertPanel,"-20 30"),
|
960 | new InfoBox(1,posPanel,"20 470"),
|
961 | new InfoBox(2,spotPanel,"900 500"),
|
962 | new InfoBox(3,bottomLabel,"900 180"),
|
963 |
|
964 | // creating wordbubbles
|
965 | new WordBubble(4,250,"60 0","Vertical Panel","blue"),
|
966 | new WordBubble(5,250,"60 440","Position Panel","red"),
|
967 | new WordBubble(6,250,"980 470","Spot Panel","green"),
|
968 | new WordBubble(7,275,"960 105","TextBlock aligned at Spot.Bottom","black")
|
969 | ],
|
970 | [
|
971 | // linking each infobox to an item on the main node.
|
972 | {from: 0, to: "bn", toPortId: "vertPanel"},
|
973 | {from: 1, to: "bn", toPortId: "posPanel"},
|
974 | {from: 2, to: "bn", toPortId: "spotPanel"},
|
975 | {from: 3, to: "bn", toPortId: "bottomLabel"}
|
976 | ]);
|
977 | </code></pre>
|
978 | <p>
|
979 | The transformations of each element in a <a>Panel</a> are compounded by that panel's transformations.
|
980 | </p>
|
981 | <script>goCode("nestedpanelcoords", 600, 400)</script>
|
982 | <p>
|
983 | The <a>TextBlock</a> that is "Bottom" has the default <a>GraphObject.angle</a> of zero, so that the text is drawn upright.
|
984 | But that TextBlock is an element in the green "Spot" <a>Panel</a> whose <a>GraphObject.angle</a> to 30,
|
985 | so it and its text should appear somewhat tilted.
|
986 | However the blue "Vertical" Panel itself has an <a>GraphObject.angle</a> of 165.
|
987 | Because each Panel has its own coordinate system and because transformations on nested elements are compounded,
|
988 | the effective angle for the green Panel is 195 degrees, the sum of those individual angles (30 + 165), which is nearly upside down.
|
989 | </p>
|
990 | <p>
|
991 | The <a>GraphObject.scale</a> property also affects how an object is sized in its container Panel.
|
992 | The brown "Position" <a>Panel</a> has a scale of 0.8 relative to its container.
|
993 | But because the "Vertical" Panel has a scale of 1.5, its effective scale is 1.2 overall,
|
994 | the product of those individual scales (0.8 x 1.5).
|
995 | </p>
|
996 | </div>
|
997 | </div>
|
998 |
|
999 | <div class="bg-nwoods-primary">
|
1000 | <section class="max-w-screen-lg text-white container mx-auto py-2 px-12">
|
1001 | <p id="version" class="leading-none mb-2 my-4">GoJS</p>
|
1002 | </section>
|
1003 | </div><footer class="bg-nwoods-primary text-white">
|
1004 | <div class="container max-w-screen-lg mx-auto px-8">
|
1005 | <div class="w-full py-6">
|
1006 |
|
1007 | <div class="max-w-screen-lg xl:max-w-screen-xl mx-auto px-4 sm:px-6 md:px-8">
|
1008 | <ul class="text-sm font-medium pb-14 sm:pb-20 grid grid-cols-1 sm:grid-cols-3 gap-y-10">
|
1009 | <li class="list-none row-span-2">
|
1010 | <h2 class="text-base font-semibold tracking-wide">GoJS</h2>
|
1011 | <ul class="list-none space-y-4 md:space-y-1 px-0">
|
1012 | <li>
|
1013 | <a href="../samples/index.html">Samples</a>
|
1014 | </li>
|
1015 | <li>
|
1016 | <a href="../learn/index.html">Learn</a>
|
1017 | </li>
|
1018 | <li>
|
1019 | <a href="../intro/index.html">Intro</a>
|
1020 | </li>
|
1021 | <li>
|
1022 | <a href="../api/index.html">API</a>
|
1023 | </li>
|
1024 | <li>
|
1025 | <a href="../changelog.html">Changelog</a>
|
1026 | </li>
|
1027 | <li>
|
1028 | <a href="https://github.com/NorthwoodsSoftware/GoJS">GitHub</a>
|
1029 | </li>
|
1030 | </ul>
|
1031 | </li>
|
1032 | <li class="list-none row-span-2">
|
1033 | <h2 class="text-base font-semibold tracking-wide">Support</h2>
|
1034 | <ul class="list-none space-y-4 md:space-y-1 px-0">
|
1035 | <li>
|
1036 | <a href="https://www.nwoods.com/contact.html"
|
1037 | target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a>
|
1038 | </li>
|
1039 | <li>
|
1040 | <a href="https://forum.nwoods.com/c/gojs">Forum</a>
|
1041 | </li>
|
1042 | <li>
|
1043 | <a href="https://www.nwoods.com/app/activate.aspx?sku=gojs">Activate</a>
|
1044 | </li>
|
1045 | <li>
|
1046 | <a href="https://www.nwoods.com/sales/index.html"
|
1047 | target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a>
|
1048 | </li>
|
1049 | <li>
|
1050 | <a href="https://www.youtube.com/channel/UC9We8EoX596-6XFjJDtZIDg">Videos</a>
|
1051 | </li>
|
1052 | </ul>
|
1053 | </li>
|
1054 | <li class="list-none row-span-2">
|
1055 | <h2 class="text-base font-semibold tracking-wide">Company</h2>
|
1056 | <ul class="list-none space-y-4 md:space-y-1 px-0">
|
1057 | <li>
|
1058 | <a href="https://www.nwoods.com">Northwoods</a>
|
1059 | </li>
|
1060 | <li>
|
1061 | <a href="https://www.nwoods.com/about.html">About Us</a>
|
1062 | </li>
|
1063 | <li>
|
1064 | <a href="https://www.nwoods.com/contact.html">Contact Us</a>
|
1065 | </li>
|
1066 | <li>
|
1067 | <a href="https://twitter.com/northwoodsgo">Twitter</a>
|
1068 | </li>
|
1069 |
|
1070 | </ul>
|
1071 | </li>
|
1072 | </ul>
|
1073 |
|
1074 |
|
1075 | <p class="text-sm text-gray-100 md:mb-6">
|
1076 | Copyright 1998-2021 <a class="text-white" href="https://www.nwoods.com">Northwoods Software</a>
|
1077 | </p>
|
1078 | </div>
|
1079 | </div>
|
1080 | </footer> </body>
|
1081 |
|
1082 | <script async src="https://www.googletagmanager.com/gtag/js?id=UA-1506307-5"></script>
|
1083 | <script>
|
1084 | window.dataLayer = window.dataLayer || [];
|
1085 | function gtag(){dataLayer.push(arguments);}
|
1086 | gtag('js', new Date()); gtag('config', 'UA-1506307-5');
|
1087 | var getOutboundLink = function(url, label) {
|
1088 | gtag('event', 'click', {
|
1089 | 'event_category': 'outbound',
|
1090 | 'event_label': label,
|
1091 | 'transport_type': 'beacon'
|
1092 | });
|
1093 | }
|
1094 |
|
1095 |
|
1096 | var topButton = document.getElementById("topnavButton");
|
1097 | var topnavList = document.getElementById("topnavList");
|
1098 | topButton.addEventListener("click", function() {
|
1099 | this.classList.toggle("active");
|
1100 | topnavList.classList.toggle("hidden");
|
1101 | document.getElementById("topnavOpen").classList.toggle("hidden");
|
1102 | document.getElementById("topnavClosed").classList.toggle("hidden");
|
1103 | });
|
1104 | </script>
|
1105 | <script src="../assets/js/prism.js"></script>
|
1106 | <script src="../release/go.js"></script>
|
1107 | <script src="../assets/js/goDoc.js"></script>
|
1108 | <script>
|
1109 | document.addEventListener("DOMContentLoaded", function() {
|
1110 | if (window.go) document.getElementById('version').textContent = "GoJS version " + go.version;
|
1111 | if (window.goDoc) window.goDoc();
|
1112 | var d = window.diagrams;
|
1113 | for (var i = 0; i < d.length; i++) {
|
1114 | var dargs = d[i];
|
1115 | goCodeExecute(dargs[0], dargs[1], dargs[2], dargs[3], dargs[4]);
|
1116 | }
|
1117 | if (window.extra) window.extra();
|
1118 | });
|
1119 | </script>
|
1120 | </html>
|