@spidunno/desmos-types 1.13.2 → 1.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,11 +6,11 @@ the graphing calculator, geometry tool, 3D calculator, and the four-function and
6
6
  ## Install
7
7
 
8
8
  ```sh
9
- npm install --save-dev @spidunno/desmos-types@~1.13.2
9
+ npm install --save-dev @spidunno/desmos-types@~1.13.4
10
10
  ```
11
11
 
12
12
  The package's major and minor version match the Desmos API version it describes; patch releases
13
- are fixes to the types. Use a tilde range (`~1.13.2`), not npm's default caret (`^`), so you only
13
+ are fixes to the types. Use a tilde range (`~1.13.4`), not npm's default caret (`^`), so you only
14
14
  get type fixes for the API version you load.
15
15
 
16
16
  ## Usage
@@ -134,7 +134,7 @@ Everything here is internal to Desmos and changes between builds, even within v1
134
134
 
135
135
  | Layer | Files | Source |
136
136
  | --- | --- | --- |
137
- | Generated | `internals/generated/objects.d.ts` | The bundle loaded in jsdom; 58 internal objects walked |
137
+ | Generated | `internals/generated/objects.d.ts` | The bundle loaded in jsdom; 60 internal objects walked |
138
138
  | Generated | `internals/generated/actions.d.ts` | Every `dispatch({ type })` call site and `switch (action.type)` reducer, found with acorn. Each of the 341 actions is attributed to the reducer(s) that handle it, giving three unions: `Action` (graph controller), `MathFieldAction` and `BasicCalculatorAction` |
139
139
  | Generated | `internals/generated/views.d.ts` | Props and instance members of the 13 `Private.Fragile` views, from live instances (about 1,400 views rendered), call sites and prop reads, following `{...props}` forwarding into inner views |
140
140
  | Hand-written | `internals/*.d.ts` | Precise types for the parts mods use, checked against the bundle source |
@@ -143,7 +143,9 @@ In the generated layer, property types come from observed values. A method's ret
143
143
  static analysis of its source (nothing returned → `void`, only booleans returned → `boolean`), or from
144
144
  calling side-effect-free getters such as `get*` and `is*`. Anything that couldn't be determined is
145
145
  `unknown`, and parameters are `unknown` because the bundle is minified. Action payload field names are
146
- reliable, but their value types are often inferred from the field name.
146
+ reliable, but their value types are often inferred from the field name. A property is optional if it
147
+ held `undefined` or was added after the calculator loaded (for example, by the first animation frame
148
+ or a UI interaction).
147
149
 
148
150
  The hand-written interfaces *extend* the generated ones (`Internals.Controller extends
149
151
  Generated.Controller`, and so on). TypeScript therefore checks every hand-written type against what
@@ -158,6 +160,18 @@ What's hand-typed:
158
160
  `ImageModel` and `TickerModel` as a discriminated union (`ItemModel`), plus `ListModel`.
159
161
  - **Actions:** `Action` is the full union. About 25 common actions have checked payloads, and
160
162
  `ActionOfType<'set-item-latex'>` picks one.
163
+ - **Graph sketches** (`controller.grapher2d.graphSketches`): one `GraphSketch` per graphed
164
+ expression, holding `GraphBranch`es as a union over the 20 branch modes the 2D grapher
165
+ draws (`BranchModes` names them). Each mode's `segments` layout is typed: flat `[x, y, …]`
166
+ for most curves, `[y, x, …]` for `x = f(y)`, `[θ, r, …]` for polar, `[x, y]` tuples for
167
+ points, and fixed tuples like `[cx, cy, r]` for geometry objects. Also covered: points of
168
+ interest (`POI`, `POITypes`), sketch labels, movable points and the grapher's sketch methods.
169
+ A fixture of 60 real sketches (`test/fixtures/graph-sketches.ts`) is type-checked against
170
+ these types.
171
+ - **The rest of `grapher2d`:** the projection (math ↔ pixel conversion, with linear and log axes),
172
+ `Viewport`, the viewport controller (jump, animate, zoom, pan), `GrapherSettings` (every graph
173
+ and drawing setting, with typed `observe` / `getProperty` / `setProperty`), the `'redraw'`
174
+ event, draw layers, graph images, screenshots and grapher state.
161
175
  - **Dispatcher:** `register`, `unregister`, `waitFor`, generic over the action type.
162
176
  - **Other controllers:** each math field (`mathField.controller`) and each basic calculator
163
177
  (`calculator.controller`) has its own controller and dispatcher. Keystrokes in a math field are
