368 lines
18 KiB
HTML
368 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>GoJS Shapes -- Northwoods Software</title>
|
|
<!-- Copyright 1998-2017 by Northwoods Software Corporation. -->
|
|
<script src="../release/go.js"></script>
|
|
<script src="goIntro.js"></script>
|
|
</head>
|
|
<body onload="goIntro()">
|
|
<div id="container" class="container-fluid">
|
|
<div id="content">
|
|
|
|
<h1>Shapes</h1>
|
|
<p>
|
|
Use the <a>Shape</a> class to paint a geometrical figure.
|
|
You can control what kind of shape is drawn and how it is stroked and filled.
|
|
</p>
|
|
<p>
|
|
Shapes, like <a>TextBlock</a>s and <a>Picture</a>s, are "atomic" objects -- they cannot contain any other objects.
|
|
So a Shape will never draw some text or an image.
|
|
</p>
|
|
<p>
|
|
In these simplistic demonstrations, the code programmatically creates a Part and adds it to the Diagram.
|
|
Once you learn about models and data binding you will generally not create parts (nodes or links) programmatically.
|
|
</p>
|
|
|
|
<h2 id="Figures">Figures</h2>
|
|
<p>
|
|
You can set the <a>Shape.figure</a> property to commonly named kinds of shapes.
|
|
When using <a>GraphObject.make</a>, you can pass the figure name as a string argument.
|
|
You may also need to set the <a>GraphObject.desiredSize</a> or <a>GraphObject.width</a> and <a>GraphObject.height</a> properties,
|
|
although it is also common to have the size determined by the Panel that the shape is in.
|
|
</p>
|
|
<p>
|
|
In these simplistic demonstrations, the code programmatically creates a Part and adds it to the Diagram.
|
|
Once you learn about models and data binding you will generally not create parts (nodes or links) programmatically.
|
|
</p>
|
|
<p>
|
|
Here are several of the most often used Shape figures:
|
|
</p>
|
|
<pre data-language="javascript" id="figureShapes">
|
|
diagram.add(
|
|
$(go.Part, "Horizontal",
|
|
$(go.Shape, "Rectangle",
|
|
{ width: 40, height: 60, margin: 4, fill: null }),
|
|
$(go.Shape, "RoundedRectangle",
|
|
{ width: 40, height: 60, margin: 4, fill: null }),
|
|
$(go.Shape, "Ellipse",
|
|
{ width: 40, height: 60, margin: 4, fill: null }),
|
|
$(go.Shape, "Triangle",
|
|
{ width: 40, height: 60, margin: 4, fill: null }),
|
|
$(go.Shape, "Diamond",
|
|
{ width: 40, height: 60, margin: 4, fill: null })
|
|
));
|
|
</pre>
|
|
<script>goCode("figureShapes", 600, 100)</script>
|
|
<p>
|
|
You can see all of the named geometrical figures in the
|
|
<a href="../samples/shapes.html" target="samples">shapes</a> sample.
|
|
Some of the most commonly used figures are predefined in the <b>GoJS</b> library.
|
|
But most figures are defined in the <a href="../extensions/Figures.js" target="_blank">Figures.js</a> file
|
|
in the extensions directory.
|
|
</p>
|
|
|
|
<h2 id="FillAndStrokes">Fill and Strokes</h2>
|
|
<p>
|
|
The <a>Shape.stroke</a> property specifies the brush used to draw the shape's outline.
|
|
The <a>Shape.fill</a> property specifies the brush used to fill the shape's outline.
|
|
Additional "stroke..." properties also control how the shape's outline is drawn.
|
|
The most common such property is <a>Shape.strokeWidth</a>.
|
|
</p>
|
|
<pre data-language="javascript" id="strokedShapes">
|
|
diagram.add(
|
|
$(go.Part, "Horizontal",
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4
|
|
}), // default fill and stroke are "black"
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4,
|
|
fill: "green" }),
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4,
|
|
fill: "green", stroke: null }),
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4,
|
|
fill: null, stroke: "green" }),
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4,
|
|
fill: null, stroke: "green", strokeWidth: 3 }),
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4,
|
|
fill: null, stroke: "green", strokeWidth: 6 }),
|
|
$(go.Shape, { figure: "Club", width: 40, height: 40, margin: 4,
|
|
fill: "green", background: "orange" })
|
|
));
|
|
</pre>
|
|
<script>goCode("strokedShapes", 600, 100)</script>
|
|
|
|
<p>
|
|
The <a>Shape.stroke</a> and <a>Shape.fill</a> properties take <a>Brush</a>es
|
|
but most often are given a CSS color string to denote solid color brushes.
|
|
These two properties default to a solid black brush.
|
|
However it is common to assign one of them to be either null or "transparent".
|
|
A null brush means that nothing is drawn for that stroke or fill.
|
|
A transparent brush produces the same appearance but different hit-testing behavior.
|
|
A shape with a null <a>Shape.fill</a> produces a "hollow" shape -- clicking inside
|
|
the shape will not "hit" that shape and thus not select the <a>Node</a> that that shape is in.
|
|
But a shape with a transparent fill produces a "filled" shape -- a mouse event inside the
|
|
shape will "hit" that shape.
|
|
</p>
|
|
<pre data-language="javascript" id="fill">
|
|
diagram.div.style.background = "lightgray";
|
|
diagram.add(
|
|
$(go.Part, "Table",
|
|
$(go.Shape, { row: 0, column: 0, figure: "Club", width: 60, height: 60, margin: 4,
|
|
fill: "green" }),
|
|
$(go.TextBlock, "green", { row: 1, column: 0 }),
|
|
$(go.Shape, { row: 0, column: 1, figure: "Club", width: 60, height: 60, margin: 4,
|
|
fill: "white" }),
|
|
$(go.TextBlock, "white", { row: 1, column: 1 }),
|
|
$(go.Shape, { row: 0, column: 2, figure: "Club", width: 60, height: 60, margin: 4,
|
|
fill: "transparent" }),
|
|
$(go.TextBlock, "transparent", { row: 1, column: 2 }),
|
|
$(go.Shape, { row: 0, column: 3, figure: "Club", width: 60, height: 60, margin: 4,
|
|
fill: null }),
|
|
$(go.TextBlock, "null", { row: 1, column: 3 })
|
|
));
|
|
</pre>
|
|
<script>goCode("fill", 600, 100)</script>
|
|
<p>
|
|
Try clicking inside each of the shapes to see which ones will respond to the click and cause the whole panel to be selected.
|
|
Note that with the "transparent" fill you can see the diagram background, yet when you click in it you "hit" the Shape.
|
|
Only the last one, with a null fill, is truly "hollow".
|
|
Clicking in the last shape will only result in a click on the diagram background, unless you click on the stroke outline.
|
|
</p>
|
|
|
|
<h2 id="Geometry">Geometry</h2>
|
|
<p>
|
|
Every <a>Shape</a> gets its "shape" from the <a>Geometry</a> that it uses.
|
|
A Geometry is just a saved description of how to draw some lines given a set of points.
|
|
Setting <a>Shape.figure</a> uses a named predefined geometry that can be parameterized.
|
|
In general it is most efficient to give a Shape a Geometry rather than giving it a figure.
|
|
</p>
|
|
<p>
|
|
If you want something different from all of the predefined figures in <b>GoJS</b>,
|
|
you can construct your own Geometry and set <a>Shape.geometry</a>.
|
|
One way of building your own <a>Geometry</a> is by building <a>PathFigure</a>s
|
|
consisting of <a>PathSegment</a>s.
|
|
This is often necessary when building a geometry whose points are computed based on some data.
|
|
</p>
|
|
<p>
|
|
But an easier way to create constant geometries is by
|
|
calling <a>Geometry.parse</a> to read a string that has a geometry-defining path expression,
|
|
or to set <a>Shape.geometryString</a> to such a string.
|
|
These expressions have commands for moving an imaginary "pen".
|
|
The syntax for geometry paths is documented in the <a href="geometry.html">Geometry Path Strings</a> page.
|
|
</p>
|
|
<p>
|
|
This example creates a Geometry that looks like the letter "W"
|
|
and uses it in several Shape objects with different stroke characteristics.
|
|
Geometry objects may be shared by multiple Shapes.
|
|
Note that there may be no need to specify the <a>GraphObject.desiredSize</a> or <a>GraphObject.width</a> and <a>GraphObject.height</a>,
|
|
because the Geometry defines its own size.
|
|
If the size is set or if it is imposed by the containing Panel, the effective geometry is determined by the <a>Shape.geometryStretch</a> property.
|
|
Depending on the value of the geometryStretch property, this may result in extra empty space or the clipping of the shape.
|
|
</p>
|
|
<pre data-language="javascript" id="geometries">
|
|
var W_geometry = go.Geometry.parse("M 0,0 L 10,50 20,10 30,50 40,0", false);
|
|
diagram.add(
|
|
$(go.Part, "Horizontal",
|
|
$(go.Shape, { geometry: W_geometry, strokeWidth: 2 }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "blue", strokeWidth: 10,
|
|
strokeJoin: "miter", strokeCap: "butt" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "blue", strokeWidth: 10,
|
|
strokeJoin: "miter", strokeCap: "round" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "blue", strokeWidth: 10,
|
|
strokeJoin: "miter", strokeCap: "square" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "green", strokeWidth: 10,
|
|
strokeJoin: "bevel", strokeCap: "butt" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "green", strokeWidth: 10,
|
|
strokeJoin: "bevel", strokeCap: "round" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "green", strokeWidth: 10,
|
|
strokeJoin: "bevel", strokeCap: "square" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "red", strokeWidth: 10,
|
|
strokeJoin: "round", strokeCap: "butt" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "red", strokeWidth: 10,
|
|
strokeJoin: "round", strokeCap: "round" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "red", strokeWidth: 10,
|
|
strokeJoin: "round", strokeCap: "square" }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "purple", strokeWidth: 2,
|
|
strokeDashArray: [4, 2] }),
|
|
$(go.Shape, { geometry: W_geometry, stroke: "purple", strokeWidth: 2,
|
|
strokeDashArray: [6, 6, 2, 2] })
|
|
));
|
|
</pre>
|
|
<script>goCode("geometries", 600, 100)</script>
|
|
|
|
<h2 id="AngleAndScale">Angle and Scale</h2>
|
|
<p>
|
|
Besides setting the <a>GraphObject.desiredSize</a> or <a>GraphObject.width</a> and <a>GraphObject.height</a> to declare the size of a <a>Shape</a>,
|
|
you can also set other properties to affect the appearance.
|
|
For example, you can set the <a>GraphObject.angle</a> and <a>GraphObject.scale</a> properties.
|
|
</p>
|
|
<pre data-language="javascript" id="transformedShapes">
|
|
diagram.add(
|
|
$(go.Part, "Table",
|
|
$(go.Shape, { row: 0, column: 1,
|
|
figure: "Club", fill: "green", width: 40, height: 40,
|
|
}), // default angle is zero; default scale is one
|
|
$(go.Shape, { row: 0, column: 2,
|
|
figure: "Club", fill: "green", width: 40, height: 40,
|
|
angle: 30 }),
|
|
$(go.Shape, { row: 0, column: 3,
|
|
figure: "Club", fill: "green", width: 40, height: 40,
|
|
scale: 1.5 }),
|
|
$(go.Shape, { row: 0, column: 4,
|
|
figure: "Club", fill: "green", width: 40, height: 40,
|
|
angle: 30, scale: 1.5 })
|
|
));
|
|
</pre>
|
|
<script>goCode("transformedShapes", 600, 100)</script>
|
|
|
|
<p>
|
|
The <a>Shape.fill</a> and <a>GraphObject.background</a> brushes scale and rotate along with the shape.
|
|
The <a>GraphObject.areaBackground</a> is drawn in the containing panel's coordinates,
|
|
so it is not affected by the object's scale or angle.
|
|
</p>
|
|
<p>
|
|
The following two shapes each use three separate linear gradient brushes, one for each of the three properties.
|
|
Note the unrotated shape on the left. Because its <a>GraphObject.background</a> brush is opaque,
|
|
you cannot see the <a>GraphObject.areaBackground</a> brush that fills the same area behind it.
|
|
</p>
|
|
<pre data-language="javascript" id="backgrounds">
|
|
var bluered = $(go.Brush, "Linear", { 0.0: "blue", 1.0: "red" });
|
|
var yellowgreen = $(go.Brush, "Linear", { 0.0: "yellow", 1.0: "green" });
|
|
var grays = $(go.Brush, "Linear", { 0.0: "black", 1.0: "lightgray" });
|
|
|
|
diagram.add(
|
|
$(go.Part, "Table",
|
|
$(go.Shape, { row: 0, column: 0,
|
|
figure: "Club", width: 40, height: 40, angle: 0, scale: 1.5,
|
|
fill: bluered,
|
|
background: yellowgreen,
|
|
areaBackground: grays
|
|
}),
|
|
$(go.Shape, { row: 0, column: 1, width: 10, fill: null, stroke: null }),
|
|
$(go.Shape, { row: 0, column: 2,
|
|
figure: "Club", width: 40, height: 40, angle: 45, scale: 1.5,
|
|
fill: bluered,
|
|
background: yellowgreen,
|
|
areaBackground: grays
|
|
})
|
|
));
|
|
</pre>
|
|
<script>goCode("backgrounds", 600, 120)</script>
|
|
|
|
<h2 id="CustomFigures">Custom Figures</h2>
|
|
<p>
|
|
As shown above, one can easily create custom shapes just by setting <a>Shape.geometry</a> or <a>Shape.geometryString</a>.
|
|
This is particularly convenient when importing SVG.
|
|
However it is also possible to define additional named figures, which is convenient when you want to be able to easily
|
|
specify or change the geometry of an existing Shape by setting or data binding the <a>Shape.figure</a> property.
|
|
</p>
|
|
<p>
|
|
The static function <a>Shape.defineFigureGenerator</a> can be used to define new figure names.
|
|
The second argument is a function that is called with the <a>Shape</a> and the expected width and height
|
|
in order to generate and return a <a>Geometry</a>.
|
|
This permits parameterization of the geometry based on properties of the Shape and the expected size.
|
|
In particular, the <a>Shape.parameter1</a> and <a>Shape.parameter2</a> properties can be considered,
|
|
in addition to the width and height, while producing the Geometry.
|
|
</p>
|
|
<pre data-language="javascript" id="defineFigure">
|
|
go.Shape.defineFigureGenerator("RoundedTopRectangle", function(shape, w, h) {
|
|
// this figure takes one parameter, the size of the corner
|
|
var p1 = 5; // default corner size
|
|
if (shape !== null) {
|
|
var param1 = shape.parameter1;
|
|
if (!isNaN(param1) && param1 >= 0) p1 = param1; // can't be negative or NaN
|
|
}
|
|
p1 = Math.min(p1, w / 2);
|
|
p1 = Math.min(p1, h / 2); // limit by whole height or by half height?
|
|
var geo = new go.Geometry();
|
|
// a single figure consisting of straight lines and quarter-circle arcs
|
|
geo.add(new go.PathFigure(0, p1)
|
|
.add(new go.PathSegment(go.PathSegment.Arc, 180, 90, p1, p1, p1, p1))
|
|
.add(new go.PathSegment(go.PathSegment.Line, w - p1, 0))
|
|
.add(new go.PathSegment(go.PathSegment.Arc, 270, 90, w - p1, p1, p1, p1))
|
|
.add(new go.PathSegment(go.PathSegment.Line, w, h))
|
|
.add(new go.PathSegment(go.PathSegment.Line, 0, h).close()));
|
|
// don't intersect with two top corners when used in an "Auto" Panel
|
|
geo.spot1 = new go.Spot(0, 0, 0.3 * p1, 0.3 * p1);
|
|
geo.spot2 = new go.Spot(1, 1, -0.3 * p1, 0);
|
|
return geo;
|
|
});
|
|
|
|
go.Shape.defineFigureGenerator("RoundedBottomRectangle", function(shape, w, h) {
|
|
// this figure takes one parameter, the size of the corner
|
|
var p1 = 5; // default corner size
|
|
if (shape !== null) {
|
|
var param1 = shape.parameter1;
|
|
if (!isNaN(param1) && param1 >= 0) p1 = param1; // can't be negative or NaN
|
|
}
|
|
p1 = Math.min(p1, w / 2);
|
|
p1 = Math.min(p1, h / 2); // limit by whole height or by half height?
|
|
var geo = new go.Geometry();
|
|
// a single figure consisting of straight lines and quarter-circle arcs
|
|
geo.add(new go.PathFigure(0, 0)
|
|
.add(new go.PathSegment(go.PathSegment.Line, w, 0))
|
|
.add(new go.PathSegment(go.PathSegment.Line, w, h - p1))
|
|
.add(new go.PathSegment(go.PathSegment.Arc, 0, 90, w - p1, h - p1, p1, p1))
|
|
.add(new go.PathSegment(go.PathSegment.Line, p1, h))
|
|
.add(new go.PathSegment(go.PathSegment.Arc, 90, 90, p1, h - p1, p1, p1).close()));
|
|
// don't intersect with two bottom corners when used in an "Auto" Panel
|
|
geo.spot1 = new go.Spot(0, 0, 0.3 * p1, 0);
|
|
geo.spot2 = new go.Spot(1, 1, -0.3 * p1, -0.3 * p1);
|
|
return geo;
|
|
});
|
|
|
|
diagram.nodeTemplate =
|
|
$(go.Part, "Spot",
|
|
{
|
|
selectionAdorned: false, // don't show the standard selection handle
|
|
resizable: true, resizeObjectName: "SHAPE", // user can resize the Shape
|
|
rotatable: true, rotateObjectName: "SHAPE", // user can rotate the Shape
|
|
// without rotating the label
|
|
},
|
|
$(go.Shape,
|
|
{
|
|
name: "SHAPE",
|
|
fill: $(go.Brush, "Linear", { 0.0: "white", 1.0: "gray" }),
|
|
desiredSize: new go.Size(100, 50)
|
|
},
|
|
new go.Binding("figure", "fig"),
|
|
new go.Binding("parameter1", "p1")),
|
|
$(go.Panel, "Vertical",
|
|
$(go.TextBlock,
|
|
new go.Binding("text", "fig")),
|
|
$(go.TextBlock, { stroke: "blue" },
|
|
new go.Binding("text", "parameter1", function(p1) { return p1; }).ofObject("SHAPE"))
|
|
)
|
|
);
|
|
|
|
diagram.model = new go.Model([
|
|
{ fig: "RoundedTopRectangle" },
|
|
{ fig: "RoundedTopRectangle", p1: 0 },
|
|
{ fig: "RoundedTopRectangle", p1: 3 },
|
|
{ fig: "RoundedTopRectangle", p1: 10 },
|
|
{ fig: "RoundedTopRectangle", p1: 50 },
|
|
{ fig: "RoundedTopRectangle", p1: 250 },
|
|
{ fig: "RoundedBottomRectangle" },
|
|
{ fig: "RoundedBottomRectangle", p1: 0 },
|
|
{ fig: "RoundedBottomRectangle", p1: 3 },
|
|
{ fig: "RoundedBottomRectangle", p1: 10 },
|
|
{ fig: "RoundedBottomRectangle", p1: 50 },
|
|
{ fig: "RoundedBottomRectangle", p1: 250 }
|
|
]);
|
|
</pre>
|
|
<script>goCode("defineFigure", 700, 300)</script>
|
|
<p>
|
|
Note how the <a>Shape.parameter1</a> property, data bound to the "p1" property, controls how rounded the corners are.
|
|
The definition of each figure limits the roundedness based on the actual size of the geometry.
|
|
You can see the effects by resizing the last shape -- the curve on the shape with p1==250 can be huge if the shape becomes huge.
|
|
</p>
|
|
<p>
|
|
You can find the definitions for many figures at: <a href="../extensions/Figures.js" target="_blank">Figures.js</a>.
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|