Rootless

Automate iOS, iPadOS, and macOS using plain JavaScript. Build custom widgets and interact directly with native APIs.

Download on the App Store
Rootless app interface

Plain JavaScript

Supports ES6. Scripts are stored as plain .js files on your disk.

Native APIs & Documentation

Integrate directly with iOS native APIs. Fully documented, available offline.

Siri Shortcuts

Trigger scripts via Siri. Present tables, websites, and custom HTML natively.

System Integration

Run from the Share Sheet, process inputs, and manage local files via Files.app.

x-callback-url

Communicate seamlessly and trigger workflows with other apps on your device.

Customizable & Ready

Tailor the code editor to your liking. Includes several example scripts to start immediately.

Documentation

Also inside the app, or as rootless.json.

Chart

Bars, lines, areas and points

Marks share one pair of axes, so a line over bars is one Chart with two marks. What x is decides the axis: numbers give a numeric axis, strings a category axis, DateTimes a date axis. It is worked out from the data, and xType overrides it. Mixing kinds in one chart is an error, because no axis can hold both. Give a point a series and colour stops being a property of the mark and becomes a mapping from the data: points sharing a series share a colour, bars sitting on the same x sit side by side, and a legend appears. A mark's name sets the series for all of its points at once. Without either, a mark is one flat color, as before. In a widget a chart redraws when the timeline does, not continuously. Wrap it in Animated to move between two sets of data.

Methods

Chart(options?)WidgetNode

A chart built from one or more marks.

  • options Any
    • marks [Any] required

      Bar, Line, Area, Point and Rule, drawn in the order given.

    • colors [Color]

      The colour scale, in the order series are first seen. Left out, the system chooses. Only read when a mark uses series.

    • xAxis Any
      • visible Boolean

        Draw the axis at all. Default true.

      • grid Boolean

        Grid lines at each tick. Default true.

      • labels Boolean

        Text at each tick. Default true.

      • ticks Number

        How many ticks to aim for. The system still decides the final positions.

      • domain [Number]

        [min, max]. Left out, the data decides.

    • yAxis Any
      • visible Boolean

        Draw the axis at all. Default true.

      • grid Boolean

        Grid lines at each tick. Default true.

      • labels Boolean

        Text at each tick. Default true.

      • ticks Number

        How many ticks to aim for. The system still decides the final positions.

      • domain [Number]

        [min, max]. Left out, the data decides.

    • xType String

      number, category or date. Overrides what the data suggests.

    • width Any

      A number of points, or a Size.

    • height Any

      A number of points, or a Size.

Examples

Bars with an average line

var week = [
  { x: "Mon", y: 5 }, { x: "Tue", y: 8 }, { x: "Wed", y: 3 },
  { x: "Thu", y: 9 }, { x: "Fri", y: 6 },
];
var mean = week.reduce(function (t, d) { return t + d.y; }, 0) / week.length;

Script.setWidget(new Widget({
  padding: EdgeInsets.all(12),
  child: Chart({
    marks: [
      Bar({ data: week, color: Color.blue() }),
      Rule({ value: mean, color: Color.orange() }),
    ],
    xAxis: { grid: false },
    yAxis: { ticks: 3 },
  }),
}));

Bars grouped by series

var sales = [
  { x: "Mon", y: 5, series: "North" }, { x: "Mon", y: 3, series: "South" },
  { x: "Tue", y: 8, series: "North" }, { x: "Tue", y: 6, series: "South" },
  { x: "Wed", y: 4, series: "North" }, { x: "Wed", y: 7, series: "South" },
];

Script.setWidget(new Widget({
  padding: EdgeInsets.all(12),
  child: Chart({
    marks: [Bar({ data: sales })],
    colors: [Color.blue(), Color.orange()],
  }),
}));