@@ -184,14 +198,150 @@ What's hand-typed:
184
198
  `getReconciledExpressionProps`, `currentLanguage`, `manageFocusHelper` / `mathquillFocusHelper`,
185
199
  and `List`.
186
200
 
201
+ ### Graph sketches
202
+
203
+ `controller.grapher2d.graphSketches` holds what the 2D grapher draws, keyed by expression id. Each
204
+ sketch has `branches`, and each branch has a numeric `branchMode` that tells you what it is and
205
+ how to read its `segments`. One expression often produces several branches: one per list element,
206
+ boundary curves plus a fill for an inequality, an outline plus a fill for a polygon.
207
+
208
+ The examples below are plain JavaScript, so you can paste them into the browser console. On
209
+ desmos.com the calculator is the global `Calc`; in your own page it's whatever you called
210
+ `Desmos.GraphingCalculator(...)`. desmos.com runs the same v1.13 line, but it is redeployed
211
+ continuously, so an internal field can change before these types are regenerated.
212
+
213
+ ```js
214
+ // Every branch of every sketch, with its mode
215
+ for (const [id, sketch] of Object.entries(Calc.controller.grapher2d.graphSketches)) {
216
+ console.log(id, sketch.branches.map((b) => b.branchMode));
217
+ }
218
+ ```
219
+
220
+ #### Branch modes
221
+
222
+ | Mode | Name | Drawn for | `segments` | Other notable fields |
223
+ | ---: | --- | --- | --- | --- |
224
+ | 1 | X | `x = f(y)`, `x` inequalities | flat `[y0, x0, y1, x1, …]` (**y first**) | `operator`, `compiled`, `poi` |
225
+ | 2 | Y | `y = f(x)`, `y` inequalities, distributions, solvable implicit equations | flat `[x0, y0, x1, y1, …]` | `operator`, `compiled`, `poi`, `boundingBox` |
226
+ | 3 | XYPOINT | points, point lists, dot plots | arrays of `[x, y]` | `labels`, `pointSize`, `pointOpacity`, `showLabel` |
227
+ | 4 | XYPOINT_MOVABLE | draggable points | arrays of `[x, y]` | `movablePointInfo` |
228
+ | 5 | PARAMETRIC | parametrics, point-list and table lines, polygon outlines, box plots | flat `[x0, y0, …]` | `compiled`, `tableId` |
229
+ | 6 | POLAR | `r = f(θ)`, polar inequalities | flat `[θ0, r0, θ1, r1, …]` (**polar**) | `sampledDomain` |
230
+ | 7 | POLYGONFILL | inequality shading, polygon and parametric fills, histogram bars | flat `[x0, y0, …]` polygons (empty for inequality shading) | `fillOpacity` |
231
+ | 8 | IMPLICIT | implicit curves | flat `[x0, y0, …]` | `compiled` |
232
+ | 15 | ERROR | an expression that failed while graphing | `[]` | `error` (`{ key, vars }`) |
233
+ | 17 | SEGMENT | `segment` | `[x1, y1, x2, y2]` | `arrowMode` |
234
+ | 18 | LINE | `line` | `[x1, y1, x2, y2]`: two points on the line | `arrowMode` |
235
+ | 19 | RAY | `ray` | `[startX, startY, throughX, throughY]` | `arrowMode` |
236
+ | 20 | CIRCLE | `circle` | `[cx, cy, r]` | |
237
+ | 21 | ARC | `arc` | `[cx, cy, r, startAngle, endAngle]` | |
238
+ | 22 | LABEL | label of a segment, polygon or angle | placement data | `labels` (text), `objectType` (17, 16 or 23) |
239
+ | 23 | ANGLE_MARKER | `angle`, `directedangle` | `[vx, vy, startAngle, angle, directed]` | |
240
+ | 24 | VECTOR | `vector` | `[tailX, tailY, headX, headY]` | `arrowMode` |
241
+ | 25 | COMPLEX_NUMBER | complex numbers in complex mode | arrays of `[re, im]` | like XYPOINT |
242
+ | 26 | COMPLEX_NUMBER_MOVABLE | draggable complex numbers | arrays of `[re, im]` | `movablePointInfo` |
243
+ | 27 | IMAGE | images | `[]` | `dimensions` (`x`, `y`, `width`, `height`, `radianAngle`, `opacity`) |
244
+
245
+ Modes 17–24 only appear in the geometry tool. Angles are in radians. In each row, `segments` is a
246
+ list of these: a curve broken at discontinuities has several flat arrays, and a list of circles has
247
+ several `[cx, cy, r]` entries. In TypeScript, hovering `branchMode` shows this table, and comparing
248
+ it to a number (`branch.branchMode === 20`) narrows the branch to that mode's type.
249
+
250
+ #### Points of interest
251
+
252
+ `sketch.getPOI()` returns the points of interest the grapher shows when an expression is selected.
253
+ `poi.type` is:
254
+
255
+ | Type | Meaning | Comes from |
256
+ | ---: | --- | --- |
257
+ | 1001 | intersection | `X` / `Y` branches |
258
+ | 1002 | zero (root) | `X` / `Y` branches |
259
+ | 1003 | axis intercept | `X` / `Y` branches |
260
+ | 1004 | extremum | `X` / `Y` branches |
261
+ | 1006 | plotted point without a visible label | point branches |
262
+ | 1008 | labeled point, or a geometry label's anchor | point branches, labels |
263
+
264
+ #### Examples
265
+
266
+ ```js
267
+ const sketches = Calc.controller.grapher2d.graphSketches;
268
+
269
+ // Turn any curve branch into a list of {x, y} points, handling the modes
270
+ // whose coordinates aren't (x, y)
271
+ function curvePoints(branch) {
272
+ const points = [];
273
+ for (const flat of branch.segments) {
274
+ for (let i = 0; i < flat.length; i += 2) {
275
+ const [a, b] = [flat[i], flat[i + 1]];
276
+ if (branch.branchMode === 1) points.push({ x: b, y: a }); // x = f(y): (y, x)
277
+ else if (branch.branchMode === 6) points.push({ x: b * Math.cos(a), y: b * Math.sin(a) }); // polar: (θ, r)
278
+ else points.push({ x: a, y: b });
279
+ }
280
+ }
281
+ return points;
282
+ }
283
+
284
+ // Circles in the geometry tool
285
+ for (const sketch of Object.values(sketches)) {
286
+ for (const branch of sketch.branches) {
287
+ if (branch.branchMode === 20) {
288
+ for (const [cx, cy, r] of branch.segments) console.log(`circle at (${cx}, ${cy}), radius ${r}`);
289
+ }
290
+ }
291
+ }
292
+
293
+ // Extrema of the expression with id "1"
294
+ sketches['1']?.getPOI().filter((poi) => poi.type === 1004).map((poi) => [poi.x, poi.y]);
295
+
296
+ // Draggable points, with table row info for table columns
297
+ sketches['1']?.getMovablePoints().map((p) => ({ x: p.x, y: p.y, row: p.tableInfo?.rowIndex }));
298
+ ```
299
+
300
+ ### Projection, viewport and settings
301
+
302
+ `grapher2d.getProjection()` converts between math coordinates and pixels (CSS pixels from the
303
+ graph paper's top-left, y down). The projection is replaced whenever you pan, zoom or resize, so
304
+ get a fresh one each time instead of keeping it.
305
+
306
+ ```js
307
+ const g = Calc.controller.grapher2d;
308
+
309
+ // Math ↔ pixels
310
+ const p = g.getProjection();
311
+ p.map_pt({ x: 0, y: 0 }); // where the origin is on screen
312
+ p.reverse_map_pt({ x: 100, y: 100 }); // the math point under pixel (100, 100)
313
+ p.mathToPixels.dangerouslyGetXScaleFactor(); // pixels per unit (throws on a log axis)
314
+
315
+ // The viewport
316
+ g.getCurrentViewport(); // { xmin, xmax, ymin, ymax }
317
+ g.viewportController.animateToViewport({ xmin: -5, xmax: 5, ymin: -5, ymax: 5 });
318
+ g.viewportController.zoom('in'); // 'in' | 'out' | 'square' | 'default'
319
+
320
+ // Settings: graph settings plus drawing settings like labelSize and graphLineWidth
321
+ g.settings.observe('showGrid.myMod', (name, settings) => console.log(name, settings.showGrid));
322
+ g.settings.setProperty('showGrid', false);
323
+ g.settings.unobserve('.myMod'); // remove every observer in the myMod namespace
324
+
325
+ // Run code after each redraw (the callback gets the redraw time in ms)
326
+ g.events.observeEvent('redraw.myMod', (event, ms) => console.log(`redrew in ${ms}ms`));
327
+ g.events.unobserveEvent('.myMod');
328
+ ```
329
+
330
+ Moving the viewport this way doesn't add an undo step. Call
331
+ `g.debounceUserRequestedViewportChange()` afterwards if you want one.
332
+
187
333
  ### Regenerating for a new bundle
188
334
 
189
335
  ```sh
190
336
  curl -o calculator.js "https://www.desmos.com/api/v1.13/calculator.js?apiKey=YOUR_API_KEY"
191
337
  npm run generate:internals -- calculator.js
338
+ npm run snapshot:sketches -- calculator.js
192
339
  npm test
193
340
  ```
194
341
 
342
+ `snapshot:sketches` re-renders real graph sketches into `test/fixtures/graph-sketches.ts`. If a
343
+ branch shape changed, `npm test` reports which field of which branch mode no longer matches.
344
+
195
345
  The generator executes the bundle inside jsdom, so only run it on a bundle from desmos.com.
196
346
  If `npm test` fails afterwards, the bundle changed in a way that contradicts a hand-written type.
197
347
  The error names the field.
@@ -18,7 +18,7 @@ declare namespace Desmos.Internals.Generated {
18
18
  bugsnagContext: string;
19
19
  cachedGeoTokenDepths: Record<string, Array<Record<string, unknown>>>;
20
20
  canShowKeyboardShortcuts: boolean;
21
- checkSlowAnalysis: boolean;
21
+ checkSlowAnalysis?: boolean;
22
22
  clipboardHandlers: Record<string, (arg0?: any) => unknown>;
23
23
  cooperativeGestureHint?: unknown;
24
24
  cooperativeGestureHintTimeout?: unknown;
@@ -51,7 +51,7 @@ declare namespace Desmos.Internals.Generated {
51
51
  isExpressionReplaceStrValidForReplace: boolean;
52
52
  isExpressionSearchStrValidForReplace: boolean;
53
53
  lastCursorContext?: unknown;
54
- lastFrameTime: number;
54
+ lastFrameTime?: number;
55
55
  lastInfiniteScrollFirstDOM: HTMLDivElement;
56
56
  lastInfiniteScrollLastDOM: HTMLDivElement;
57
57
  lastParsableObjects: { abstract_item_2: Record<string, unknown>; abstract_item_3: Record<string, unknown>; abstract_item_4: Record<string, unknown>; abstract_item_5: Record<string, unknown>; abstract_item_6: Record<string, unknown>; abstract_item_7: { type: string; id: string; center: string; angle: string; width: string; height: string; opacity: string; mask: string; clickableInfo: Record<string, unknown>; description: string; draggable: boolean; moduleId?: unknown; guid: string; index: number; color: string; shouldGraph: boolean; showPoints: boolean }; abstract_item_8: { type: string; id: string; columns: Array<Record<string, unknown>>; regression?: unknown }; dcg_ticker_guid_internal: { type: string; id: string; handlerLatex: string; minStepLatex: string; shouldGraph: boolean }; dcg_viewport_statement_id_internal: { type: string; id: string; viewport: Record<string, unknown> } };
@@ -66,7 +66,7 @@ declare namespace Desmos.Internals.Generated {
66
66
  pinchZoom: number;
67
67
  progressUpdateLegendHidden: boolean;
68
68
  raw(arg0?: unknown, arg1?: unknown): unknown;
69
- requestedEvaluatorRestart: boolean;
69
+ requestedEvaluatorRestart?: boolean;
70
70
  rootElt: HTMLDivElement;
71
71
  s(arg0?: unknown, arg1?: unknown): unknown;
72
72
  sendActionToIframeConnect(): void;
@@ -1024,7 +1024,7 @@ declare namespace Desmos.Internals.Generated {
1024
1024
  imageLayer: Grapher2DImageLayer;
1025
1025
  isVisible: boolean;
1026
1026
  lastActiveToken: { selected?: unknown; hovered?: unknown };
1027
- lastTickViewport: Grapher2DLastTickViewport;
1027
+ lastTickViewport?: Grapher2DLastTickViewport;
1028
1028
  markLabelsDirty(): unknown;
1029
1029
  movablePointsLayer: Grapher2DMovablePointsLayer;
1030
1030
  poiController: Grapher2DPoiController;
@@ -1120,7 +1120,7 @@ declare namespace Desmos.Internals.Generated {
1120
1120
  graphLineWidth: number;
1121
1121
  guid: string;
1122
1122
  hideCustomColors: boolean;
1123
- highlight?: unknown;
1123
+ highlight?: boolean;
1124
1124
  highlightPropertyMultipliers: Record<string, number[]>;
1125
1125
  includeFunctionParametersInRandomSeed: boolean;
1126
1126
  labelHangingColor: string;