Class SurfaceVector
A retained vector drawing node: a small catalog of fill/stroke/text operations recorded in
paint order and replayed natively by every platform renderer (SwiftUI Canvas on iOS, an
in-process bitmap on Android, Codename One Graphics on desktop). It exists for the widgets
the sealed template catalog cannot express -- clocks, gauges, dials and similar custom art --
without shipping pre-rendered images for every state.
Operations use a logical coordinate space (the view box passed to the constructor) that is scaled to the node's laid-out bounds preserving aspect ratio and centered, so the same op list renders correctly at every widget size.
Angles: the clock convention
All angles in this class are degrees where 0 points up (12 o'clock) and positive angles advance clockwise -- the natural convention for clock hands and gauge needles. Renderers convert internally to each platform's native arc convention.
Rotation groups
Operations added between beginRotation(...) and endRotation() rotate together around a
pivot. The angle is either fixed or read from the entry state map by key, which is what makes
an analog clock cheap: publish the face layout once and drive the hands with per-entry state:
SurfaceVector face = new SurfaceVector(200, 200)
.fillEllipse(100, 100, 96, 96, SurfaceColor.BACKGROUND)
.strokeEllipse(100, 100, 96, 96, 4, SurfaceColor.LABEL)
.beginRotation("hourAngle", 100, 100)
.line(100, 100, 100, 52, 8, SurfaceColor.LABEL)
.endRotation()
.beginRotation("minuteAngle", 100, 100)
.line(100, 100, 100, 24, 5, SurfaceColor.ACCENT)
.endRotation()
.fillEllipse(100, 100, 6, 6, SurfaceColor.ACCENT);
// one timeline entry per minute; the OS flips entries on schedule without waking the app
WidgetTimeline t = new WidgetTimeline().setContent(face);
for (int m = 0; m < 60; m++) {
int totalMinutes = hourOfDay * 60 + minute + m;
Map<String, Object> state = new HashMap<String, Object>();
state.put("minuteAngle", Float.valueOf(totalMinutes % 60 * 6f));
state.put("hourAngle", Float.valueOf(totalMinutes % 720 * 0.5f));
t.addEntry(new Date(startOfMinute + m * 60000L), state);
}
A state-driven angle does not tick by itself -- state is per timeline entry, so a clock publishes one entry per minute (as above) and the OS flips them on its own schedule.
Descriptors cap the total operation count at 512 per vector node; exceeding it fails at
serialization time. Unbalanced beginRotation/endRotation pairs also fail at serialization
time with IllegalStateException.
-
Constructor Summary
ConstructorsConstructorDescriptionSurfaceVector(int viewBoxWidth, int viewBoxHeight) Creates a vector node with a logical coordinate space. -
Method Summary
Modifier and TypeMethodDescriptionbeginRotation(float degrees, float pivotX, float pivotY) Opens a rotation group with a fixed angle: every op added until the matchingendRotation()rotates bydegrees(clock convention: clockwise positive) around the pivot.beginRotation(String degreesStateKey, float pivotX, float pivotY) Opens a rotation group whose angle is read from the entry state map: the state value is aNumberin degrees, clockwise positive.Closes the most recently opened rotation group.fillArc(float cx, float cy, float rx, float ry, float startDeg, float sweepDeg, SurfaceColor c) Fills a pie slice: the elliptical arc between the two angles joined to the center.fillEllipse(float cx, float cy, float rx, float ry, SurfaceColor c) Fills an ellipse.fillPath(float[] xy, boolean close, SurfaceColor c) Fills a polygon built from x,y coordinate pairs.fillRect(float x, float y, float w, float h, SurfaceColor c) Fills an axis-aligned rectangle.fillRoundRect(float x, float y, float w, float h, float corner, SurfaceColor c) Fills a rectangle with rounded corners.intReturns the number of recorded operations, rotation groups included.intReturns the logical view-box height.intReturns the logical view-box width.line(float x1, float y1, float x2, float y2, float strokeWidth, SurfaceColor c) Draws a line with round caps.Assigns a tap action to this node.Assigns a tap action with parameters to this node.setAlignment(SurfaceAlignment alignment) Sets this node's alignment within its parent.setBackground(SurfaceColor background) Sets the background color of this node.setCornerRadius(int radius) Sets the corner radius applied to the node's background.setPadding(int all) Sets the same padding on all four sides.setPadding(int top, int right, int bottom, int left) Sets the padding of each side individually.setSize(int widthDips, int heightDips) Sets a fixed size for this node.setWeight(int weight) Sets the flexible-space weight of this node within a row or column.strokeArc(float cx, float cy, float rx, float ry, float startDeg, float sweepDeg, float strokeWidth, SurfaceColor c) Strokes an open elliptical arc with round caps -- the primitive for gauge tracks and progress rings.strokeEllipse(float cx, float cy, float rx, float ry, float strokeWidth, SurfaceColor c) Strokes the outline of an ellipse.strokePath(float[] xy, boolean close, float strokeWidth, SurfaceColor c) Strokes a poly-line built from x,y coordinate pairs, with round caps and joins.text(String text, float x, float y, float fontSize, SurfaceFontWeight w, SurfaceColor c) Draws text anchored at the middle ofxwith its baseline aty.Methods inherited from class SurfaceNode
getActionId, getActionParams, getAlignment, getBackground, getCornerRadius, getHeightDips, getPaddingBottom, getPaddingLeft, getPaddingRight, getPaddingTop, getWeight, getWidthDips
-
Constructor Details
-
SurfaceVector
public SurfaceVector(int viewBoxWidth, int viewBoxHeight) Creates a vector node with a logical coordinate space. The view box is scaled to the node's laid-out bounds preserving aspect ratio (centered); it also provides the node's natural size in dips when no fixed size or weight applies.
Parameters
viewBoxWidth: the logical width of the drawing coordinate spaceviewBoxHeight: the logical height of the drawing coordinate space
-
-
Method Details
-
fillRect
Fills an axis-aligned rectangle.
Parameters
x: left edge in view-box unitsy: top edge in view-box unitsw: width in view-box unitsh: height in view-box unitsc: the fill color
Returns
this vector node, for chaining
-
fillRoundRect
public SurfaceVector fillRoundRect(float x, float y, float w, float h, float corner, SurfaceColor c) Fills a rectangle with rounded corners.
Parameters
x: left edge in view-box unitsy: top edge in view-box unitsw: width in view-box unitsh: height in view-box unitscorner: the corner radius in view-box unitsc: the fill color
Returns
this vector node, for chaining
-
fillEllipse
Fills an ellipse.
Parameters
cx: center x in view-box unitscy: center y in view-box unitsrx: horizontal radius in view-box unitsry: vertical radius in view-box unitsc: the fill color
Returns
this vector node, for chaining
-
fillArc
public SurfaceVector fillArc(float cx, float cy, float rx, float ry, float startDeg, float sweepDeg, SurfaceColor c) Fills a pie slice: the elliptical arc between the two angles joined to the center. Angles use the clock convention (degrees, 0 = 12 o'clock, clockwise positive).
Parameters
cx: center x in view-box unitscy: center y in view-box unitsrx: horizontal radius in view-box unitsry: vertical radius in view-box unitsstartDeg: the start angle in clock degreessweepDeg: the sweep in degrees, clockwise positivec: the fill color
Returns
this vector node, for chaining
-
strokeEllipse
public SurfaceVector strokeEllipse(float cx, float cy, float rx, float ry, float strokeWidth, SurfaceColor c) Strokes the outline of an ellipse.
Parameters
cx: center x in view-box unitscy: center y in view-box unitsrx: horizontal radius in view-box unitsry: vertical radius in view-box unitsstrokeWidth: the stroke width in view-box unitsc: the stroke color
Returns
this vector node, for chaining
-
strokeArc
public SurfaceVector strokeArc(float cx, float cy, float rx, float ry, float startDeg, float sweepDeg, float strokeWidth, SurfaceColor c) Strokes an open elliptical arc with round caps -- the primitive for gauge tracks and progress rings. Angles use the clock convention (degrees, 0 = 12 o'clock, clockwise positive).
Parameters
cx: center x in view-box unitscy: center y in view-box unitsrx: horizontal radius in view-box unitsry: vertical radius in view-box unitsstartDeg: the start angle in clock degreessweepDeg: the sweep in degrees, clockwise positivestrokeWidth: the stroke width in view-box unitsc: the stroke color
Returns
this vector node, for chaining
-
line
public SurfaceVector line(float x1, float y1, float x2, float y2, float strokeWidth, SurfaceColor c) Draws a line with round caps.
Parameters
x1: start x in view-box unitsy1: start y in view-box unitsx2: end x in view-box unitsy2: end y in view-box unitsstrokeWidth: the stroke width in view-box unitsc: the stroke color
Returns
this vector node, for chaining
-
fillPath
Fills a polygon built from x,y coordinate pairs. The path is implicitly closed for filling regardless of
close.Parameters
xy: coordinate pairsx0, y0, x1, y1, ...in view-box units, at least three pointsclose: whether the serialized path is marked closed (kept for renderer symmetry withstrokePath)c: the fill color
Returns
this vector node, for chaining
-
strokePath
Strokes a poly-line built from x,y coordinate pairs, with round caps and joins.
Parameters
xy: coordinate pairsx0, y0, x1, y1, ...in view-box units, at least two pointsclose: whether the last point connects back to the firststrokeWidth: the stroke width in view-box unitsc: the stroke color
Returns
this vector node, for chaining
-
text
public SurfaceVector text(String text, float x, float y, float fontSize, SurfaceFontWeight w, SurfaceColor c) Draws text anchored at the middle of
xwith its baseline aty. The text supports${key}interpolation from the entry state map, likeSurfaceText.Parameters
text: the text, may embed${key}placeholdersx: the horizontal anchor (text centers on it) in view-box unitsy: the text baseline in view-box unitsfontSize: the font size in view-box unitsw: the font weightc: the text color
Returns
this vector node, for chaining
-
beginRotation
Opens a rotation group with a fixed angle: every op added until the matching
endRotation()rotates bydegrees(clock convention: clockwise positive) around the pivot. Groups nest.Parameters
degrees: the rotation in degrees, clockwise positivepivotX: the pivot x in view-box unitspivotY: the pivot y in view-box units
Returns
this vector node, for chaining
-
beginRotation
Opens a rotation group whose angle is read from the entry state map: the state value is a
Numberin degrees, clockwise positive. This is how clock hands and gauge needles animate -- a per-entry timeline updates the angle without republishing the layout.Parameters
degreesStateKey: the state-map key holding the angle in degreespivotX: the pivot x in view-box unitspivotY: the pivot y in view-box units
Returns
this vector node, for chaining
-
endRotation
Closes the most recently opened rotation group.
Returns
this vector node, for chaining
-
getViewBoxWidth
public int getViewBoxWidth()Returns the logical view-box width. -
getViewBoxHeight
public int getViewBoxHeight()Returns the logical view-box height. -
getOpCount
public int getOpCount()Returns the number of recorded operations, rotation groups included. -
setPadding
Description copied from class:SurfaceNodeSets the same padding on all four sides.
Parameters
all: padding in dips
Returns
this node, for chaining
- Overrides:
setPaddingin classSurfaceNode
-
setPadding
Description copied from class:SurfaceNodeSets the padding of each side individually.
Parameters
top: top padding in dipsright: right padding in dipsbottom: bottom padding in dipsleft: left padding in dips
Returns
this node, for chaining
- Overrides:
setPaddingin classSurfaceNode
-
setBackground
Description copied from class:SurfaceNodeSets the background color of this node.
Parameters
color: the background color
Returns
this node, for chaining
- Overrides:
setBackgroundin classSurfaceNode
-
setCornerRadius
Description copied from class:SurfaceNodeSets the corner radius applied to the node's background. May render square on Android versions below 12.
Parameters
radius: the corner radius in dips
Returns
this node, for chaining
- Overrides:
setCornerRadiusin classSurfaceNode
-
setAlignment
Description copied from class:SurfaceNodeSets this node's alignment within its parent. In a
SurfaceBoxall nine positions apply; in rows and columns only the cross-axis component is used.Parameters
alignment: the alignment
Returns
this node, for chaining
- Overrides:
setAlignmentin classSurfaceNode
-
setWeight
Description copied from class:SurfaceNodeSets the flexible-space weight of this node within a row or column. Nodes with a weight share the leftover space of the parent proportionally; a weight of 0 (the default) sizes the node to its natural size.
Parameters
weight: the relative weight, 0 for natural sizing
Returns
this node, for chaining
- Overrides:
setWeightin classSurfaceNode
-
setSize
Description copied from class:SurfaceNodeSets a fixed size for this node. A value of 0 (the default) keeps the natural size of the respective axis.
Parameters
widthDips: fixed width in dips, 0 for natural widthheightDips: fixed height in dips, 0 for natural height
Returns
this node, for chaining
- Overrides:
setSizein classSurfaceNode
-
setAction
Description copied from class:SurfaceNodeAssigns a tap action to this node. Tapping the node opens (or foregrounds) the app and delivers the action id to the handler registered with
Surfaces.setActionHandler(...). Note that small iOS home-screen widgets only honor the action of the root node.Parameters
actionId: the app-defined action identifier
Returns
this node, for chaining
- Overrides:
setActionin classSurfaceNode
-
setAction
Description copied from class:SurfaceNodeAssigns a tap action with parameters to this node. The parameter map may contain
String,NumberandBooleanvalues and is delivered verbatim with theSurfaceActionEvent.Parameters
actionId: the app-defined action identifierparams: parameters delivered with the action, may be null
Returns
this node, for chaining
- Overrides:
setActionin classSurfaceNode
-