Skip to content

Feature. Text rotation#564

Open
azamat7g wants to merge 4 commits into
johnfercher:masterfrom
azamat7g:feature/text-rotation
Open

Feature. Text rotation#564
azamat7g wants to merge 4 commits into
johnfercher:masterfrom
azamat7g:feature/text-rotation

Conversation

@azamat7g

Copy link
Copy Markdown

Description
Adds Rotation (degrees, positive = CCW, negative = CW) and RotationPivot (Horizontal × Vertical axes) to props.Text. Cell auto-expands vertically to fit the rotated bounding box; default Center+Middle pivot keeps single-line
behavior identical to before.

Notable details:

  • Text.GetHeight returns the rotated bbox height (w·|sinθ| + h·|cosθ|) so the layout reserves room.
  • New Provider.GetStringWidth lets GetHeight use the actual rendered width instead of cell.Width (avoids ~3× over-allocation for short text).
  • gofpdf Add hoists line-splitting above the rotation transform so multi-line blocks rotate as one around the correct textHeight-based pivot.
  • upExtent is computed from the four rotated corners — covers all 9 pivot combos for any angle/sign.
  • ToMap omits the new keys when default → existing snapshots untouched.

Related Issue
N/A

Checklist

  • All methods associated with structs has func (<first letter of struct> *struct) method() {} name style.
  • Wrote unit tests for new/changed features.
  • Followed the unit test when,should naming pattern.
  • All mocks created with m := mocks.NewConstructor(t).
  • All mocks using m.EXPECT().MethodName() method to mock methods.
  • Updated docs/*
  • Updated example_test.go.
  • Updated README.md
  • New public methods/structs/interfaces has comments upside them explaining they responsibilities
  • Executed make dod with none issues pointed out by golangci-lint

Azamat added 3 commits April 29, 2026 20:18
Add horizontal and vertical pivot options for text rotation. Default pivots are set to Center and Middle. Update tests to cover various pivot configurations and ensure accurate positioning for multi-line text.
Add new example demonstrating text rotation with pivot customization. Update documentation to describe `Rotation` and `RotationPivot` options comprehensively, including usage notes.
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9ff74a7c-6ba3-4318-b7d7-d4bafc53d042

📥 Commits

Reviewing files that changed from the base of the PR and between 74d201d and 9fa6c5b.

📒 Files selected for processing (1)
  • pkg/components/text/text.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Text component supports rotation (degrees) and configurable rotation anchor (start/center/end × top/middle/bottom).
  • Behavior Changes
    • Height and layout calculations updated so rotated multi-line text fits within its cell and aligns to the chosen pivot.
  • Documentation
    • Docs updated with rotation usage, pivot rules, and layout/height notes.
  • Examples
    • Added example demonstrating rotated text.
  • Tests
    • Added tests validating rotated rendering and height calculations.

Walkthrough

Adds text rotation support: new rotation props and pivot constants, provider/interface methods for measuring string width, rotated bounding-box math and pivot-aware positioning in rendering, mock/test updates, example, and documentation updates.

Changes

Cohort / File(s) Summary
Rotation Pivot Constants
pkg/consts/rotationpivot/rotationpivot.go
New package defining horizontal (Start, Center, End) and vertical (Top, Middle, Bottom) pivot types and Pivot struct.
Core Interfaces
pkg/core/components.go, pkg/core/provider.go
Added GetStringWidth(text string, textProp *props.Text) float64 to Text and Provider interfaces.
Text Properties
pkg/props/text.go, pkg/props/text_test.go
Added Rotation float64 and RotationPivot rotationpivot.Pivot; ToMap() emits rotation fields conditionally; MakeValid() defaults missing pivot axes; tests updated for serialization/validation.
Text Component API & Logic
pkg/components/text/text.go, pkg/components/text/text_test.go, pkg/components/text/example_test.go
GetHeight now accounts for rotated bounding-box math (sine/cosine, clamping to content width); tests added for rotation cases; example demonstrating rotated text added.
GoFPDF Provider Implementation
internal/providers/gofpdf/provider.go, internal/providers/gofpdf/text.go, internal/providers/gofpdf/text_test.go
Provider exposes GetStringWidth; text rendering computes wrapped lines first, calculates block width/height, alignment and pivot offsets, adjusts Y to fit rotated bounding box, applies TransformRotate around pivot, then renders lines; extensive tests assert transforms and text positions.
Mocks
mocks/Provider.go, mocks/Text.go
Added GetStringWidth mock methods and expectation plumbing to both provider and text mocks.
Documentation
docs/v2/features/text.md
Documentation extended with Rotation and RotationPivot prop descriptions, usage notes, and rotated height/baseline calculation details.

Sequence Diagram(s)

sequenceDiagram
    participant Component as Text Component
    participant Provider as GoFPDF Provider
    participant PDF as PDF Context

    Component->>Provider: Add(text, props {Rotation, RotationPivot})
    activate Provider
    Provider->>Provider: Determine wrapped lines\nGetStringWidth for measurement
    Provider->>Provider: Compute block width/height\nCompute alignment & pivot offsets
    Provider->>Provider: Calculate rotated bounding-box\nAdjust start Y if needed
    Provider->>PDF: TransformBegin()
    Provider->>PDF: TransformRotate(angle, pivotX, pivotY)
    Provider->>PDF: Text(x, y) for each line
    Provider->>PDF: TransformEnd()
    deactivate Provider
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Spin the letters, twirl the line,

Pivot set and angle fine,
Sine and cosine do their part,
Every block fits—art to art,
A rabbit hops, and stamps “rendered!” ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feature. Text rotation' is concise and clearly indicates the main change: adding text rotation capability.
Description check ✅ Passed The description is comprehensive and follows the template. It explains the feature, details technical aspects, and addresses all applicable checklist items with confirmation marks.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/components/text/text.go`:
- Around line 72-85: contentWidth can be negative if t.prop.Left + t.prop.Right
> cell.Width which yields invalid heights when rotation math runs; before
calling provider.GetLinesQuantity/GetStringWidth and before using contentWidth
in the rotation block, clamp contentWidth to zero (or math.Max(0, contentWidth))
and use that non-negative value for subsequent calculations (affecting the call
to provider.GetLinesQuantity, the stringWidth clamp and the rotation height math
that updates textHeight); update references to contentWidth,
provider.GetLinesQuantity, provider.GetStringWidth and the rotation block that
computes textHeight to use the guarded value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fd2ca0d7-df9a-41f5-9e0d-90457dffb08b

📥 Commits

Reviewing files that changed from the base of the PR and between aa2645f and 74d201d.

📒 Files selected for processing (14)
  • docs/v2/features/text.md
  • internal/providers/gofpdf/provider.go
  • internal/providers/gofpdf/text.go
  • internal/providers/gofpdf/text_test.go
  • mocks/Provider.go
  • mocks/Text.go
  • pkg/components/text/example_test.go
  • pkg/components/text/text.go
  • pkg/components/text/text_test.go
  • pkg/consts/rotationpivot/rotationpivot.go
  • pkg/core/components.go
  • pkg/core/provider.go
  • pkg/props/text.go
  • pkg/props/text_test.go

Comment thread pkg/components/text/text.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant