Rect
A Rect is an object that contains the postion (Point) and measurements (Size) of the bounding box of a graphic or group, regardless of the graphic’s shape or appearance.
new Rect(x: Number, y: Number, width: Number, height: Number) → (Rect) • Returns a new Rect with the specified coordinates and size.
The Rect Object
[object Rect: (0.0, 0.0, 1024.0, 768.0)]
The four numeric values of a Rect represent (in order):
- the horizontal offset from the origin,
- the vertical offset from the origin,
- the width of the object,
- the height of the object.
Functionally, you may think of a Rect as a Point and a Size combined into a single object.
Creating a Rect Object
To create a Rect, precede the Rect class name with the “new” allocator, followed by the comma-delimited sequence of the numeric values described in the previous list: (horizontal offset, vertical offset, width, height). The result will be a Rect object:
Creating a Rect Object
aRect = new Rect(0, 0, 1024, 768)
//--> [object Rect: (0.0, 0.0, 1024.0, 768.0)]
The position and dimensions of every graphic are contained in a Rect that is the value of the graphic’s geometry property:
Get value of the Geometry property of a Selected Graphic
document.windows[0].selection.graphics[0].geometry
//--> [object Rect: (354.0, 235.5, 316.0, 297.0)]
The geometry property is used quite often in Omni Automation scripts, and when addressing the geometry property, scripts are actually working with a Rect instance.
Rect Properties
A Rect instance has seven properties, all of which are editable, except the center property which has a read-only value:
size (Size) • The value of the size property is a Size object, whose elements are the width and height of the graphic or bounding box.
height (Number) • The value of the height property is a number (in points) describing the vertical measurement of the graphic or bounding box.
width (Number) • The value of the width property is a number (in points) describing the horizontal measurement of the graphic or bounding box.
origin (Point) • The value of the origin property is a Point object, describing the position of the top-left corner of the graphic or bounding box from the canvas origin.
x (Number) • The value of the x property is a number (in points) describing the distance from the canvas horizontal origin to the left side of the graphic or bounding box.
y (Number) • The value of the y property is a number (in points) describing the distance from the canvas vertical origin to the top side of the graphic or bounding box.
center (r/o) (Point) • The value of the center property is a Point object describing the position of the center of the graphic or bounding box in relation to the canvas origin.
Editing a Rect
To change the origin (position) or size of a graphic, you extract the Rect object that is the value of the graphic’s geometry property, alter the extracted copy, and then assign the altered copy as the new value of the graphic’s geometry property. For example, here is a script that changes the origin (position) of a graphic:
Changing the Postion of a Graphic
slds = document.windows[0].selection.solids
if(slds.length === 1){
geo = slds[0].geometry
geo.origin = new Point(0,0)
slds[0].geometry = geo
}
Use the same technique for changing the size of a graphic:
Changing the Size of a Graphic
slds = document.windows[0].selection.solids
if(slds.length === 1){
geo = slds[0].geometry
geo.size = new Size(300,300)
slds[0].geometry = geo
}
The “Handles” of a Rect
The visual representation of a Rect has “handles” to enable the physical manipulation of the object.
minX (Number) • The smallest (leftmost) horizontal offset of the rectangle.
minY (Number) • The smallest (topmost) vertical offset of the rectangle.
midX (Number) • The horizontal offset midway through the width of the rectangle.
midY (Number) • The vertical offset midway through the height of the rectangle.
maxX (Number) • The largest (rightmost) horizontal offset of the rectangle.
maxY (Number) • The largest (bottom) vertical offset of the rectangle.
Deriving the Postion of a Handle
slds = document.windows[0].selection.solids
if(slds.length === 1){
geo = slds[0].geometry
bottomRight = new Point(geo.maxX, geo.maxY)
//--> [object Point: (287.5, 263.0)] {length: 389.6475971952092, negative: [object Point: (-287.5, -263.0)], normalized: [object Point: (0.7378462027470573, 0.6749688741651341)], x: 287.5, y: 263}
}
More properties of a Rect instance:
standardized (Rect r/o) • Returns a rectangle with a positive width and height.
integral (Rect r/o) • Returns the smallest rectangle that results from converting the source rectangle values to integers.
isEmpty (Boolean r/o) • Is the Rect instance empty?
isInfinite (Boolean r/o) • Is the Rect instance set to have infinite dimensions? This is possible if the shape is the background for a canvas.
isNull (Boolean r/o) • Is the Rect instance non-existant?
Properties of a Rect
slds = document.windows[0].selection.solids
if(slds.length === 1){
console.log(slds[0].geometry)
//--> [object Rect: (87.5, 63.0, 200.0, 200.0)]
console.log(slds[0].geometry.standardized)
//--> [object Rect: (87.5, 63.0, 200.0, 200.0)]
console.log(slds[0].geometry.integral)
//--> [object Rect: (87.0, 63.0, 201.0, 200.0)]
}
Rect Functions
The following functions can be called on an instance of the Rect class:
union(rect: Rect) → (Rect) • This method takes a Rect as its parameter, and returns a Rect describing the bounding box of the union of the instance Rect and the parameter Rect.
intersect(rect: Rect) → (Rect) • DESCRIPTION
containsRect(rect: Rect) → (Boolean) • DESCRIPTION
containsPoint(point: Point) → (Boolean) • DESCRIPTION
intersects(rect: Rect) → (Boolean) • DESCRIPTION
insetBy(dx: Number, dy: Number) → (Rect) • DESCRIPTION
offsetBy(dx: Number, dy: Number) → (Rect) • DESCRIPTION
Multiple Shapes
cnvs = document.windows[0].selection.canvas
shapes = cnvs.graphics
redBox = shapes[2]
blueBox = shapes[1]
greenBox = shapes[0]
Union
redBox.geometry.union(greenBox.geometry)
//--> [object Rect: (0.0, 0.0, 300.0, 300.0)] {center: [object Point: (150.0, 150.0)], height: 300, integral: [object Rect: (0.0, 0.0, 300.0, 300.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 300, maxY: 300, midX: 150, midY: 150, minX: 0, minY: 0, origin: [object Point: (0.0, 0.0)], size: [object Size: (300.0, 300.0)], standardized: [object Rect: (0.0, 0.0, 300.0, 300.0)], width: 300, x: 0, y: 0}
Intersect
redBox.geometry.intersect(greenBox.geometry)
//--> [object Rect: (100.0, 100.0, 100.0, 100.0)] {center: [object Point: (150.0, 150.0)], height: 100, integral: [object Rect: (100.0, 100.0, 100.0, 100.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 200, maxY: 200, midX: 150, midY: 150, minX: 100, minY: 100, origin: [object Point: (100.0, 100.0)], size: [object Size: (100.0, 100.0)], standardized: [object Rect: (100.0, 100.0, 100.0, 100.0)], width: 100, x: 100, y: 100}
Contains Rect
redBox.geometry.containsRect(greenBox.geometry)
//--> false
redBox.geometry.containsRect(blueBox.geometry)
//--> true
Contains Point
redBox.geometry.containsPoint(blueBox.geometry.origin)
//--> true
redBox.geometry.containsPoint(greenBox.geometry.origin)
//--> true
redBox.geometry.containsPoint(greenBox.geometry.center)
//--> false
var gBottomRight = new Point(greenBox.geometry.maxX, greenBox.geometry.maxY)
redBox.geometry.containsPoint(gBottomRight)
//--> false
Intersects
redBox.geometry.intersects(blueBox.geometry)
//--> true
redBox.geometry.intersects(greenBox.geometry)
//--> true
The insetBy() function can be used to derive new geometry for a shape that decreases its size by horizontal and vertical percentages.
In the shown example, the starting width and height of the green shape are 200pt and 200pt respectively. The following example script uses the function to generate a Rect instance that is scaled down from the original shape geometry by 50% horizontally and 50% vertically. The resulting Rect instance is then assigned as the value for the shape’s geometry property, causing the shape to resize:
Inset By
newRect = greenBox.geometry.insetBy(50, 50)
greenBox.geometry = newRect
//--> [object Rect: (150.0, 150.0, 100.0, 100.0)] {center: [object Point: (200.0, 200.0)], height: 100, integral: [object Rect: (150.0, 150.0, 100.0, 100.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 250, maxY: 250, midX: 200, midY: 200, minX: 150, minY: 150, origin: [object Point: (150.0, 150.0)], size: [object Size: (100.0, 100.0)], standardized: [object Rect: (150.0, 150.0, 100.0, 100.0)], width: 100, x: 150, y: 150}
The offsetBy() function can be used to change the postion of a shape by the provided horizontal and vertical percentages of the current shape offset.
In the shown example, the starting horizontal and vertical origins of the green shape are 100pt and 100pt respectively. The following example script uses the function to generate a Rect instance that adjusts the origin from the original shape geometry by 100% horizontally and 100% vertically. The resulting Rect instance is then assigned as the value for the shape’s geometry property, causing the shape to be repositioned with an origin point of (200pt, 200pt):
Offset By
newRect = greenBox.geometry.offsetBy(100, 100)
greenBox.geometry = newRect
//--> [object Rect: (200.0, 200.0, 200.0, 200.0)] {center: [object Point: (300.0, 300.0)], height: 200, integral: [object Rect: (200.0, 200.0, 200.0, 200.0)], isEmpty: false, isInfinite: false, isNull: false, maxX: 400, maxY: 400, midX: 300, midY: 300, minX: 200, minY: 200, origin: [object Point: (200.0, 200.0)], size: [object Size: (200.0, 200.0)], standardized: [object Rect: (200.0, 200.0, 200.0, 200.0)], width: 200, x: 200, y: 200}
Using Rect Properties and Functions
The following example script incorporates many of the properties and functions of the Rect class to generate a “flower” from a single selected square solid in OmniGraffle:
Generate “Flower”
cnvs = document.windows[0].selection.canvas
slds = document.windows[0].selection.solids
if(slds.length === 1){
s = slds[0]
g = s.geometry
c = s.fillColor
c1 = Color.RGB(c.red * 0.9,c.green * 0.9,c.blue * 0.9)
c2 = Color.RGB(c.red * 0.2,c.green * 0.2,c.blue * 0.2)
// 1
d = s.duplicateTo(new Point(g.maxX,g.maxY),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 225
// 2
d = s.duplicateTo(new Point(g.minX-g.width,g.maxY),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 315
// 3
d = s.duplicateTo(new Point(g.minX-g.width,g.minY-g.height),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 45
//4
d = s.duplicateTo(new Point(g.maxX,g.minY-g.height),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 135
// 5
d = s.duplicateTo(new Point(g.maxX,g.minY),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 135
// 6
d = s.duplicateTo(new Point(g.x,g.maxY),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 225
// 7
d = s.duplicateTo(new Point(g.x-g.width,g.minY),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 315
// 8
d = s.duplicateTo(new Point(g.x,g.minY-g.height),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 45
// center circle
aRect = g.insetBy(g.width/5,g.height/5)
circle = cnvs.addShape('Circle',aRect)
circle.fillType = FillType.Radial
circle.fillColor = Color.white
circle.gradientColor = c2
// original square
s.fillType = FillType.Radial
s.fillColor = Color.white
s.gradientColor = c2
}
And here is a similar script written as an Omni Automation plug-in:
Replicate Square in Flower Pattern
/*{
"type": "action",
"targets": ["omnigraffle"],
"author": "Otto Automator",
"identifier": "com.omni-automation.og.flower-replication",
"version": "1.1",
"description": "Will replicate the selected single-color filled square in a flower-like pattern.",
"label": "Replicate in Flower Pattern",
"shortLabel": "Replicate as Flower",
"paletteLabel": "Replicate as Flower",
"image": "rectangle.grid.2x2"
}*/
(() => {
const action = new PlugIn.Action(async function(selection, sender){
// action code
// selection options: canvas, document, graphics, lines, solids, view
try {
/* To use with Browse tool, selection reference must be explicit */
var s = document.windows[0].selection.solids[0]
var cnvs = document.windows[0].selection.canvas
var docView = document.windows[0].selection.view
g = s.geometry
c = s.fillColor
c1 = Color.RGB(c.red * 0.9,c.green * 0.9,c.blue * 0.9)
c2 = Color.RGB(c.red * 0.2,c.green * 0.2,c.blue * 0.2)
// 1
d = s.duplicateTo(new Point(g.maxX,g.maxY),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 225
// 2
d = s.duplicateTo(new Point(g.minX-g.width,g.maxY),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 315
// 3
d = s.duplicateTo(new Point(g.minX-g.width,g.minY-g.height),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 45
//4
d = s.duplicateTo(new Point(g.maxX,g.minY-g.height),null)
d.fillType = FillType.Linear
d.gradientColor = c2
d.gradientAngle = 135
// 5
d = s.duplicateTo(new Point(g.maxX,g.minY),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 135
// 6
d = s.duplicateTo(new Point(g.x,g.maxY),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 225
// 7
d = s.duplicateTo(new Point(g.x-g.width,g.minY),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 315
// 8
d = s.duplicateTo(new Point(g.x,g.minY-g.height),null)
d.rotation = 45
d.fillType = FillType.Linear
d.fillColor = Color.white
d.gradientColor = c1
d.gradientAngle = 45
// center circle
aRect = g.insetBy(g.width/5,g.height/5)
circle = cnvs.addShape('Circle',aRect)
circle.fillType = FillType.Radial
circle.fillColor = Color.white
circle.gradientColor = c2
// original square
s.fillType = FillType.Radial
s.fillColor = Color.white
s.gradientColor = c2
// deselect
docView.select([])
}
catch(err){
if(!err.causedByUserCancelling){
new Alert(err.name, err.message).show()
}
}
});
action.validate = function(selection, sender){
// validation code
// selection options: canvas, document, graphics, lines, solids, view
// square filled with a solid color
if (selection.solids.length === 1){
solid = selection.solids[0]
rect = solid.geometry
return (
rect.width === rect.height &&
solid.fillColor !== null &&
solid.fillType === FillType.Solid
)
} else {return false}
};
return action;
})();