gum-jsx 1.6.2 → 1.6.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.
Files changed (60) hide show
  1. package/README.md +2 -3
  2. package/docs/code/Arc.jsx +2 -2
  3. package/docs/code/Ellipse.jsx +2 -2
  4. package/docs/code/Images.jsx +1 -1
  5. package/docs/code/Line.jsx +1 -1
  6. package/docs/code/Math.jsx +12 -10
  7. package/docs/code/Network.jsx +1 -1
  8. package/docs/code/Points.jsx +4 -1
  9. package/docs/code/Shape.jsx +1 -1
  10. package/docs/code/SymFill.jsx +1 -1
  11. package/docs/code/SymShape.jsx +3 -4
  12. package/docs/code/Tables.jsx +3 -2
  13. package/docs/text/Box.md +1 -1
  14. package/docs/text/Element.md +11 -14
  15. package/docs/text/Gum.md +5 -5
  16. package/docs/text/Math.md +2 -1
  17. package/docs/text/SymFill.md +2 -1
  18. package/docs/text/SymLine.md +2 -1
  19. package/docs/text/SymPoints.md +2 -1
  20. package/docs/text/SymShape.md +2 -1
  21. package/docs/text/SymSpline.md +1 -0
  22. package/gala/code/atomic_orbitals.jsx +1 -2
  23. package/gala/code/complex_plot.jsx +1 -1
  24. package/gala/code/pendulum_physics.jsx +3 -3
  25. package/gala/code/plot_manual.jsx +2 -2
  26. package/gala/code/polygon_slide.jsx +3 -4
  27. package/gala/code/spline_star.jsx +2 -2
  28. package/gala/code/unit_distance.jsx +96 -0
  29. package/gala/text/unit_distance.md +7 -0
  30. package/package.json +1 -1
  31. package/scripts/gum.ts +14 -11
  32. package/scripts/test.ts +0 -69
  33. package/skills/gum-jsx/SKILL.md +12 -15
  34. package/skills/gum-jsx/references/gala/atomic_orbitals.md +1 -2
  35. package/skills/gum-jsx/references/gala/complex_plot.md +1 -1
  36. package/skills/gum-jsx/references/gala/pendulum_physics.md +3 -3
  37. package/skills/gum-jsx/references/gala/plot_manual.md +2 -2
  38. package/skills/gum-jsx/references/gala/polygon_slide.md +3 -4
  39. package/skills/gum-jsx/references/gala/spline_star.md +2 -2
  40. package/skills/gum-jsx/references/geometry.md +6 -6
  41. package/skills/gum-jsx/references/layout.md +5 -2
  42. package/skills/gum-jsx/references/networks.md +1 -1
  43. package/skills/gum-jsx/references/symbolic.md +12 -8
  44. package/skills/gum-jsx/references/utilities.md +18 -14
  45. package/src/elems/core.ts +33 -13
  46. package/src/elems/geometry.ts +37 -14
  47. package/src/elems/layout.ts +5 -7
  48. package/src/elems/math.ts +9 -0
  49. package/src/elems/network.ts +4 -3
  50. package/src/elems/plot.ts +19 -35
  51. package/src/elems/symbolic.ts +30 -24
  52. package/src/eval.ts +13 -3
  53. package/src/gum.ts +9 -9
  54. package/src/lib/const.ts +2 -1
  55. package/src/lib/interp.ts +10 -4
  56. package/src/lib/parse.ts +8 -2
  57. package/src/lib/types.ts +5 -4
  58. package/src/lib/utils.ts +105 -25
  59. package/src/render.ts +7 -27
  60. package/src/types/katex.d.ts +8 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { THEME } from '../lib/theme'
4
4
  import { DEFAULTS as D, none } from '../lib/const'
5
- import { is_scalar, ensure_vector, broadcast_point, log, exp, max, sum, zip, div2, cumsum, reshape, repeat, meshgrid, padvec, normalize, mean, identity, invert, aspect_invariant, check_singleton, check_array, rect_center, rect_radius, join_limits, radial_rect, norm_side, intersperse, prefix_split, merge_points } from '../lib/utils'
5
+ import { is_scalar, ensure_vector, ensure_pair, log, exp, max, sum, zip, div2, cumsum, reshape, repeat, meshgrid, padvec, normalize, mean, identity, invert, aspect_invariant, check_singleton, check_array, rect_center, rect_radius, join_limits, radial_rect, norm_side, intersperse, prefix_split, merge_points } from '../lib/utils'
6
6
  import { wrapWidths } from '../lib/wrap'
7
7
 
8
8
  import { Context, Group, Element, Rectangle, Spacer, spec_split, align_frac, ensure_children } from './core'
@@ -328,7 +328,7 @@ function computeGridLayout(children: Element[][], rows: number, cols: number, {
328
328
  const aspect_ideal = exp(log_mu - mean(widths.map(log)) + mean(heights.map(log)))
329
329
 
330
330
  // adjust widths and heights to account for spacing
331
- const [spacex, spacey] = broadcast_point(spacing)
331
+ const [spacex, spacey] = ensure_pair(spacing)
332
332
  const [scalex, scaley] = [1 - spacex * (cols-1), 1 - spacey * (rows-1)]
333
333
  widths = widths.map(w => scalex * w)
334
334
  heights = heights.map(h => scaley * h)
@@ -382,11 +382,9 @@ class Grid extends Group {
382
382
  const aspect = aspect0 ?? aspect_ideal
383
383
 
384
384
  // make grid
385
- const rects = meshgrid(rranges, cranges).map(([ ylim, xlim ]) =>
386
- join_limits({ h: xlim, v: ylim })
387
- )
388
- const items = zip(children, rects).map(([ child, rect ]) =>
389
- child.clone({ rect })
385
+ const mesh = meshgrid(rranges, cranges)
386
+ const items = zip(children, mesh).map(([ child, [ ylim, xlim ] ]) =>
387
+ child.clone({ xrect: xlim, yrect: ylim })
390
388
  )
391
389
 
392
390
  // pass to Group
package/src/elems/math.ts CHANGED
@@ -50,6 +50,10 @@ const SYMBOL_MODE_FONT: Record<SymbolMode, FontFamily> = {
50
50
  text: 'KaTeX_Main',
51
51
  }
52
52
 
53
+ const TEX_FONT_FAMILY: Record<string, FontFamily | undefined> = {
54
+ mathbb: 'KaTeX_AMS',
55
+ }
56
+
53
57
  //
54
58
  // constants
55
59
  //
@@ -1130,6 +1134,11 @@ function convert_tree(tree: Tree | TreeNode | null, attr: Attrs = {}): WithMath
1130
1134
  } else if (type == 'text') {
1131
1135
  const { body } = tree
1132
1136
  return convert_tree(body, attr)
1137
+ } else if (type == 'font') {
1138
+ const { font, body } = tree
1139
+ const font_family = TEX_FONT_FAMILY[font]
1140
+ const font_attr = font_family == null ? {} : { font_family }
1141
+ return convert_tree(body, { ...attr, ...font_attr })
1133
1142
  } else if (type == 'accent') {
1134
1143
  const { label, base: base0 } = tree
1135
1144
  const base = convert_tree(base0, attr)
@@ -1,14 +1,14 @@
1
1
  // network elements
2
2
 
3
3
  import { THEME } from '../lib/theme'
4
- import { abs, sub2, mul2, check_singleton, is_string, rect_center, side_direc, prefix_split } from '../lib/utils'
4
+ import { abs, sub2, mul2, check_singleton, is_string, rect_center, side_direc, prefix_split, join_limits } from '../lib/utils'
5
5
 
6
6
  import { Context, Element, Group, ensure_children } from './core'
7
- import type { ElementArgs, GroupArgs } from './core'
8
7
  import { Frame } from './layout'
9
8
  import { Arrow } from './geometry'
10
9
  import { Text } from './text'
11
10
 
11
+ import type { ElementArgs, GroupArgs } from './core'
12
12
  import type { AlignValue, Point, Side } from '../lib/types'
13
13
 
14
14
  //
@@ -135,8 +135,9 @@ class Edge extends Element {
135
135
 
136
136
  class Network extends Group {
137
137
  constructor(args: GroupArgs = {}) {
138
- const { children: children0, coord, ...attr0 } = THEME(args, 'Network')
138
+ const { children: children0, xlim, ylim, coord: coord0, ...attr0 } = THEME(args, 'Network')
139
139
  const [ node_attr, edge_attr, attr ] = prefix_split([ 'node', 'edge' ], attr0)
140
+ const coord = coord0 ?? join_limits({ h: xlim, v: ylim })
140
141
  const children = ensure_children(children0)
141
142
 
142
143
  // process nodes and make label map
package/src/elems/plot.ts CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { THEME } from '../lib/theme'
4
4
  import { DEFAULTS as D, none, blue, white } from '../lib/const'
5
- import { sign, abs, linspace, invert_orient, join_limits, ensure_vector, is_scalar, is_string, is_object, ensure_singleton, check_singleton, rounder, enumerate, aspect_invariant, rect_aspect, merge_rects, expand_limits, flip_rect, resolve_limits, smoothstep, prefix_split, prefix_join } from '../lib/utils'
5
+ import { sign, abs, linspace, invert_orient, join_limits, split_limits, ensure_vector, is_scalar, is_string, is_object, ensure_singleton, check_singleton, rounder, enumerate, aspect_invariant, rect_aspect, merge_rects, expand_limits, flip_rect, resolve_limits, smoothstep, prefix_split, prefix_join } from '../lib/utils'
6
6
  import { Span } from './text'
7
7
 
8
8
  import { Element, Group, Spacer, spec_split, is_element, ensure_children } from './core'
@@ -416,10 +416,10 @@ interface LegendArgs extends ElementArgs {
416
416
 
417
417
  class Mesh extends Scale {
418
418
  constructor(args: MeshArgs = {}) {
419
- const { children: children0, locs: locs0, direc = 'h', lim = D.lim, span = D.lim, ...attr } = THEME(args, 'Mesh')
420
- const locs = auto_array(locs0, lim)
421
- const coord = join_limits({ [direc]: lim, [invert_orient(direc)]: span })
422
- super({ locs, direc, coord, span, ...attr })
419
+ const { children: children0, locs: locs0 = 10, direc = 'h', xlim, ylim, coord, ...attr } = THEME(args, 'Mesh')
420
+ const { [direc]: lim, [invert_orient(direc)]: span } = resolve_limits(xlim, ylim, coord as Rect)
421
+ const locs = auto_array(locs0, lim ?? D.lim)
422
+ super({ locs, direc, span, xlim, ylim, coord, ...attr })
423
423
  this.args = args
424
424
  }
425
425
  }
@@ -442,23 +442,9 @@ class VMesh extends Mesh {
442
442
 
443
443
  class Mesh2D extends Group {
444
444
  constructor(args: Mesh2DArgs = {}) {
445
- let { children: children0, locs, xlocs, ylocs, direc = 'h', xlim = D.lim, ylim = D.lim, xspan, yspan, ...attr } = THEME(args, 'Mesh2D')
446
-
447
- // set default values
448
- xlocs ??= locs
449
- ylocs ??= locs
450
- xspan ??= xlim
451
- yspan ??= ylim
452
-
453
- // convert locs to arrays
454
- xlocs = auto_array(xlocs, xlim)
455
- ylocs = auto_array(ylocs, ylim)
456
-
457
- // create meshes
458
- const hmesh = new HMesh({ locs: xlocs, span: yspan, lim: xlim, ...attr })
459
- const vmesh = new VMesh({ locs: ylocs, span: xspan, lim: ylim, ...attr })
460
-
461
- // pass to Group
445
+ let { children: children0, locs, xlocs, ylocs, direc = 'h', xlim, ylim, coord, ...attr } = THEME(args, 'Mesh2D')
446
+ const hmesh = new HMesh({ locs: xlocs ?? locs, xlim, ylim, coord })
447
+ const vmesh = new VMesh({ locs: ylocs ?? locs, xlim, ylim, coord })
462
448
  super({ children: [ hmesh, vmesh ], ...attr })
463
449
  this.args = args
464
450
  }
@@ -527,8 +513,8 @@ function outer_limits(children: Element[], { xlim, ylim, padding = 0 }: { xlim?:
527
513
  if (children.length == 0) return
528
514
 
529
515
  // pull in child coordinate system
530
- const coord0 = merge_rects(children.map((c: Element) => c.graphCoord()))
531
- const { xlim: xlim0, ylim: ylim0 } = resolve_limits(xlim, ylim, coord0)
516
+ const coord = merge_rects(children.map((c: Element) => c.graphCoord()))
517
+ const { h: xlim0, v: ylim0 } = resolve_limits(xlim, ylim, coord)
532
518
 
533
519
  // expand with padding
534
520
  const [ xpad, ypad ] = ensure_vector(padding, 2)
@@ -607,13 +593,13 @@ interface PlotArgs extends BoxArgs {
607
593
  class Plot extends Box {
608
594
  constructor(args: PlotArgs = {}) {
609
595
  let {
610
- children: children0, xlim, ylim, axis = true, xaxis, yaxis, xticks = 5, yticks = 5, xanchor, yanchor, grid, xgrid, ygrid, xlabel, ylabel, title, tick_size = 0.015, label_size = 0.05, label_offset = 0.125, title_size = 0.075, title_offset = 0.05, xlabel_size, ylabel_size, xlabel_offset, ylabel_offset, xtick_label_offset = 0.75, ytick_label_offset = 0.25, xtick_size, ytick_size, padding, margin, aspect: aspect0 = 'auto', clip, debug = false, ...attr0
596
+ children: children0, xlim, ylim, axis = true, xaxis, yaxis, xticks = 5, yticks = 5, xanchor, yanchor, grid, xgrid, ygrid, xlabel, ylabel, title, tick_size = 0.015, label_size = 0.05, label_offset = 0.125, title_size = 0.075, title_offset = 0.05, xlabel_size, ylabel_size, xlabel_offset, ylabel_offset, xtick_label_offset = 0.75, ytick_label_offset = 0.25, xtick_size, ytick_size, padding, margin, coord: coord0 = 'auto', aspect: aspect0 = 'auto', clip, debug = false, ...attr0
611
597
  } = THEME(args, 'Plot')
612
598
  const children = ensure_children(children0)
613
599
 
614
600
  // determine coordinate system and aspect
615
- const coord = outer_limits(children, { xlim, ylim, padding }) as Rect
616
- const [ xmin, ymin, xmax, ymax ] = coord
601
+ const coord = coord0 == 'auto' ? outer_limits(children, { xlim, ylim, padding }) : coord0
602
+ const [ xmin, ymin, xmax, ymax ] = coord ?? D.coord
617
603
  xlim = [ xmin, xmax ]
618
604
  ylim = [ ymin, ymax ]
619
605
 
@@ -666,9 +652,8 @@ class Plot extends Box {
666
652
  if (xaxis === true) xaxis = new HAxis({ ticks: xticks, lim: xlim })
667
653
  if (xaxis != null && xaxis !== false) {
668
654
  const xtick_size1 = xtick_size * (ymax - ymin)
669
- const xaxis_ylim: Limit = [ xanchor - xtick_size1, xanchor + xtick_size1 ]
670
- const xaxis_rect = join_limits({ h: xlim, v: xaxis_ylim })
671
- xaxis = xaxis.clone({ rect: xaxis_rect, ...xaxis_attr }) as HAxis
655
+ const xaxis_ylim = [ xanchor - xtick_size1, xanchor + xtick_size1 ]
656
+ xaxis = xaxis.clone({ xrect: xlim, yrect: xaxis_ylim, ...xaxis_attr }) as HAxis
672
657
  fg_elems.push(xaxis)
673
658
  }
674
659
 
@@ -676,16 +661,15 @@ class Plot extends Box {
676
661
  if (yaxis === true) yaxis = new VAxis({ ticks: yticks, lim: ylim })
677
662
  if (yaxis != null && yaxis !== false) {
678
663
  const ytick_size1 = ytick_size * (xmax - xmin)
679
- const yaxis_xlim: Limit = [ yanchor - ytick_size1, yanchor + ytick_size1 ]
680
- const yaxis_rect = join_limits({ h: yaxis_xlim, v: ylim })
681
- yaxis = yaxis.clone({ rect: yaxis_rect, ...yaxis_attr }) as VAxis
664
+ const yaxis_xlim = [ yanchor - ytick_size1, yanchor + ytick_size1 ]
665
+ yaxis = yaxis.clone({ xrect: yaxis_xlim, yrect: ylim, ...yaxis_attr }) as VAxis
682
666
  fg_elems.push(yaxis)
683
667
  }
684
668
 
685
669
  // automatic xgrid generation
686
670
  if (xgrid != null && xgrid !== false) {
687
671
  const locs = (xgrid === true && xaxis != null && xaxis !== false) ? xaxis.locs : xgrid
688
- const xgrid_elem = new HMesh({ locs: locs as number[], lim: xlim, rect: coord, ...xgrid_attr })
672
+ const xgrid_elem = new HMesh({ locs: locs as number[], ...xgrid_attr })
689
673
  bg_elems.unshift(xgrid_elem)
690
674
  } else {
691
675
  xgrid = undefined
@@ -694,7 +678,7 @@ class Plot extends Box {
694
678
  // automatic ygrid generation
695
679
  if (ygrid != null && ygrid !== false) {
696
680
  const locs = (ygrid === true && yaxis != null && yaxis !== false) ? yaxis.locs : ygrid
697
- const ygrid_elem = new VMesh({ locs: locs as number[], lim: ylim, rect: coord, ...ygrid_attr })
681
+ const ygrid_elem = new VMesh({ locs: locs as number[], ...ygrid_attr })
698
682
  bg_elems.unshift(ygrid_elem)
699
683
  } else {
700
684
  ygrid = undefined
@@ -39,12 +39,14 @@ interface SymArgsBase {
39
39
  }
40
40
 
41
41
  interface SymArgs extends SymArgsBase {
42
+ f?: ((t: number) => Point)
42
43
  fx?: ((t: number) => number)
43
44
  fy?: ((t: number) => number)
44
45
  }
45
46
 
46
47
  // determines actual values given combinations of limits, values, and functions
47
- function sympath({ fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N }: SymArgs = {}): [number[], number[], number[]] {
48
+ function sympath({ f, fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N }: SymArgs = {}): [number[], number[], number[]] {
49
+ f = ensure_function(f)
48
50
  fx = ensure_function(fx)
49
51
  fy = ensure_function(fy)
50
52
 
@@ -76,7 +78,11 @@ function sympath({ fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N }: SymArgs =
76
78
  tvals = tvals ?? linspace(...tlim, N)
77
79
 
78
80
  // compute data values
79
- if (fx != null && fy != null) {
81
+ if (f != null) {
82
+ const points = tvals.map(f)
83
+ xvals = points.map(([x, _y]) => x)
84
+ yvals = points.map(([_x, y]) => y)
85
+ } else if (fx != null && fy != null) {
80
86
  xvals = tvals.map(fx)
81
87
  yvals = tvals.map(fy)
82
88
  } else if (fy != null && xlim != null) {
@@ -119,26 +125,24 @@ interface SymPointsArgs extends SymArgs, GroupArgs {
119
125
 
120
126
  class SymPoints extends Group {
121
127
  constructor(args: SymPointsArgs = {}) {
122
- const { fx, fy, point_size = D.point, point_shape: point_shape0, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, ...attr0 } = THEME(args, 'SymPoints')
128
+ const { f, fx, fy, point_size = D.point, point_shape: point_shape0, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, ...attr0 } = THEME(args, 'SymPoints')
123
129
  const [ spec, attr ] = spec_split(attr0)
124
130
  const fsize = ensure_function(point_size)
125
131
  const fshap = ensure_shapefunc(point_shape0 ?? new Dot(attr))
126
- const { xlim, ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
132
+ const { h: xlim, v: ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
127
133
 
128
134
  // compute point values
129
135
  const [ tvals1, xvals1, yvals1 ] = sympath({
130
- fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
136
+ f, fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
131
137
  })
132
138
 
133
139
  // make points
134
140
  const points = zip(tvals1, xvals1, yvals1).filter(not_null)
135
141
 
136
142
  // make children
137
- const children = enumerate(points).map(([i, [t, x, y]]) => {
138
- const sh = fshap(x, y, t, i)
139
- const has_size = sh.args.size != null || sh.args.xsize != null || sh.args.ysize != null
140
- return sh.clone({ pos: [x, y], ...(has_size ? {} : { size: fsize(x, y, t, i) }) })
141
- })
143
+ const children = enumerate(points).map(([i, [t, x, y]]) =>
144
+ fshap(x, y, t, i).clone({ pos: [x, y], size: fsize(x, y, t, i) })
145
+ )
142
146
 
143
147
  // compute coords
144
148
  const coord = coord0 ?? detect_coords(xvals1, yvals1, xlim, ylim)
@@ -158,12 +162,12 @@ interface SymLineArgs extends SymArgs, LineArgs {
158
162
 
159
163
  class SymLine extends Line {
160
164
  constructor(args: SymLineArgs = {}) {
161
- const { fx, fy, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, ...attr } = THEME(args, 'SymLine')
162
- const { xlim, ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
165
+ const { f, fx, fy, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, ...attr } = THEME(args, 'SymLine')
166
+ const { h: xlim, v: ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
163
167
 
164
168
  // compute path values
165
169
  const [ _tvals1, xvals1, yvals1 ] = sympath({
166
- fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
170
+ f, fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
167
171
  })
168
172
 
169
173
  // get valid point pairs
@@ -187,12 +191,12 @@ interface SymSplineArgs extends SymArgs, SplineArgs {
187
191
 
188
192
  class SymSpline extends Spline {
189
193
  constructor(args: SymSplineArgs = {}) {
190
- const { fx, fy, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, curve, ...attr } = THEME(args, 'SymSpline')
191
- const { xlim, ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
194
+ const { f, fx, fy, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, curve, ...attr } = THEME(args, 'SymSpline')
195
+ const { h: xlim, v: ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
192
196
 
193
197
  // compute path values
194
198
  const [ _tvals1, xvals1, yvals1 ] = sympath({
195
- fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
199
+ f, fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
196
200
  })
197
201
 
198
202
  // get valid point pairs
@@ -216,12 +220,12 @@ interface SymShapeArgs extends SymArgs, ElementArgs {
216
220
 
217
221
  class SymShape extends Shape {
218
222
  constructor(args: SymShapeArgs = {}) {
219
- const { fx, fy, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, ...attr } = THEME(args, 'SymShape')
220
- const { xlim, ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
223
+ const { f, fx, fy, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, coord: coord0, ...attr } = THEME(args, 'SymShape')
224
+ const { h: xlim, v: ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
221
225
 
222
226
  // compute point values
223
227
  const [ _tvals1, xvals1, yvals1 ] = sympath({
224
- fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
228
+ f, fx, fy, xlim, ylim, tlim, xvals, yvals, tvals, N
225
229
  })
226
230
 
227
231
  // get valid point pairs
@@ -241,23 +245,25 @@ class SymShape extends Shape {
241
245
  //
242
246
 
243
247
  interface SymFillArgs extends SymArgsBase, GroupArgs {
248
+ f1?: ((t: number) => Point)
244
249
  fx1?: ((t: number) => number)
245
250
  fy1?: ((t: number) => number)
251
+ f2?: ((t: number) => Point)
246
252
  fx2?: ((t: number) => number)
247
253
  fy2?: ((t: number) => number)
248
254
  }
249
255
 
250
256
  class SymFill extends Fill {
251
257
  constructor(args: SymFillArgs = {}) {
252
- const { fx1, fy1, fx2, fy2, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, stroke = none, fill = gray, coord: coord0, ...attr } = THEME(args, 'SymFill')
253
- const { xlim, ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
258
+ const { f1, fx1, fy1, f2, fx2, fy2, xlim: xlim0, ylim: ylim0, tlim, xvals, yvals, tvals, N, stroke = none, fill = gray, coord: coord0, ...attr } = THEME(args, 'SymFill')
259
+ const { h: xlim, v: ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
254
260
 
255
261
  // compute point values
256
262
  const [ _tvals1, xvals1, yvals1 ] = sympath({
257
- fx: fx1, fy: fy1, xlim, ylim, tlim, xvals, yvals, tvals, N
263
+ f: f1, fx: fx1, fy: fy1, xlim, ylim, tlim, xvals, yvals, tvals, N
258
264
  })
259
265
  const [ _tvals2, xvals2, yvals2 ] = sympath({
260
- fx: fx2, fy: fy2, xlim, ylim, tlim, xvals, yvals, tvals, N
266
+ f: f2, fx: fx2, fy: fy2, xlim, ylim, tlim, xvals, yvals, tvals, N
261
267
  })
262
268
 
263
269
  // get valid point pairs
@@ -316,7 +322,7 @@ interface SymFieldArgs extends SymArgs, GroupArgs {
316
322
  class SymField extends SymPoints {
317
323
  constructor(args: SymFieldArgs = {}) {
318
324
  const { func, xlim: xlim0, ylim: ylim0, N = 10, point_size: point_size0, shape: shape0, coord: coord0, ...attr } = THEME(args, 'SymField')
319
- const { xlim, ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
325
+ const { h: xlim, v: ylim } = resolve_limits(xlim0, ylim0, coord0 as Rect)
320
326
  const shape = ensure_shapefunc(shape0 ?? default_arrow)
321
327
  const point_size = point_size0 ?? 0.25 / N
322
328
 
package/src/eval.ts CHANGED
@@ -3,13 +3,13 @@
3
3
  import type { ParseConfig } from 'papaparse'
4
4
 
5
5
  import { setTheme, type ThemeName } from './lib/theme'
6
- import { is_string } from './lib/utils'
6
+ import { is_string, ensure_pair } from './lib/utils'
7
7
  import { parseTable } from './lib/table'
8
8
  import { is_element, Svg } from './elems/core'
9
9
  import type { SvgArgs } from './elems/core'
10
10
  import { runJSX } from './lib/parse'
11
11
  import { PngImage, type PngImageArgs } from './elems/image'
12
- import type { LoadFile } from './lib/types'
12
+ import type { LoadFile, Size } from './lib/types'
13
13
 
14
14
  //
15
15
  // types
@@ -147,9 +147,19 @@ function evaluateGum(code: string, { theme, context = {}, debug = false, loadFil
147
147
  return result
148
148
  }
149
149
 
150
+ function fitSize([ w0, h0 ]: Size, rasterSize?: Size | number): Size {
151
+ if (rasterSize == null) return [ w0, h0 ]
152
+ const [ maxW, maxH ] = ensure_pair(rasterSize)
153
+ const scale = Math.min(maxW / w0, maxH / h0)
154
+ return [
155
+ Math.max(1, Math.round(w0 * scale)),
156
+ Math.max(1, Math.round(h0 * scale)),
157
+ ]
158
+ }
159
+
150
160
  //
151
161
  // export
152
162
  //
153
163
 
154
- export { ErrorNoCode, ErrorNoReturn, ErrorNoElement, ErrorGenerate, ErrorRender, runJSX, evaluateGum, parseTable }
164
+ export { ErrorNoCode, ErrorNoReturn, ErrorNoElement, ErrorGenerate, ErrorRender, runJSX, evaluateGum, parseTable, fitSize }
155
165
  export type { EvaluateArgs, TableRow, LoadTable, GumContext }
package/src/gum.ts CHANGED
@@ -5,13 +5,13 @@ import './types/linebreak.d.ts'
5
5
  import './types/katex.d.ts'
6
6
 
7
7
  import { setTheme } from './lib/theme'
8
- import { sans, mono, moji, cmoji, light, regular, bold, none, black, white, gray, blue, red, green, yellow, purple, lightgray, darkgray, e, pi, phi, r2d, d2r } from './lib/const'
9
- import { is_scalar, is_string, is_boolean, is_object, is_function, is_array, zip, reshape, split, concat, slice, sum, prod, mean, cumsum, norm, range, linspace, enumerate, repeat, meshgrid, lingrid, exp, log, log10, sin, cos, tan, abs, pow, sqrt, sign, floor, ceil, round, atan, atan2, minimum, maximum, min, max, clamp, rescale, sigmoid, logit, smoothstep, setSeed, random, uniform, normal, integer, interp, palette, polar, rounder, add2, sub2, mul2, div2, normalize } from './lib/utils'
8
+ import { sans, mono, moji, cmoji, light, regular, bold, none, black, white, gray, blue, red, green, yellow, purple, lightgray, darkgray, slate, e, pi, phi, r2d, d2r } from './lib/const'
9
+ import { is_scalar, is_string, is_boolean, is_object, is_function, is_array, zip, reshape, split, concat, slice, sum, prod, mean, cumsum, norm, range, linspace, enumerate, repeat, meshgrid, lingrid, exp, log, log10, sin, cos, tan, abs, pow, sqrt, sign, floor, ceil, round, atan, atan2, minimum, maximum, min, max, clamp, rescale, normalize, sigmoid, logit, smoothstep, setSeed, random, uniform, normal, integer, interp, palette, polar, polard, rounder, add2, sub2, mul2, div2, addn, subn, muln, divn, addc, subc, mulc, divc, conjc, normc, argc } from './lib/utils'
10
10
  import { registerFont } from './fonts/fonts'
11
11
 
12
12
  import { Context, Element, Group, Svg, Rectangle, Spacer, is_element, type ElementArgs } from './elems/core'
13
13
  import { Box, Frame, Stack, VStack, HStack, HWrap, Grid, Points, Anchor, Attach, Absolute } from './elems/layout'
14
- import { Line, UnitLine, VLine, HLine, Square, Ellipse, Arc, Circle, Dot, Ray, Shape, Triangle, Fill, VFill, HFill, Path, Command, MoveCmd, LineCmd, ArcCmd, CornerCmd, RoundedCornerCmd, CubicSplineCmd, Spline, RoundedRect, RoundedLine, ArrowHead, Arrow } from './elems/geometry'
14
+ import { Line, UnitLine, VLine, HLine, CoordLine, Segments, Square, Ellipse, Arc, Circle, Dot, Ray, Shape, Triangle, Fill, VFill, HFill, Path, Command, MoveCmd, LineCmd, ArcCmd, CornerCmd, RoundedCornerCmd, CubicSplineCmd, Spline, RoundedRect, RoundedLine, ArrowHead, Arrow } from './elems/geometry'
15
15
  import { spline1d, spline2d } from './lib/interp'
16
16
  import { Span, TextLine, Text, TextBox, TextFrame, TextStack, Bold, Italic } from './elems/text'
17
17
  import { Node, Edge, Network } from './elems/network'
@@ -27,11 +27,11 @@ const Rect = Rectangle
27
27
  type ElementConstructor = new (args: ElementArgs) => Element
28
28
 
29
29
  const CONST = {
30
- e, pi, phi, r2d, d2r, none, white, black, blue, red, green, yellow, purple, gray, lightgray, darkgray, sans, mono, moji, cmoji, light, regular, bold,
30
+ e, pi, phi, r2d, d2r, none, white, black, blue, red, green, yellow, purple, gray, lightgray, darkgray, slate, sans, mono, moji, cmoji, light, regular, bold,
31
31
  }
32
32
 
33
33
  const UTILS = {
34
- range, linspace, enumerate, repeat, meshgrid, lingrid, zip, reshape, split, concat, slice, sum, prod, mean, cumsum, min, max, minimum, maximum, norm, clamp, rescale, normalize, exp, log, log10, sin, cos, tan, abs, pow, sqrt, sign, floor, ceil, round, atan, atan2, sigmoid, logit, smoothstep, polar, rounder, interp, palette, add2, sub2, mul2, div2, spline1d, spline2d,
34
+ range, linspace, enumerate, repeat, meshgrid, lingrid, zip, reshape, split, concat, slice, sum, prod, mean, cumsum, min, max, minimum, maximum, norm, clamp, rescale, normalize, exp, log, log10, sin, cos, tan, abs, pow, sqrt, sign, floor, ceil, round, atan, atan2, sigmoid, logit, smoothstep, polar, polard, rounder, interp, palette, add2, sub2, mul2, div2, addn, subn, muln, divn, addc, subc, mulc, divc, conjc, normc, argc, spline1d, spline2d,
35
35
  }
36
36
 
37
37
  const RAND = {
@@ -39,7 +39,7 @@ const RAND = {
39
39
  }
40
40
 
41
41
  const ELEMS: Record<string, ElementConstructor> = {
42
- Element, Group, Svg, Box, Frame, Stack, VStack, HStack, HWrap, Grid, Points, Anchor, Attach, Absolute, Spacer, Ray, Line, UnitLine, HLine, VLine, Rectangle, Rect, RoundedRect, RoundedLine, Square, Ellipse, Arc, Circle, Dot, Shape, Path, Spline, Triangle, Fill, VFill, HFill, Arrow, Field, Span, TextLine, Text, TextBox, TextFrame, TextStack, Bold, Italic, LabelBox, TitleBox, TitleFrame, ArrowHead, Node, Edge, Network, SymPoints, SymLine, SymSpline, SymShape, SymFill, SymField, Bar, VBar, HBar, Bars, VBars, HBars, Scale, VScale, HScale, Label, HLabel, VLabel, Labels, HLabels, VLabels, Axis, HAxis, VAxis, OuterLabel, Mesh, HMesh, VMesh, Mesh2D, Graph, Plot, BarPlot, Legend, Slide, Latex, Tex, MathSpan, MathSymbol, MathSpacer, MathRow, MathCol, MathBox, MathRule, MathText, SupSub, Frac, Sqrt, Accent, Bracket, PngImage, SvgImage
42
+ Element, Group, Svg, Box, Frame, Stack, VStack, HStack, HWrap, Grid, Points, Anchor, Attach, Absolute, Spacer, Ray, Line, UnitLine, HLine, VLine, CoordLine, Segments, Rectangle, Rect, RoundedRect, RoundedLine, Square, Ellipse, Arc, Circle, Dot, Shape, Path, Spline, Triangle, Fill, VFill, HFill, Arrow, Field, Span, TextLine, Text, TextBox, TextFrame, TextStack, Bold, Italic, LabelBox, TitleBox, TitleFrame, ArrowHead, Node, Edge, Network, SymPoints, SymLine, SymSpline, SymShape, SymFill, SymField, Bar, VBar, HBar, Bars, VBars, HBars, Scale, VScale, HScale, Label, HLabel, VLabel, Labels, HLabels, VLabels, Axis, HAxis, VAxis, OuterLabel, Mesh, HMesh, VMesh, Mesh2D, Graph, Plot, BarPlot, Legend, Slide, Latex, Tex, MathSpan, MathSymbol, MathSpacer, MathRow, MathCol, MathBox, MathRule, MathText, SupSub, Frac, Sqrt, Accent, Bracket, PngImage, SvgImage
43
43
  }
44
44
 
45
45
  const CONTEXT = { ...CONST, ...UTILS, ...RAND, ...ELEMS }
@@ -48,10 +48,10 @@ export {
48
48
  ELEMS, CONTEXT, Context,
49
49
  setTheme, registerFont, calcPngAspect, parseTable,
50
50
  is_string, is_boolean, is_array, is_object, is_function, is_element, is_scalar,
51
- e, pi, phi, r2d, d2r, none, white, black, blue, red, green, yellow, purple, gray, lightgray, darkgray, sans, mono, moji, cmoji, light, regular, bold,
52
- range, linspace, enumerate, repeat, meshgrid, lingrid, zip, reshape, split, concat, slice, sum, prod, mean, cumsum, min, max, minimum, maximum, norm, clamp, rescale, normalize, exp, log, log10, sin, cos, tan, abs, pow, sqrt, sign, floor, ceil, round, atan, atan2, sigmoid, logit, smoothstep, polar, rounder, interp, palette, add2, sub2, mul2, div2, spline1d, spline2d,
51
+ e, pi, phi, r2d, d2r, none, white, black, blue, red, green, yellow, purple, gray, lightgray, darkgray, slate, sans, mono, moji, cmoji, light, regular, bold,
52
+ range, linspace, enumerate, repeat, meshgrid, lingrid, zip, reshape, split, concat, slice, sum, prod, mean, cumsum, min, max, minimum, maximum, norm, clamp, rescale, normalize, exp, log, log10, sin, cos, tan, abs, pow, sqrt, sign, floor, ceil, round, atan, atan2, sigmoid, logit, smoothstep, polar, polard, rounder, interp, palette, add2, sub2, mul2, div2, addn, subn, muln, divn, addc, subc, mulc, divc, conjc, normc, argc, spline1d, spline2d,
53
53
  setSeed, random, uniform, normal, integer,
54
- Element, Group, Svg, Box, Frame, Stack, HWrap, VStack, HStack, Grid, Points, Anchor, Attach, Absolute, Spacer, Ray, Line, UnitLine, HLine, VLine, Rectangle, Rect, RoundedRect, RoundedLine, Square, Ellipse, Arc, Circle, Dot, Shape, Path, Spline, Triangle, Fill, Arrow, Field, Span, TextLine, Text, TextBox, TextFrame, TextStack, Bold, Italic, LabelBox, TitleBox, TitleFrame, ArrowHead, Node, Edge, Network, SymPoints, SymLine, SymSpline, SymShape, SymFill, SymField, Bar, VBar, HBar, Bars, VBars, HBars, Scale, VScale, HScale, Label, HLabel, VLabel, Labels, HLabels, VLabels, Axis, HAxis, VAxis, OuterLabel, Mesh, HMesh, VMesh, Mesh2D, Graph, Plot, BarPlot, Legend, Slide, Latex, MathSpan, MathSymbol, MathSpacer, MathRow, MathCol, MathBox, MathRule, MathText, SupSub, Frac, Sqrt, Accent, Bracket, PngImage, SvgImage,
54
+ Element, Group, Svg, Box, Frame, Stack, HWrap, VStack, HStack, Grid, Points, Anchor, Attach, Absolute, Spacer, Ray, Line, UnitLine, HLine, VLine, CoordLine, Segments, Rectangle, Rect, RoundedRect, RoundedLine, Square, Ellipse, Arc, Circle, Dot, Shape, Path, Spline, Triangle, Fill, Arrow, Field, Span, TextLine, Text, TextBox, TextFrame, TextStack, Bold, Italic, LabelBox, TitleBox, TitleFrame, ArrowHead, Node, Edge, Network, SymPoints, SymLine, SymSpline, SymShape, SymFill, SymField, Bar, VBar, HBar, Bars, VBars, HBars, Scale, VScale, HScale, Label, HLabel, VLabel, Labels, HLabels, VLabels, Axis, HAxis, VAxis, OuterLabel, Mesh, HMesh, VMesh, Mesh2D, Graph, Plot, BarPlot, Legend, Slide, Latex, MathSpan, MathSymbol, MathSpacer, MathRow, MathCol, MathBox, MathRule, MathText, SupSub, Frac, Sqrt, Accent, Bracket, PngImage, SvgImage,
55
55
  Command, MoveCmd, LineCmd, ArcCmd, CornerCmd, RoundedCornerCmd, CubicSplineCmd,
56
56
  }
57
57
 
package/src/lib/const.ts CHANGED
@@ -32,6 +32,7 @@ const yellow = '#ffb300'
32
32
  const purple = '#9c27b0'
33
33
  const lightgray = '#f6f6f6'
34
34
  const darkgray = '#888888'
35
+ const slate = '#1e252e'
35
36
 
36
37
  // math
37
38
  const e = Math.E
@@ -55,4 +56,4 @@ const DEFAULTS = {
55
56
  calc_size: 16,
56
57
  }
57
58
 
58
- export { DEFAULTS, svgns, htmlns, sans, mono, moji, cmoji, light, regular, bold, vtext, none, black, white, gray, blue, red, green, yellow, purple, lightgray, darkgray, e, pi, phi, r2d, d2r }
59
+ export { DEFAULTS, svgns, htmlns, sans, mono, moji, cmoji, light, regular, bold, vtext, none, black, white, gray, blue, red, green, yellow, purple, lightgray, darkgray, slate, e, pi, phi, r2d, d2r }
package/src/lib/interp.ts CHANGED
@@ -53,12 +53,18 @@ function cubic_spline_data<T extends Point | MPoint>(points: T[], { start_dir, e
53
53
  })
54
54
  }
55
55
 
56
+ function cubic_spline_tangent(pos1: Point | MPoint, pos2: Point | MPoint, dir: Grad | undefined, tan: Point): Point {
57
+ if (dir == null) return tan
58
+ const delta = squeeze_mpoint(sub2m(pos2, pos1)).map(abs)
59
+ const scale = Math.max(...delta)
60
+ return mul2(dir, scale)
61
+ }
62
+
56
63
  function cubic_spline_points({ pos1, pos2, dir1, dir2, tan1, tan2, curve = 0.5 }: SplineData<Point>): [Point, Point, Point, Point] {
57
64
 
58
65
  // use dir if provided, otherwise use tan
59
- const dist = squeeze_mpoint(sub2m(pos2, pos1)).map(abs) as Point
60
- const tan1a = dir1 != null ? mul2(dir1, dist) as Point : tan1
61
- const tan2a = dir2 != null ? mul2(dir2, dist) as Point : tan2
66
+ const tan1a = cubic_spline_tangent(pos1, pos2, dir1, tan1)
67
+ const tan2a = cubic_spline_tangent(pos1, pos2, dir2, tan2)
62
68
  if (tan1a == null || tan2a == null) throw new Error('Spline tangent must be defined')
63
69
 
64
70
  // compute scaled tangents and Bernstein controls in spline coordinates
@@ -166,5 +172,5 @@ function spline1d(points: Point[], { curve = 0.5 }: { curve?: number } = {}): (t
166
172
  // export
167
173
  //
168
174
 
169
- export { cubic_spline_data, cubic_spline_points, spline1d, spline2d }
175
+ export { cubic_spline_data, cubic_spline_points, cubic_spline_tangent, spline1d, spline2d }
170
176
  export type { SplineData, SplineFuncArgs }
package/src/lib/parse.ts CHANGED
@@ -291,8 +291,14 @@ const handlers: Record<string, (node: ASTNode) => any> = {
291
291
  return body.map(walkTree).join('\n')
292
292
  },
293
293
  MethodDefinition(node) {
294
- const { key, value } = node
295
- return `${walkTree(key)}${walkTree(value)}`
294
+ const { key, value, computed, static: isStatic, kind } = node
295
+ const prefix = isStatic ? 'static ' : ''
296
+ const name = computed ? `[${walkTree(key)}]` : walkTree(key)
297
+ const params = value.params.map(walkTree).join(', ')
298
+ const body = walkTree(value.body)
299
+ if (kind == 'get') return `${prefix}get ${name}() ${body}`
300
+ if (kind == 'set') return `${prefix}set ${name}(${params}) ${body}`
301
+ return `${prefix}${name}(${params}) ${body}`
296
302
  },
297
303
  JSXIdentifier(node) {
298
304
  return node.name
package/src/lib/types.ts CHANGED
@@ -7,7 +7,9 @@ type Limit = [number, number]
7
7
  type Size = [number, number]
8
8
  type Grad = [number, number]
9
9
  type Polar = [number | Size, number]
10
- type Pair = Point | Size | Limit | Grad
10
+ type Complex = [number, number]
11
+ type Pair = Point | Size | Limit | Grad | Complex
12
+ type Vector = number[]
11
13
 
12
14
  // color
13
15
  type RGBA = [number, number, number, number]
@@ -66,11 +68,10 @@ interface CliArgs {
66
68
  theme: ThemeName
67
69
  background?: string
68
70
  size?: Size
69
- width?: number
70
- height?: number
71
+ rasterSize?: Size
71
72
  dev: boolean
72
73
  loadFile: LoadFile
73
74
  }
74
75
 
75
76
 
76
- export type { Point, Rect, Limit, Size, Grad, Polar, Pair, RGBA, MNumber, MPoint, AlignValue, Align, Zone, Side, Side0, Orient, Angle, Direc, RoundedValue, Padding, Rounded, Attrs, Spec, ThemeName, OutputFormat, LoadFileData, LoadFile, CliArgs }
77
+ export type { Point, Rect, Limit, Size, Grad, Polar, Complex, Pair, Vector, RGBA, MNumber, MPoint, AlignValue, Align, Zone, Side, Side0, Orient, Angle, Direc, RoundedValue, Padding, Rounded, Attrs, Spec, ThemeName, OutputFormat, LoadFileData, LoadFile, CliArgs }