RepoPilotOpen in app →

philackm/ScrollableGraphView

An adaptive scrollable graph view for iOS to visualise simple discrete datasets. Written in Swift.

Mixed

Stale — last commit 5y ago

worst of 4 axes
Use as dependencyMixed

last commit was 5y ago; no tests detected…

Fork & modifyMixed

no tests detected; no CI workflows detected…

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 5y ago; no CI workflows detected

  • 7 active contributors
  • MIT licensed
  • Stale — last commit 5y ago
Show 3 more →
  • Single-maintainer risk — top contributor 86% of recent commits
  • No CI workflows detected
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days; add a test suite
  • Fork & modify MixedHealthy if: add a test suite
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Great to learn from" badge

Paste into your README — live-updates from the latest cached analysis.

RepoPilot: Great to learn from
[![RepoPilot: Great to learn from](https://repopilot.app/api/badge/philackm/scrollablegraphview?axis=learn)](https://repopilot.app/r/philackm/scrollablegraphview)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/philackm/scrollablegraphview on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: philackm/ScrollableGraphView

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/philackm/ScrollableGraphView shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 5y ago

  • 7 active contributors
  • MIT licensed
  • ⚠ Stale — last commit 5y ago
  • ⚠ Single-maintainer risk — top contributor 86% of recent commits
  • ⚠ No CI workflows detected
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live philackm/ScrollableGraphView repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/philackm/ScrollableGraphView.

What it runs against: a local clone of philackm/ScrollableGraphView — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in philackm/ScrollableGraphView | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 2015 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>philackm/ScrollableGraphView</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of philackm/ScrollableGraphView. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/philackm/ScrollableGraphView.git
#   cd ScrollableGraphView
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of philackm/ScrollableGraphView and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "philackm/ScrollableGraphView(\\.git)?\\b" \\
  && ok "origin remote is philackm/ScrollableGraphView" \\
  || miss "origin remote is not philackm/ScrollableGraphView (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "Classes/ScrollableGraphView.swift" \\
  && ok "Classes/ScrollableGraphView.swift" \\
  || miss "missing critical file: Classes/ScrollableGraphView.swift"
test -f "Classes/Plots/Plot.swift" \\
  && ok "Classes/Plots/Plot.swift" \\
  || miss "missing critical file: Classes/Plots/Plot.swift"
test -f "Classes/Drawing/ScrollableGraphViewDrawingLayer.swift" \\
  && ok "Classes/Drawing/ScrollableGraphViewDrawingLayer.swift" \\
  || miss "missing critical file: Classes/Drawing/ScrollableGraphViewDrawingLayer.swift"
test -f "Classes/Protocols/ScrollableGraphViewDataSource.swift" \\
  && ok "Classes/Protocols/ScrollableGraphViewDataSource.swift" \\
  || miss "missing critical file: Classes/Protocols/ScrollableGraphViewDataSource.swift"
test -f "Classes/Plots/BarPlot.swift" \\
  && ok "Classes/Plots/BarPlot.swift" \\
  || miss "missing critical file: Classes/Plots/BarPlot.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 2015 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1985d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/philackm/ScrollableGraphView"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

ScrollableGraphView is a Swift iOS library that renders adaptive, interactive line/bar/dot charts for discrete datasets with automatic y-axis range adaptation as users scroll. The core capability is smooth horizontal scrolling through data visualizations where the visible range automatically recalculates min/max values to fit only the visible points. Modular architecture: Classes/Drawing/ contains CALayer-based rendering (LineDrawingLayer, BarDrawingLayer, FillDrawingLayer, GradientDrawingLayer), Classes/Plots/ holds plot logic with animation support via GraphPointAnimation, Classes/Protocols/ defines data source and drawing delegate contracts, and ScrollableGraphView.swift orchestrates the main UIScrollView container.

👥Who it's for

iOS app developers building dashboard or financial tracking UIs who need performant, customizable graphs without external dependencies like Charts or Core Plot. Specifically developers who want range-adaptive behavior and multi-plot support with minimal configuration.

🌱Maturity & risk

Production-ready and actively maintained (Version 4 released 9-7-2017 with breaking API changes showing intentional evolution). The Swift-heavy codebase (136KB) suggests maturity; however, lacking explicit test suite visibility and CI configuration. Last activity and star count not provided in data, but CocoaPods/Carthage support confirms established distribution.

Single-maintainer project (philackm) creates bus-factor risk. Version 4 introduced breaking API changes with no backward compatibility, requiring careful migration planning. Absence of visible test infrastructure or CI pipeline (not in file list) means quality assurance relies on manual testing. No dependency on external frameworks visible, reducing supply-chain risk.

Active areas of work

APIv4.md documents recent major version release introducing multiple plots, dynamic value reloading, and reference line customization. The GraphView demo project in the repository tree indicates ongoing example/test coverage maintenance. No active PR data visible in provided file structure.

🚀Get running

Clone: git clone https://github.com/philackm/ScrollableGraphView.git. Install: CocoaPods (pod install if Podfile exists) or Carthage (carthage update), or manually copy Classes/ directory. Run: Open GraphView/GraphView.xcodeproj in Xcode and build for simulator.

Daily commands: Open GraphView/GraphView.xcodeproj in Xcode, select a simulator or device target, press Cmd+R. The example app in GraphView/GraphView/ demonstrates multi-plot rendering with interactive scrolling.

🗺️Map of the codebase

  • Classes/ScrollableGraphView.swift — Main entry point and orchestrator for the entire graph component; handles data binding, plot management, and rendering lifecycle
  • Classes/Plots/Plot.swift — Abstract base class defining the plot interface; all concrete plots (Line, Bar, Dot) inherit from this
  • Classes/Drawing/ScrollableGraphViewDrawingLayer.swift — Core drawing abstraction that manages all visual layer rendering; critical for performance and composition
  • Classes/Protocols/ScrollableGraphViewDataSource.swift — Data source protocol defining how external data flows into the graph; required by all consumers
  • Classes/Plots/BarPlot.swift — Example concrete plot implementation showing composition of drawing layers; reference for extending with new plot types
  • Classes/Reference/ReferenceLines.swift — Manages reference line rendering and label pooling; handles adaptive label placement for readability
  • Classes/Plots/Animation/GraphPointAnimation.swift — Drives all initialization and update animations; critical for smooth visual transitions

🛠️How to make changes

Add a New Plot Type

  1. Create a new Swift file in Classes/Plots/ that subclasses Plot.swift and implements required methods (setupLayers, animationDidFinish, etc.) (Classes/Plots/Plot.swift)
  2. Implement plot-specific drawing layer composition by instantiating and configuring drawing layers from Classes/Drawing/ (Classes/Plots/BarPlot.swift)
  3. Register the drawing layers in setupLayers() so they render in correct order (Classes/Drawing/ScrollableGraphViewDrawingLayer.swift)
  4. Add initialization example to GraphViewCode/Examples.swift demonstrating configuration of your new plot type (GraphView/GraphViewCode/Examples.swift)

Customize Graph Rendering with Drawing Delegate

  1. Implement ScrollableGraphViewDrawingDelegate protocol in your view controller (Classes/Protocols/ScrollableGraphViewDrawingDelegate.swift)
  2. Assign your view controller as drawingDelegate to the ScrollableGraphView instance (Classes/ScrollableGraphView.swift)
  3. Override delegate methods to modify drawing behavior (e.g., custom layer configuration, post-render adjustments) (Classes/Drawing/ScrollableGraphViewDrawingLayer.swift)

Implement Data Source and Integrate Graph

  1. Conform your view controller to ScrollableGraphViewDataSource protocol (Classes/Protocols/ScrollableGraphViewDataSource.swift)
  2. Implement getValue(at:plot:) method returning Float values for each data point index (Classes/Protocols/ScrollableGraphViewDataSource.swift)
  3. Create and configure ScrollableGraphView with plots and assign self as dataSource in viewDidLoad or setupUI (Classes/ScrollableGraphView.swift)
  4. Call reloadData() on the graph view whenever your underlying data changes (Classes/ScrollableGraphView.swift)

Customize Reference Lines and Labels

  1. Configure ReferenceLines properties (backgroundColor, textColor, labelFont, etc.) on your ScrollableGraphView instance (Classes/Reference/ReferenceLines.swift)
  2. Set numberOfInterlinesY and numberOfInterlinesX to control reference line density (Classes/Reference/ReferenceLines.swift)
  3. The LabelPool automatically reuses UILabel instances for efficient scrolling; no manual configuration needed (Classes/Reference/LabelPool.swift)

🔧Why these technologies

  • Swift — Modern iOS development language with strong type safety; cleaner syntax than Objective-C for layer composition
  • CALayer & CABasicAnimation — Core graphics framework for efficient, GPU-accelerated 2D rendering and smooth property animations without redrawing
  • UIScrollView (implicit) — Provides native horizontal scrolling with momentum and deceleration; graph content extends beyond visible frame
  • Object pooling (LabelPool) — Reuses UILabel instances during scrolling to prevent memory churn and improve frame rate with many reference labels

⚖️Trade-offs already made

  • Data source protocol rather than direct data array property

    • Why: Allows app to provide data dynamically without storing graph-owned copy; supports very large datasets via lazy evaluation
    • Consequence: Requires data source implementation from consumer; slightly more boilerplate but more flexible
  • Multiple CALayers per plot (line + gradient + dots) rather than single custom view

    • Why: Composition allows independent animation and styling of each visual element; easier to add/remove layers
    • Consequence: More layer objects in hierarchy; potential performance cost with very complex graphs (many plots × many layers)
  • Animation-driven by GraphPointAnimation keyframes rather than direct CADisplayLink

    • Why: Decouples animation timing from rendering; easier to test and synchronize across multiple plots
    • Consequence: Keyframe data must be pre-computed; less fine-grained control over per-frame rendering
  • Reference lines drawn as separate view layer rather than baked into main graph CALayers

    • Why: Allows independent styling and label management; scrolling coordinate system can differ from plot content
    • Consequence: Requires separate coordinate space mapping; potential z-order complexity with plots

🚫Non-goals (don't propose these)

  • Does not handle real-time streaming data updates (designed for discrete datasets that change at app level)
  • Does not persist graph state or data; consumer owns serialization
  • Does not provide built-in data transformation or aggregation; expects pre-processed Float arrays
  • Does not support 3D visualizations or complex chart types (heat maps, treemaps, network graphs)
  • Does not include accessibility features (VoiceOver, Dynamic Type) in core implementation

🪤Traps & gotchas

No explicit minimum iOS version stated in file list; check Info.plist or podspec for deployment target. The multi-plot feature introduced in v4 may have undocumented interaction rules when mixing LinePlot + BarPlot. Range adaptation logic in ScrollableGraphView likely has edge cases with single-point datasets or datasets where all values are identical. Drawing layer coordinate transforms assume specific scroll bounds—manual scrollView contentSize manipulation outside the library may break rendering.

🏗️Architecture

💡Concepts to learn

  • CALayer-based custom drawing — ScrollableGraphView renders graphs via CABasicAnimation and CAShapeLayer, not UIView—understanding layer-level coordinate transforms and rendering pipelines is essential to modifying draw behavior
  • Range adaptation algorithm — The library's core feature recalculates y-axis min/max from visible scroll bounds; understanding how scroll offset maps to data indices and triggers re-layout prevents bugs when adding new plot types
  • Protocol-oriented design (ScrollableGraphViewDataSource) — Data decoupling via protocols follows Swift best practices; contributors must implement this interface to provide custom data sources without modifying core graph logic
  • CABasicAnimation with CADisplayLink timing — GraphPointAnimation chains animations for smooth coordinate transitions; misunderstanding animation stacking or timing can cause jank or visual artifacts in range adaptations
  • Label pooling and reuse — LabelPool recycles CATextLayers to avoid allocation churn during rapid reference line updates; this memory optimization pattern is non-obvious and critical for scroll performance
  • UIScrollView content offset mapping to data indices — The library translates horizontal scroll position into which data points are visible; understanding this coordinate space mapping is essential for implementing custom scroll behaviors or range predicates
  • danielgindi/Charts — Feature-rich iOS charting library supporting line, bar, scatter, candlestick; direct competitor with broader capabilities but higher complexity
  • core-plot/core-plot — Objective-C charting framework predating ScrollableGraphView; shows alternative CALayer-based rendering approach for iOS graphics
  • instagram/IGListKit — Demonstrates similar Swift UIKit modernization and data-driven rendering patterns used in ScrollableGraphView's plot/layer abstraction
  • ReactiveCocoa/ReactiveCocoa — Functional reactive patterns could enhance ScrollableGraphView's data source updates and animation state management (currently imperative)
  • airbnb/lottie-ios — Shows advanced CALayer animation techniques that could improve GraphPointAnimation smoothness and customization

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add unit tests for Drawing layers (BarDrawingLayer, LineDrawingLayer, etc.)

The Classes/Drawing directory contains 5 drawing layer implementations but there's no evidence of unit tests. These are core rendering components that would benefit from tests validating coordinate calculations, layer positioning, and animation behavior. This would prevent regressions when refactoring drawing logic.

  • [ ] Create Tests/ directory structure mirroring Classes/Drawing/
  • [ ] Add unit tests for LineDrawingLayer.swift validating path generation and point calculations
  • [ ] Add unit tests for BarDrawingLayer.swift validating bar width, spacing, and positioning logic
  • [ ] Add unit tests for GradientDrawingLayer.swift and FillDrawingLayer.swift color/gradient application
  • [ ] Configure XCTest target in GraphView.xcodeproj/project.pbxproj if not present

Add unit tests for Plot classes (LinePlot, BarPlot, DotPlot) and animation system

The Classes/Plots directory has Plot.swift base class and specific implementations, plus Classes/Plots/Animation with GraphPoint and GraphPointAnimation. These are complex stateful components managing data transformation and animations that lack test coverage. Tests here would ensure data consistency during scrolling and animation state transitions.

  • [ ] Create Tests/Plots/ directory with test files for Plot.swift, LinePlot.swift, BarPlot.swift, DotPlot.swift
  • [ ] Add tests for GraphPointAnimation.swift validating animation state progression and completion handlers
  • [ ] Add tests validating that plots correctly transform datasource values through their respective drawing layers
  • [ ] Test edge cases: empty datasets, single points, rapid animation cancellation

Add unit tests for ScrollableGraphViewDataSource protocol implementation and data loading

The Classes/Protocols/ScrollableGraphViewDataSource.swift defines the data contract, but without tests there's no validation that implementations correctly handle edge cases. Tests should verify the main ScrollableGraphView.swift properly handles data source callbacks, particularly for dynamic reloading (mentioned in README as new in v4) and reference line calculations in Classes/Reference/ReferenceLines.swift.

  • [ ] Create Tests/DataSource/ with mock implementations of ScrollableGraphViewDataSource protocol
  • [ ] Add tests validating ScrollableGraphView.swift correctly calls datasource methods and handles nil/empty responses
  • [ ] Add tests for ReferenceLines.swift validating calculations with various min/max values and label generation from LabelPool.swift
  • [ ] Test v4 dynamic reload functionality: verify that calling reloadData() correctly updates graph without memory leaks

🌿Good first issues

  • Add XCTest unit test suite for Classes/Plots/Plot.swift and GraphPoint.swift covering animation state transitions and min/max calculation logic—currently no test directory exists despite complexity
  • Document and implement example usage snippets in APIv4.md showing how to compose BarPlot + LinePlot together with custom ReferenceLines, as the README only shows single-plot basic usage
  • Refactor Classes/Reference/LabelPool.swift to include Swift unit tests for label reuse and memory management, ensuring pooling doesn't leak CATextLayers during rapid range adaptations

Top contributors

Click to expand
  • @philackm — 86 commits
  • @kellyroach — 8 commits
  • @dhf — 2 commits
  • @apisit — 1 commits
  • [@Mike Peterson](https://github.com/Mike Peterson) — 1 commits

📝Recent commits

Click to expand
  • aa0948b — Merge pull request #151 from apisit/master (philackm)
  • 39dfcd2 — changed setting to use Swift 4.2 (apisit)
  • c404433 — Update README.md (philackm)
  • c2ced53 — Update podspec (philackm)
  • 9a5aafa — Migrate to Swift 4.2 (philackm)
  • 7c82309 — Merge pull request #144 from kellyroach/kellyroach/upgrade-to-xcode941 (philackm)
  • 2eae26c — Remove //KBR: comment (kellyroach)
  • 72fb8a8 — Add AppIcon's and LaunchImage's to both demo apps (kellyroach)
  • f2e8584 — Code and IB demo apps moved into same GraphView.xcodeproj (kellyroach)
  • 86c1ea0 — Rename graphview_example_code --> GraphView (kellyroach)

🔒Security observations

This iOS Swift project has a good security baseline. It is a UI library with no apparent network communication, database access, or external dependencies visible in the provided structure. No critical vulnerabilities detected. Minor concerns relate to input validation for color parsing and data handling, which are low-severity issues common in UI libraries. The project appears to be well-structured with clear separation of concerns (Drawing layers, Plots, Protocols). Recommendation: Conduct code review of data validation logic and color parsing implementation to ensure robustness against malformed inputs.

  • Low · Missing .gitignore entries for sensitive files — .gitignore. The .gitignore file exists but without reviewing its contents, it's unclear if sensitive files like .env, *.config, or build artifacts are properly excluded. iOS projects should exclude derived data, build folders, and CocoaPods/SPM artifacts. Fix: Ensure .gitignore includes common sensitive patterns: *.xcworkspace/xcuserdata/, DerivedData/, .env, *.config, Pods/, .DS_Store, and build artifacts.
  • Low · Potential color handling vulnerability — GraphView/GraphView/UIColor+colorFromHex.swift. The file 'UIColor+colorFromHex.swift' suggests custom hex color parsing. Custom parsing logic for color strings can be vulnerable to malformed input or unexpected values if not properly validated. Fix: Ensure the hex color parser validates input strictly: check string length, character validity (only 0-9, A-F), and handle edge cases gracefully with appropriate error handling.
  • Low · No visible input validation in data source protocol — Classes/Protocols/ScrollableGraphViewDataSource.swift. The ScrollableGraphViewDataSource protocol is used to provide data to the graph. Without reviewing the implementation, there's potential risk of insufficient validation of incoming data points that could cause crashes or unexpected behavior. Fix: Implement strict input validation for data points: verify they are numeric, within expected ranges, and handle nil/invalid values gracefully. Add bounds checking for array access.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · philackm/ScrollableGraphView — RepoPilot