-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathviewport.html
361 lines (336 loc) · 16.1 KB
/
viewport.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GoJS Coordinate Systems-- Northwoods Software</title>
<!-- Copyright 1998-2016 by Northwoods Software Corporation. -->
<script src="go.js"></script>
<script src="goIntro.js"></script>
</head>
<body onload="goIntro()">
<div id="container" class="container-fluid">
<div id="content">
<h2>Coordinate Systems</h2>
<p>
A <a>Diagram</a> uses two major coordinate systems when drawing <a>Part</a>s: document and view coordinates.
Furthermore each <a>Panel</a> within a <a>Part</a> has its own coordinate system that its elements use.
</p>
<p>
All coordinate systems in <b>GoJS</b> have <a>Point</a>s with increasing values of X going rightwards and
increasing values of Y going downwards.
</p>
<h3>Document and View coordinates</h3>
<p>
The <a>Part.location</a> and <a>GraphObject.actualBounds</a> and <a>GraphObject.position</a> of Parts are in document coordinates.
Thus the <a>Point</a>s that may be saved in the model's node data are normally in document coordinates:
</p>
<pre>
diagram.model.nodeDataArray = [
{ key: "Alpha", loc: "0 0" },
{ key: "Beta", loc: "100 50" }
];
</pre>
<p>
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
the HTML Div element that the user sees in the page.
When the user scrolls the diagram the part will need to be drawn elsewhere on the canvas.
And if the user zooms in to make the parts appear larger, the parts will be drawn at different points in the canvas.
Yet the <a>Part.location</a> does not change value as the user scrolls or zooms the diagram.
</p>
<p>
Points in the canvas are in view coordinates: distances from the top-left corner in device-independent pixels.
The differences between document coordinates and view coordinates are primarily controlled by two <a>Diagram</a> properties:
<a>Diagram.position</a> and <a>Diagram.scale</a>.
Scrolling and panning change the Diagram.position.
Zooming in or out changes the Diagram.scale.
You can also convert between coordinate systems by calling <a>Diagram.transformDocToView</a> and <a>Diagram.transformViewToDoc</a>.
However very few properties and method arguments or return values are in view coordinates -- almost everything is in document
coordinates or in panel coordinates.
</p>
<p>
The <i>viewport</i> is the area of the document that is visible in the canvas.
That area is available as the <a>Diagram.viewportBounds</a>.
Note that the viewport bounds is in document coordinates, not in view coordinates!
The top-left corner of the viewport is (0,0) in view coordinates but is at <a>Diagram.position</a> in document coordinates.
The bottom-right corner of the viewport is at the canvas's (width,height) in view coordinates.
The bottom-right corner of the viewport in document coordinates depends on the <a>Diagram.scale</a>.
</p>
<p>
As an example of showing the viewport in the context of the whole document, an <a>Overview</a> does exactly that.
Take a look at the overview that is in the <a href="../samples/orgChartStatic.html">Org Chart sample</a>.
The overview shows the whole document of the main diagram.
The magenta box shows the main diagram's viewport within the whole document.
As you scroll or pan the main diagram, the viewport moves.
As you zoom out, the viewport gets larger.
</p>
<h3>Coordinate systems example</h3>
<p>
This example shows three Parts at three different locations in document coordinates.
Pass the mouse over each of the parts to see where those locations are in view coordinates.
Initially you will see that the only difference between document and view coordinates are a constant offset.
That offset is due to the <a>Diagram.padding</a> that puts a little space between the edge of the canvas and
the edge of where the diagram's objects are.
It is also due to <a>Part.locationSpot</a> having the location be at the center of the "+" Shape,
not at the top-left corner of the whole Part.
</p>
<pre data-language="javascript" id="coordsystems">
// read-only to avoid accidentally moving any Part in document coordinates
diagram.isReadOnly = true;
diagram.nodeTemplate =
$(go.Part, // no links or grouping, so use the simpler Part class instead of Node
{
locationSpot: go.Spot.Center, locationObjectName: "SHAPE",
layerName: "Background",
mouseOver: function (e, obj) { showPoint(obj.part.location); },
click: function (e, obj) { showPoint(obj.part.location); }
},
new go.Binding("location", "loc", go.Point.parse),
$(go.Shape, "PlusLine",
{ name: "SHAPE", width: 8, height: 8 }),
$(go.TextBlock,
{ position: new go.Point(6, 6), font: "8pt sans-serif" },
new go.Binding("text", "loc"))
);
diagram.model.nodeDataArray = [
{ loc: "0 0" },
{ loc: "100 0" },
{ loc: "100 50" }
];
function showPoint(loc) {
var docloc = diagram.transformDocToView(loc);
var elt = document.getElementById("Message1");
elt.textContent = "Node location, document coordinates: " + loc.x.toFixed(2) + " " + loc.y.toFixed(2) +
" view coordinates: " + docloc.x.toFixed(2) + " " + docloc.y.toFixed(2);
}
myDiagram = diagram; // make accessible to the HTML buttons
</pre>
<script>goCode("coordsystems", 300, 150)</script>
<input id="ZoomOut" type="button" onclick="myDiagram.commandHandler.decreaseZoom()" value="Zoom Out" />
<input id="ZoomIn" type="button" onclick="myDiagram.commandHandler.increaseZoom()" value="Zoom In" />
<span id="Message1">(object location in document and in view coordinates)</span>
<p>
Then try zooming in and looking at the locations of those parts in view coordinates.
Zooming in increases the <a>Diagram.scale</a> by a small factor.
That changes the locations in view coordinates, even though the locations in document coordinates did not change.
</p>
<h3>Document bounds</h3>
<p>
All of the <a>Part</a>s of a diagram have positions and sizes (i.e. their <a>GraphObject.actualBounds</a>) in document coordinates.
The union of all of those parts' actualBounds constitutes the <a>Diagram.documentBounds</a>.
If all of the parts are close together, the document bounds might be small.
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
or if there is just one really large part.
The <a>Diagram.documentBounds</a> value is independent of the <a>Diagram.viewportBounds</a>.
The former only depends on the bounds of the parts; the latter only depends on the size of the canvas and the diagram's
position and scale.
</p>
<p>
<a>Diagram.computeBounds</a>, which is responsible for the bounds computation,
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.
You may want to keep some parts, particularly background decorations, from being included in the document bounds computation.
Just set <a>Part.isInDocumentBounds</a> to false for such parts.
</p>
<p>
The diagram does not compute a new value for <a>Diagram.documentBounds</a> immediately upon any change to any part
or the addition or removal of a part.
Thus the <a>Diagram.documentBounds</a> property value may not be up-to-date until after a transaction completes.
</p>
<p>
The relative sizes of the <a>Diagram.documentBounds</a> and <a>Diagram.viewportBounds</a> control whether or not
scrollbars are needed.
You can set <a>Diagram.hasHorizontalScrollbar</a> and/or <a>Diagram.hasVerticalScrollbar</a> to false to
make sure no scrollbar appears even when needed.
</p>
<p>
If you do not want the <a>Diagram.documentBounds</a> to always reflect the sizes and locations of all of the nodes and links,
you can set the <a>Diagram.fixedBounds</a> property.
However if there are any nodes that are located beyond the fixedBounds, the user may be unable to scroll the diagram to see them.
</p>
<p>
If you want to be notified whenever the document bounds changes, you can register a "DocumentBoundsChanged" <a>DiagramEvent</a> listener.
</p>
<h3>Viewport bounds</h3>
<p>
The <a>Diagram.viewportBounds</a> always has x and y values that are given by the <a>Diagram.position</a>.
It always has width and height values that are computed from the canvas size and the <a>Diagram.scale</a>.
</p>
<p>
Users can scroll the document contents using keyboard commands, scrollbars or panning.
Programmatically, you can scroll using several means:
</p>
<ul>
<li>setting <a>Diagram.position</a></li>
<li>calling <a>Diagram.scrollToRect</a> or <a>Diagram.centerRect</a> or <a>Diagram.scroll</a></li>
<li>calling <a>Diagram.alignDocument</a></li>
<li>setting <a>Diagram.contentAlignment</a></li>
<li>calling <a>CommandHandler.scrollToPart</a></li>
</ul>
<p>
Furthermore, scrolling may happen automatically as nodes or links are added to or removed from or change visibility in the diagram.
Also, zooming will typically result in scrolling as well.
</p>
<p>
When scrolling, the <a>Diagram.position</a> normally will be limited to the range specified by the <a>Diagram.documentBounds</a>.
The short or "line" scrolling distance is controlled by <a>Diagram.scrollHorizontalLineChange</a> and <a>Diagram.scrollVerticalLineChange</a>.
The long or "page" scrolling distance is controlled by the size of the viewport.
If you want to control the precise values that the <a>Diagram.position</a> may have,
you can specify a <a>Diagram.positionComputation</a> function. See the example below.
</p>
<p>
User can zoom in or out using keyboard commands, mouse wheel, or pinching.
Programmatically, you can zoom using several means:
</p>
<ul>
<li>setting <a>Diagram.scale</a></li>
<li>calling <a>Diagram.zoomToFit</a> or <a>Diagram.zoomToRect</a></li>
<li>setting <a>Diagram.autoScale</a></li>
<li>calling <a>CommandHandler.decreaseZoom</a>, <a>CommandHandler.increaseZoom</a>, <a>CommandHandler.resetZoom</a>, or
<a>CommandHandler.zoomToFit</a></li>
</ul>
<p>
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>.
If you want to control the precise values that the <a>Diagram.scale</a> may have,
you can specify a <a>Diagram.scaleComputation</a> function. See the example below.
</p>
<p>
If you want to be notified whenever the viewport bounds changes, you can register a "ViewportBoundsChanged" <a>DiagramEvent</a> listener.
</p>
<h3>Scrolling modes</h3>
<p>
<a>Diagram.scrollMode</a> allows the user to either scroll to document bound borders with <a>Diagram.DocumentScroll</a> (the default), or scroll endlessly with <a>Diagram.InfiniteScroll</a>.
</p>
<p>
<a>Diagram.positionComputation</a> and <a>Diagram.scaleComputation</a> allow you to determine what positions and scales are acceptable to be scrolled to. For instance, you could allow only integer position values, or only allow scaling to the values of 0.5, 1, or 2.
</p>
<p>
The <a href="../samples/scrollModes.html">Scroll Modes sample</a> displays all the code for the example below, which lets you toggle these three properties.
</p>
<pre data-language="javascript" id="scrollmodes" style="display: none;">
diagram.minScale = 0.25;
diagram.grid = $(go.Panel, "Grid",
$(go.Shape, "LineH", { stroke: "gray", strokeWidth: 0.5 }),
$(go.Shape, "LineH", { stroke: "darkslategray", strokeWidth: 1.5, interval: 10 }),
$(go.Shape, "LineV", { stroke: "gray", strokeWidth: 0.5 }),
$(go.Shape, "LineV", { stroke: "darkslategray", strokeWidth: 1.5, interval: 10 })
);
diagram.toolManager.draggingTool.isGridSnapEnabled = true;
diagram.initialContentAlignment = go.Spot.Center;
diagram.undoManager.isEnabled = true;
diagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "RoundedRectangle",
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 3 },
new go.Binding("text", "key"))
);
// create the model data that will be represented by Nodes and Links
diagram.model = new go.GraphLinksModel(
[
{ key: "Alpha", color: "lightblue" },
{ key: "Beta", color: "orange" },
{ key: "Gamma", color: "lightgreen" },
{ key: "Delta", color: "pink" }
],
[
{ from: "Alpha", to: "Beta" },
{ from: "Alpha", to: "Gamma" },
{ from: "Gamma", to: "Delta" },
{ from: "Delta", to: "Alpha" }
]);
myDiagram2 = diagram; // make accessible to the HTML buttons
</pre>
<script>goCode("scrollmodes", 400, 400)</script>
<p>
<label><input id="infscroll" type="checkbox" />Enable Infinite Scrolling, setting <a>Diagram.scrollMode</a></label>
<pre data-language="javascript"><code>
myDiagram.scrollMode = checked ? go.Diagram.InfiniteScroll : go.Diagram.DocumentScroll;
</code></pre>
</p>
<p>
<label><input id="poscomp" type="checkbox" />Enable <a>Diagram.positionComputation</a> function</label>
<pre data-language="javascript"><code>
function positionfunc(diagram, pos) {
var size = diagram.grid.gridCellSize;
return new go.Point(
Math.round(pos.x / size.width) * size.width,
Math.round(pos.y / size.height) * size.height);
}
</code></pre>
</p>
<p>
<label><input id="scalecomp" type="checkbox" />Enable <a>Diagram.scaleComputation</a> function</label>
<pre data-language="javascript"><code>
function scalefunc(diagram, scale) {
var oldscale = diagram.scale;
if (scale > oldscale) {
return oldscale + 0.25;
} else if (scale < oldscale) {
return oldscale - 0.25;
}
return oldscale;
}
</code></pre>
</p>
<script type="text/javascript">
function positionfunc(diagram, pos) {
var size = diagram.grid.gridCellSize;
return new go.Point(
Math.round(pos.x / size.width) * size.width,
Math.round(pos.y / size.height) * size.height);
}
function scalefunc(diagram, scale) {
var oldscale = diagram.scale;
if (scale > oldscale) {
return oldscale + 0.25;
} else if (scale < oldscale) {
return oldscale - 0.25;
}
return oldscale;
}
var infscroll = document.getElementById('infscroll');
infscroll.addEventListener('change', function(e) {
myDiagram2.startTransaction('change scroll mode');
myDiagram2.scrollMode = infscroll.checked ? go.Diagram.InfiniteScroll : go.Diagram.DocumentScroll;
myDiagram2.commitTransaction('change scroll mode');
});
var poscomp = document.getElementById('poscomp');
poscomp.addEventListener('change', function(e) {
myDiagram2.startTransaction('change position computation');
myDiagram2.positionComputation = poscomp.checked ? positionfunc : null;
myDiagram2.commitTransaction('change position computation');
});
var scalecomp = document.getElementById('scalecomp');
scalecomp.addEventListener('change', function(e) {
myDiagram2.startTransaction('change scale computation');
myDiagram2.scaleComputation = scalecomp.checked ? scalefunc : null;
myDiagram2.commitTransaction('change scale computation');
});
</script>
<h3>Panel coordinates</h3>
<p>
A <a>GraphObject</a> that is not a <a>Part</a> but is an element of a <a>Panel</a> has measurements
that are in panel coordinates, not in document coordinates.
That means that <a>GraphObject.position</a>, <a>GraphObject.actualBounds</a>, <a>GraphObject.maxSize</a>,
<a>GraphObject.minSize</a>, <a>GraphObject.measuredBounds</a>, <a>GraphObject.margin</a>, and
<a>RowColumnDefinition</a> properties apply to all elements of a panel using the same coordinate system.
</p>
<p>
Some <a>GraphObject</a> properties use units that have values before they are transformed for use by
the containing <a>Panel</a>'s coordinate system.
In particular, <a>GraphObject.desiredSize</a> (which means <a>GraphObject.width</a> and <a>GraphObject.height</a>),
<a>GraphObject.naturalBounds</a>, <a>Shape.geometry</a>, and <a>Shape.strokeWidth</a> are in "local" coordinates,
before the object is scaled and rotated by the value of <a>GraphObject.scale</a> and <a>GraphObject.angle</a>.
</p>
<p>
<a>GraphObject.actualBounds</a> will tell you the position and size of an element within its panel.
If you want to get the document position of some object that is within a Node,
call <a>GraphObject.getDocumentPoint</a>.
</p>
<p>
For examples of the sizes of elements in a panel, see <a href="sizing.html">Sizing GraphObjects</a>.
</p>
</div>
</div>
</body>
</html>