@kanzo-tech/graph 0.24.0 → 0.26.0

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 (71) hide show
  1. package/dist/core/categories.d.ts +1 -1
  2. package/dist/core/categories.d.ts.map +1 -1
  3. package/dist/core/categories.js.map +1 -1
  4. package/dist/core/channels.d.ts +12 -6
  5. package/dist/core/channels.d.ts.map +1 -1
  6. package/dist/core/channels.js +15 -12
  7. package/dist/core/channels.js.map +1 -1
  8. package/dist/core/client.d.ts +26 -0
  9. package/dist/core/client.d.ts.map +1 -0
  10. package/dist/core/client.js +62 -0
  11. package/dist/core/client.js.map +1 -0
  12. package/dist/core/error.d.ts +3 -3
  13. package/dist/core/error.d.ts.map +1 -1
  14. package/dist/core/error.js.map +1 -1
  15. package/dist/core/load.d.ts +30 -39
  16. package/dist/core/load.d.ts.map +1 -1
  17. package/dist/core/load.js +63 -117
  18. package/dist/core/load.js.map +1 -1
  19. package/dist/core/source.d.ts +90 -0
  20. package/dist/core/source.d.ts.map +1 -0
  21. package/dist/core/source.js +105 -0
  22. package/dist/core/source.js.map +1 -0
  23. package/dist/core/state.d.ts +19 -20
  24. package/dist/core/state.d.ts.map +1 -1
  25. package/dist/core/store.d.ts.map +1 -1
  26. package/dist/core/store.js +137 -157
  27. package/dist/core/store.js.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/parts/graph-canvas.d.ts.map +1 -1
  30. package/dist/parts/graph-canvas.js +49 -48
  31. package/dist/parts/graph-canvas.js.map +1 -1
  32. package/dist/parts/graph-counts.js +4 -4
  33. package/dist/parts/graph-counts.js.map +1 -1
  34. package/dist/parts/graph-inspector.d.ts +3 -3
  35. package/dist/parts/graph-inspector.d.ts.map +1 -1
  36. package/dist/parts/graph-inspector.js +45 -43
  37. package/dist/parts/graph-inspector.js.map +1 -1
  38. package/dist/parts/graph-search.d.ts +7 -7
  39. package/dist/parts/graph-search.d.ts.map +1 -1
  40. package/dist/parts/graph-search.js +60 -69
  41. package/dist/parts/graph-search.js.map +1 -1
  42. package/dist/parts/graph-toolbar.js +1 -1
  43. package/dist/parts/graph-toolbar.js.map +1 -1
  44. package/dist/react/use-graph.js +31 -31
  45. package/dist/react/use-graph.js.map +1 -1
  46. package/dist/render/graph-sim.d.ts +1 -1
  47. package/dist/render/graph-sim.d.ts.map +1 -1
  48. package/dist/render/graph-sim.js.map +1 -1
  49. package/dist/render/motion.d.ts +33 -0
  50. package/dist/render/motion.d.ts.map +1 -0
  51. package/dist/render/motion.js +19 -0
  52. package/dist/render/motion.js.map +1 -0
  53. package/dist/render/placement.d.ts +2 -4
  54. package/dist/render/placement.d.ts.map +1 -1
  55. package/dist/render/placement.js +12 -16
  56. package/dist/render/placement.js.map +1 -1
  57. package/dist/render/renderer.d.ts +6 -5
  58. package/dist/render/renderer.d.ts.map +1 -1
  59. package/dist/render/renderer.js +124 -113
  60. package/dist/render/renderer.js.map +1 -1
  61. package/dist/section.js +1 -1
  62. package/dist/section.js.map +1 -1
  63. package/package.json +8 -10
  64. package/dist/core/detail.d.ts +0 -26
  65. package/dist/core/detail.d.ts.map +0 -1
  66. package/dist/core/detail.js +0 -63
  67. package/dist/core/detail.js.map +0 -1
  68. package/dist/core/filter.d.ts +0 -23
  69. package/dist/core/filter.d.ts.map +0 -1
  70. package/dist/core/filter.js +0 -95
  71. package/dist/core/filter.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { Binding } from './channels';
2
- import { VertexTable } from '@fossil-lang/corpus';
2
+ import { VertexTable } from './source';
3
3
  /**
4
4
  * **The categorical domain, fixed before the graph loads.** Colour by vertex type ranks the drawn
5
5
  * tables in the manifest's order; a column ranks by the keys of the host's `categories`. Only a value
@@ -1 +1 @@
1
- {"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/core/categories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACvD,SAAS,OAAO,EAAE,CAIpB;AAED,oEAAoE;AACpE,eAAO,MAAM,MAAM,GAAI,OAAO,OAAO,EAAE,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,KAAG,MAC7C,CAAC;AAEtD;;;;GAIG;AACH,qBAAa,UAAU;;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAM;gBAIpB,IAAI,GAAE,SAAS,OAAO,EAAO;IAKzC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAW5B,2EAA2E;IAC3E,KAAK,IAAI,WAAW;CAUrB"}
1
+ {"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/core/categories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,SAAS,WAAW,EAAE,EAC9B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACvD,SAAS,OAAO,EAAE,CAIpB;AAED,oEAAoE;AACpE,eAAO,MAAM,MAAM,GAAI,OAAO,OAAO,EAAE,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,KAAG,MAC7C,CAAC;AAEtD;;;;GAIG;AACH,qBAAa,UAAU;;IACrB,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAM;gBAIpB,IAAI,GAAE,SAAS,OAAO,EAAO;IAKzC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;IAW5B,2EAA2E;IAC3E,KAAK,IAAI,WAAW;CAUrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"categories.js","sources":["../../src/core/categories.ts"],"sourcesContent":["import type { Binding } from \"./channels\";\nimport type { VertexTable } from \"@fossil-lang/corpus\";\n\n/**\n * **The categorical domain, fixed before the graph loads.** Colour by vertex type ranks the drawn\n * tables in the manifest's order; a column ranks by the keys of the host's `categories`. Only a value\n * neither names is ranked as it is seen, after them.\n */\nexport function domainOf(\n tables: readonly VertexTable[],\n binding: Binding,\n categories: Readonly<Record<string, string>> | undefined,\n): readonly unknown[] {\n if (binding.byTable) return tables.map((table) => table.name);\n if (binding.category === undefined) return [];\n return categories ? Object.keys(categories) : [];\n}\n\n/** What a legend, a card or an inspector calls a category value. */\nexport const nameOf = (value: unknown, categories: Readonly<Record<string, string>> | undefined): string =>\n categories?.[String(value)] ?? String(value ?? \"—\");\n\n/**\n * Values to codes, in the order first seen. **The seed ranks first, in its own order**, so a colour\n * is decided before a row arrives; a value outside it is ranked after the seed, numbers before\n * strings. Values meet by their text, so a column's `0` is the host's key `\"0\"`.\n */\nexport class Dictionary {\n readonly values: unknown[] = [];\n readonly #codes = new Map<string | null, number>();\n readonly #seeded: number;\n\n constructor(seed: readonly unknown[] = []) {\n for (const value of seed) this.code(value);\n this.#seeded = this.values.length;\n }\n\n code(value: unknown): number {\n const key = value === null || value === undefined ? null : String(value);\n let code = this.#codes.get(key);\n if (code === undefined) {\n code = this.values.length;\n this.values.push(typeof value === \"bigint\" ? Number(value) : (value ?? null));\n this.#codes.set(key, code);\n }\n return code;\n }\n\n /** Each code's rank: the seed's own order, then every other value seen. */\n ranks(): Uint32Array {\n const ranks = new Uint32Array(this.values.length);\n for (let code = 0; code < this.#seeded; code++) ranks[code] = code;\n const rest = this.values.slice(this.#seeded).map((value, i) => ({ value, code: this.#seeded + i }));\n rest.sort((a, b) => compare(a.value, b.value));\n rest.forEach(({ code }, i) => {\n ranks[code] = this.#seeded + i;\n });\n return ranks;\n }\n}\n\nfunction compare(a: unknown, b: unknown): number {\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n if (typeof a === \"number\") return -1;\n if (typeof b === \"number\") return 1;\n return String(a ?? \"\").localeCompare(String(b ?? \"\"));\n}\n"],"names":["domainOf","tables","binding","categories","table","nameOf","value","_codes","_seeded","Dictionary","seed","__publicField","__privateAdd","__privateSet","key","code","__privateGet","ranks","rest","a","b","compare"],"mappings":";;;;;;;AAQO,SAASA,EACdC,GACAC,GACAC,GACoB;AACpB,SAAID,EAAQ,UAAgBD,EAAO,IAAI,CAACG,MAAUA,EAAM,IAAI,IACxDF,EAAQ,aAAa,SAAkB,CAAA,IACpCC,IAAa,OAAO,KAAKA,CAAU,IAAI,CAAA;AAChD;AAGO,MAAME,IAAS,CAACC,GAAgBH,OACrCA,KAAA,gBAAAA,EAAa,OAAOG,CAAK,OAAM,OAAOA,KAAS,GAAG;AAZ7C,IAAAC,GAAAC;AAmBA,MAAMC,EAAW;AAAA,EAKtB,YAAYC,IAA2B,IAAI;AAJlC,IAAAC,EAAA,gBAAoB,CAAA;AACpB,IAAAC,EAAA,MAAAL,uBAAa,IAAA;AACb,IAAAK,EAAA,MAAAJ;AAGP,eAAWF,KAASI,EAAM,MAAK,KAAKJ,CAAK;AACzC,IAAAO,EAAA,MAAKL,GAAU,KAAK,OAAO;AAAA,EAC7B;AAAA,EAEA,KAAKF,GAAwB;AAC3B,UAAMQ,IAAMR,KAAU,OAA8B,OAAO,OAAOA,CAAK;AACvE,QAAIS,IAAOC,EAAA,MAAKT,GAAO,IAAIO,CAAG;AAC9B,WAAIC,MAAS,WACXA,IAAO,KAAK,OAAO,QACnB,KAAK,OAAO,KAAK,OAAOT,KAAU,WAAW,OAAOA,CAAK,IAAKA,KAAS,IAAK,GAC5EU,EAAA,MAAKT,GAAO,IAAIO,GAAKC,CAAI,IAEpBA;AAAA,EACT;AAAA;AAAA,EAGA,QAAqB;AACnB,UAAME,IAAQ,IAAI,YAAY,KAAK,OAAO,MAAM;AAChD,aAASF,IAAO,GAAGA,IAAOC,EAAA,MAAKR,IAASO,IAAQ,CAAAE,EAAMF,CAAI,IAAIA;AAC9D,UAAMG,IAAO,KAAK,OAAO,MAAMF,EAAA,MAAKR,EAAO,EAAE,IAAI,CAACF,GAAO,OAAO,EAAE,OAAAA,GAAO,MAAMU,EAAA,MAAKR,KAAU,IAAI;AAClG,WAAAU,EAAK,KAAK,CAACC,GAAGC,MAAMC,EAAQF,EAAE,OAAOC,EAAE,KAAK,CAAC,GAC7CF,EAAK,QAAQ,CAAC,EAAE,MAAAH,EAAA,GAAQ,MAAM;AAC5B,MAAAE,EAAMF,CAAI,IAAIC,EAAA,MAAKR,KAAU;AAAA,IAC/B,CAAC,GACMS;AAAA,EACT;AACF;AA9BWV,IAAA,eACAC,IAAA;AA+BX,SAASa,EAAQF,GAAYC,GAAoB;AAC/C,SAAI,OAAOD,KAAM,YAAY,OAAOC,KAAM,WAAiBD,IAAIC,IAC3D,OAAOD,KAAM,WAAiB,KAC9B,OAAOC,KAAM,WAAiB,IAC3B,OAAOD,KAAK,EAAE,EAAE,cAAc,OAAOC,KAAK,EAAE,CAAC;AACtD;"}
1
+ {"version":3,"file":"categories.js","sources":["../../src/core/categories.ts"],"sourcesContent":["import type { Binding } from \"./channels\";\nimport type { VertexTable } from \"./source\";\n\n/**\n * **The categorical domain, fixed before the graph loads.** Colour by vertex type ranks the drawn\n * tables in the manifest's order; a column ranks by the keys of the host's `categories`. Only a value\n * neither names is ranked as it is seen, after them.\n */\nexport function domainOf(\n tables: readonly VertexTable[],\n binding: Binding,\n categories: Readonly<Record<string, string>> | undefined,\n): readonly unknown[] {\n if (binding.byTable) return tables.map((table) => table.name);\n if (binding.category === undefined) return [];\n return categories ? Object.keys(categories) : [];\n}\n\n/** What a legend, a card or an inspector calls a category value. */\nexport const nameOf = (value: unknown, categories: Readonly<Record<string, string>> | undefined): string =>\n categories?.[String(value)] ?? String(value ?? \"—\");\n\n/**\n * Values to codes, in the order first seen. **The seed ranks first, in its own order**, so a colour\n * is decided before a row arrives; a value outside it is ranked after the seed, numbers before\n * strings. Values meet by their text, so a column's `0` is the host's key `\"0\"`.\n */\nexport class Dictionary {\n readonly values: unknown[] = [];\n readonly #codes = new Map<string | null, number>();\n readonly #seeded: number;\n\n constructor(seed: readonly unknown[] = []) {\n for (const value of seed) this.code(value);\n this.#seeded = this.values.length;\n }\n\n code(value: unknown): number {\n const key = value === null || value === undefined ? null : String(value);\n let code = this.#codes.get(key);\n if (code === undefined) {\n code = this.values.length;\n this.values.push(typeof value === \"bigint\" ? Number(value) : (value ?? null));\n this.#codes.set(key, code);\n }\n return code;\n }\n\n /** Each code's rank: the seed's own order, then every other value seen. */\n ranks(): Uint32Array {\n const ranks = new Uint32Array(this.values.length);\n for (let code = 0; code < this.#seeded; code++) ranks[code] = code;\n const rest = this.values.slice(this.#seeded).map((value, i) => ({ value, code: this.#seeded + i }));\n rest.sort((a, b) => compare(a.value, b.value));\n rest.forEach(({ code }, i) => {\n ranks[code] = this.#seeded + i;\n });\n return ranks;\n }\n}\n\nfunction compare(a: unknown, b: unknown): number {\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n if (typeof a === \"number\") return -1;\n if (typeof b === \"number\") return 1;\n return String(a ?? \"\").localeCompare(String(b ?? \"\"));\n}\n"],"names":["domainOf","tables","binding","categories","table","nameOf","value","_codes","_seeded","Dictionary","seed","__publicField","__privateAdd","__privateSet","key","code","__privateGet","ranks","rest","a","b","compare"],"mappings":";;;;;;;AAQO,SAASA,EACdC,GACAC,GACAC,GACoB;AACpB,SAAID,EAAQ,UAAgBD,EAAO,IAAI,CAACG,MAAUA,EAAM,IAAI,IACxDF,EAAQ,aAAa,SAAkB,CAAA,IACpCC,IAAa,OAAO,KAAKA,CAAU,IAAI,CAAA;AAChD;AAGO,MAAME,IAAS,CAACC,GAAgBH,OACrCA,KAAA,gBAAAA,EAAa,OAAOG,CAAK,OAAM,OAAOA,KAAS,GAAG;AAZ7C,IAAAC,GAAAC;AAmBA,MAAMC,EAAW;AAAA,EAKtB,YAAYC,IAA2B,IAAI;AAJlC,IAAAC,EAAA,gBAAoB,CAAA;AACpB,IAAAC,EAAA,MAAAL,uBAAa,IAAA;AACb,IAAAK,EAAA,MAAAJ;AAGP,eAAWF,KAASI,EAAM,MAAK,KAAKJ,CAAK;AACzC,IAAAO,EAAA,MAAKL,GAAU,KAAK,OAAO;AAAA,EAC7B;AAAA,EAEA,KAAKF,GAAwB;AAC3B,UAAMQ,IAAMR,KAAU,OAA8B,OAAO,OAAOA,CAAK;AACvE,QAAIS,IAAOC,EAAA,MAAKT,GAAO,IAAIO,CAAG;AAC9B,WAAIC,MAAS,WACXA,IAAO,KAAK,OAAO,QACnB,KAAK,OAAO,KAAK,OAAOT,KAAU,WAAW,OAAOA,CAAK,IAAKA,KAAS,IAAK,GAC5EU,EAAA,MAAKT,GAAO,IAAIO,GAAKC,CAAI,IAEpBA;AAAA,EACT;AAAA;AAAA,EAGA,QAAqB;AACnB,UAAME,IAAQ,IAAI,YAAY,KAAK,OAAO,MAAM;AAChD,aAASF,IAAO,GAAGA,IAAOC,EAAA,MAAKR,IAASO,IAAQ,CAAAE,EAAMF,CAAI,IAAIA;AAC9D,UAAMG,IAAO,KAAK,OAAO,MAAMF,EAAA,MAAKR,EAAO,EAAE,IAAI,CAACF,GAAO,OAAO,EAAE,OAAAA,GAAO,MAAMU,EAAA,MAAKR,KAAU,IAAI;AAClG,WAAAU,EAAK,KAAK,CAACC,GAAGC,MAAMC,EAAQF,EAAE,OAAOC,EAAE,KAAK,CAAC,GAC7CF,EAAK,QAAQ,CAAC,EAAE,MAAAH,EAAA,GAAQ,MAAM;AAC5B,MAAAE,EAAMF,CAAI,IAAIC,EAAA,MAAKR,KAAU;AAAA,IAC/B,CAAC,GACMS;AAAA,EACT;AACF;AA9BWV,IAAA,eACAC,IAAA;AA+BX,SAASa,EAAQF,GAAYC,GAAoB;AAC/C,SAAI,OAAOD,KAAM,YAAY,OAAOC,KAAM,WAAiBD,IAAIC,IAC3D,OAAOD,KAAM,WAAiB,KAC9B,OAAOC,KAAM,WAAiB,IAC3B,OAAOD,KAAK,EAAE,EAAE,cAAc,OAAOC,KAAK,EAAE,CAAC;AACtD;"}
@@ -13,10 +13,18 @@ export interface Channels {
13
13
  symbol?: string;
14
14
  /** What tints a link. Absent, a link takes the colour of the vertex it leaves. */
15
15
  stroke?: string;
16
+ /**
17
+ * Two numeric columns a point is drawn at — `lon` and `lat` draw a map. Both bound, the data
18
+ * places the points and nothing simulates; unbound, the layout does, on the GPU.
19
+ */
20
+ x?: string;
21
+ y?: string;
22
+ /** Which column a running layout pulls points together by — cosmos.gl's cluster force. */
23
+ cluster?: string;
16
24
  }
17
25
  /** Narrow on purpose — `var(…)`, a hex, a colour function — so a bare word is always a column. */
18
26
  export declare function isColour(value: string | undefined): value is string;
19
- /** The columns a binding reads, which is what a scan projects. */
27
+ /** The columns a binding reads. */
20
28
  export interface Binding {
21
29
  /** The one categorical column: `fill` when it names one, `symbol` when `fill` is a constant or absent. */
22
30
  readonly category: string | undefined;
@@ -26,14 +34,12 @@ export interface Binding {
26
34
  readonly size: string | undefined;
27
35
  /** The text a label and the hover card show — Plot's `title`. */
28
36
  readonly title: string | undefined;
37
+ readonly x: string | undefined;
38
+ readonly y: string | undefined;
39
+ readonly cluster: string | undefined;
29
40
  }
30
41
  export declare function bindingOf(options: Channels & {
31
42
  r?: string;
32
43
  title?: string;
33
44
  }): Binding;
34
- /**
35
- * A binding is a projection: `fill` and `r` as columns become the scan's `select`, where the table
36
- * has them. `title` is not: a label's text is read for the few vertices that carry one.
37
- */
38
- export declare function projectionOf(binding: Binding, fixed: readonly string[], has: (column: string) => boolean): string[];
39
45
  //# sourceMappingURL=channels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/core/channels.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,0GAA0G;IAC1G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAEnE;AAED,kEAAkE;AAClE,MAAM,WAAW,OAAO;IACtB,0GAA0G;IAC1G,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,QAAQ,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAIrF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,EAAE,CAGnH"}
1
+ {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/core/channels.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,0GAA0G;IAC1G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAEnE;AAED,mCAAmC;AACnC,MAAM,WAAW,OAAO;IACtB,0GAA0G;IAC1G,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,QAAQ,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAYrF"}
@@ -1,17 +1,20 @@
1
- function c(t) {
2
- return t !== void 0 && /^(var\(|#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(t);
1
+ function e(l) {
2
+ return l !== void 0 && /^(var\(|#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(l);
3
3
  }
4
- function n(t) {
5
- const l = c(t.fill), r = l ? t.symbol : t.fill ?? t.symbol;
6
- return { category: r, byTable: !l && r === void 0, size: t.r, title: t.title };
7
- }
8
- function i(t, l, r) {
9
- const o = [t.category, t.size].filter((e) => e !== void 0 && r(e));
10
- return [.../* @__PURE__ */ new Set([...l, ...o])];
4
+ function t(l) {
5
+ const r = e(l.fill), c = r ? l.symbol : l.fill ?? l.symbol;
6
+ return {
7
+ category: c,
8
+ byTable: !r && c === void 0,
9
+ size: l.r,
10
+ title: l.title,
11
+ x: l.x,
12
+ y: l.y,
13
+ cluster: l.cluster
14
+ };
11
15
  }
12
16
  export {
13
- n as bindingOf,
14
- c as isColour,
15
- i as projectionOf
17
+ t as bindingOf,
18
+ e as isColour
16
19
  };
17
20
  //# sourceMappingURL=channels.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"channels.js","sources":["../../src/core/channels.ts"],"sourcesContent":["/**\n * What each channel is bound to — Plot's names, and Plot's rule that **a CSS colour is a constant\n * and anything else is a column.** `fill=\"kind\"` spends colour on a category; `fill=\"var(--foreground)\"`\n * paints every point one ink and leaves colour free to mean the selection.\n */\nexport interface Channels {\n /** Which column colours a point, or a CSS colour every point wears. Absent, colour is the vertex type. */\n fill?: string;\n /**\n * Which column a point's shape carries. The graph holds one categorical column, so bound beside a\n * `fill` column this reads the same one; a second would need a second array everywhere.\n */\n symbol?: string;\n /** What tints a link. Absent, a link takes the colour of the vertex it leaves. */\n stroke?: string;\n}\n\n/** Narrow on purpose — `var(…)`, a hex, a colour function — so a bare word is always a column. */\nexport function isColour(value: string | undefined): value is string {\n return value !== undefined && /^(var\\(|#|rgb|hsl|oklch|oklab|lab|lch|color\\()/i.test(value);\n}\n\n/** The columns a binding reads, which is what a scan projects. */\nexport interface Binding {\n /** The one categorical column: `fill` when it names one, `symbol` when `fill` is a constant or absent. */\n readonly category: string | undefined;\n /** No column and no constant: the category is the vertex type. */\n readonly byTable: boolean;\n /** What the size ramp is spent on — Plot's `r`. */\n readonly size: string | undefined;\n /** The text a label and the hover card show — Plot's `title`. */\n readonly title: string | undefined;\n}\n\nexport function bindingOf(options: Channels & { r?: string; title?: string }): Binding {\n const constant = isColour(options.fill);\n const category = constant ? options.symbol : (options.fill ?? options.symbol);\n return { category, byTable: !constant && category === undefined, size: options.r, title: options.title };\n}\n\n/**\n * A binding is a projection: `fill` and `r` as columns become the scan's `select`, where the table\n * has them. `title` is not: a label's text is read for the few vertices that carry one.\n */\nexport function projectionOf(binding: Binding, fixed: readonly string[], has: (column: string) => boolean): string[] {\n const bound = [binding.category, binding.size].filter((c): c is string => c !== undefined && has(c));\n return [...new Set([...fixed, ...bound])];\n}\n"],"names":["isColour","value","bindingOf","options","constant","category","projectionOf","binding","fixed","has","bound","c"],"mappings":"AAkBO,SAASA,EAASC,GAA4C;AACnE,SAAOA,MAAU,UAAa,kDAAkD,KAAKA,CAAK;AAC5F;AAcO,SAASC,EAAUC,GAA6D;AACrF,QAAMC,IAAWJ,EAASG,EAAQ,IAAI,GAChCE,IAAWD,IAAWD,EAAQ,SAAUA,EAAQ,QAAQA,EAAQ;AACtE,SAAO,EAAE,UAAAE,GAAU,SAAS,CAACD,KAAYC,MAAa,QAAW,MAAMF,EAAQ,GAAG,OAAOA,EAAQ,MAAA;AACnG;AAMO,SAASG,EAAaC,GAAkBC,GAA0BC,GAA4C;AACnH,QAAMC,IAAQ,CAACH,EAAQ,UAAUA,EAAQ,IAAI,EAAE,OAAO,CAACI,MAAmBA,MAAM,UAAaF,EAAIE,CAAC,CAAC;AACnG,SAAO,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAGH,GAAO,GAAGE,CAAK,CAAC,CAAC;AAC1C;"}
1
+ {"version":3,"file":"channels.js","sources":["../../src/core/channels.ts"],"sourcesContent":["/**\n * What each channel is bound to — Plot's names, and Plot's rule that **a CSS colour is a constant\n * and anything else is a column.** `fill=\"kind\"` spends colour on a category; `fill=\"var(--foreground)\"`\n * paints every point one ink and leaves colour free to mean the selection.\n */\nexport interface Channels {\n /** Which column colours a point, or a CSS colour every point wears. Absent, colour is the vertex type. */\n fill?: string;\n /**\n * Which column a point's shape carries. The graph holds one categorical column, so bound beside a\n * `fill` column this reads the same one; a second would need a second array everywhere.\n */\n symbol?: string;\n /** What tints a link. Absent, a link takes the colour of the vertex it leaves. */\n stroke?: string;\n /**\n * Two numeric columns a point is drawn at — `lon` and `lat` draw a map. Both bound, the data\n * places the points and nothing simulates; unbound, the layout does, on the GPU.\n */\n x?: string;\n y?: string;\n /** Which column a running layout pulls points together by — cosmos.gl's cluster force. */\n cluster?: string;\n}\n\n/** Narrow on purpose — `var(…)`, a hex, a colour function — so a bare word is always a column. */\nexport function isColour(value: string | undefined): value is string {\n return value !== undefined && /^(var\\(|#|rgb|hsl|oklch|oklab|lab|lch|color\\()/i.test(value);\n}\n\n/** The columns a binding reads. */\nexport interface Binding {\n /** The one categorical column: `fill` when it names one, `symbol` when `fill` is a constant or absent. */\n readonly category: string | undefined;\n /** No column and no constant: the category is the vertex type. */\n readonly byTable: boolean;\n /** What the size ramp is spent on — Plot's `r`. */\n readonly size: string | undefined;\n /** The text a label and the hover card show — Plot's `title`. */\n readonly title: string | undefined;\n readonly x: string | undefined;\n readonly y: string | undefined;\n readonly cluster: string | undefined;\n}\n\nexport function bindingOf(options: Channels & { r?: string; title?: string }): Binding {\n const constant = isColour(options.fill);\n const category = constant ? options.symbol : (options.fill ?? options.symbol);\n return {\n category,\n byTable: !constant && category === undefined,\n size: options.r,\n title: options.title,\n x: options.x,\n y: options.y,\n cluster: options.cluster,\n };\n}\n"],"names":["isColour","value","bindingOf","options","constant","category"],"mappings":"AA0BO,SAASA,EAASC,GAA4C;AACnE,SAAOA,MAAU,UAAa,kDAAkD,KAAKA,CAAK;AAC5F;AAiBO,SAASC,EAAUC,GAA6D;AACrF,QAAMC,IAAWJ,EAASG,EAAQ,IAAI,GAChCE,IAAWD,IAAWD,EAAQ,SAAUA,EAAQ,QAAQA,EAAQ;AACtE,SAAO;AAAA,IACL,UAAAE;AAAA,IACA,SAAS,CAACD,KAAYC,MAAa;AAAA,IACnC,MAAMF,EAAQ;AAAA,IACd,OAAOA,EAAQ;AAAA,IACf,GAAGA,EAAQ;AAAA,IACX,GAAGA,EAAQ;AAAA,IACX,SAASA,EAAQ;AAAA,EAAA;AAErB;"}
@@ -0,0 +1,26 @@
1
+ import { MosaicClient, FilterExpr, Selection } from '@kanzo-tech/mosaic';
2
+ import { Structure } from './source';
3
+ export declare class GraphClient extends MosaicClient {
4
+ #private;
5
+ constructor(filterBy: Selection | undefined, structure: () => Structure | null, kept: (ids: Float64Array | null) => void, fail: (error: unknown) => void);
6
+ /**
7
+ * Not stable: the answer is a set of ids, not a group-by a pre-aggregate could stand in for. And
8
+ * Mosaic's pre-aggregator calls `query()` with no filter to analyse a client — false keeps it away.
9
+ */
10
+ get filterStable(): boolean;
11
+ /**
12
+ * The surviving ids — or, with nothing to filter by, {@link UNFILTERED}: one row whose id is
13
+ * `NULL`, which no `dense_id` is. The answer says which it is, so two statements in flight can
14
+ * never be read as each other's.
15
+ */
16
+ query(filter?: FilterExpr | null): string;
17
+ queryResult(data: unknown): this;
18
+ queryError(error: Error): this;
19
+ }
20
+ /**
21
+ * **The reader's pick, published** — from the graph, so the crossfilter applies it to every chart and
22
+ * skips it for the graph. A canvas that greyed out everything but a lasso of thirteen would hide the
23
+ * neighbourhood the reader was looking at.
24
+ */
25
+ export declare function publish(selection: Selection, self: MosaicClient, ids: readonly number[] | null): void;
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAgC,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEjH,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAYxE,qBAAa,WAAY,SAAQ,YAAY;;gBAMzC,QAAQ,EAAE,SAAS,GAAG,SAAS,EAC/B,SAAS,EAAE,MAAM,SAAS,GAAG,IAAI,EACjC,IAAI,EAAE,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,EACxC,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI;IAQhC;;;OAGG;IACH,IAAa,YAAY,IAAI,OAAO,CAEnC;IAED;;;;OAIG;IACM,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,MAAM;IAwBzC,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAMhC,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAIxC;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAOrG"}
@@ -0,0 +1,62 @@
1
+ var f = (t) => {
2
+ throw TypeError(t);
3
+ };
4
+ var L = (t, r, e) => r.has(t) || f("Cannot " + e);
5
+ var u = (t, r, e) => (L(t, r, "read from private field"), e ? e.call(t) : r.get(t)), h = (t, r, e) => r.has(t) ? f("Cannot add the same private member more than once") : r instanceof WeakSet ? r.add(t) : r.set(t, e), m = (t, r, e, n) => (L(t, r, "write to private field"), n ? n.call(t, e) : r.set(t, e), e);
6
+ import { MosaicClient as g, collectColumns as A, clausePoints as v } from "@kanzo-tech/mosaic";
7
+ import { GraphError as C } from "./error.js";
8
+ import { relation as $, ident as y } from "./source.js";
9
+ const S = "SELECT NULL::DOUBLE AS id";
10
+ var a, c, l;
11
+ class N extends g {
12
+ constructor(e, n, i, d) {
13
+ super(e);
14
+ h(this, a);
15
+ h(this, c);
16
+ h(this, l);
17
+ m(this, a, n), m(this, c, i), m(this, l, d);
18
+ }
19
+ /**
20
+ * Not stable: the answer is a set of ids, not a group-by a pre-aggregate could stand in for. And
21
+ * Mosaic's pre-aggregator calls `query()` with no filter to analyse a client — false keeps it away.
22
+ */
23
+ get filterStable() {
24
+ return !1;
25
+ }
26
+ /**
27
+ * The surviving ids — or, with nothing to filter by, {@link UNFILTERED}: one row whose id is
28
+ * `NULL`, which no `dense_id` is. The answer says which it is, so two statements in flight can
29
+ * never be read as each other's.
30
+ */
31
+ query(e) {
32
+ const n = (Array.isArray(e) ? e : [e]).filter((s) => s != null), i = u(this, a).call(this);
33
+ if (!i || n.length === 0) return S;
34
+ const d = n.map((s) => `(${String(s)})`).join(" AND "), p = [...new Set(n.flatMap((s) => A(s).map((o) => o.column)))], E = i.vertices.filter((s) => p.every((o) => s.columns.has(o)));
35
+ return E.length === 0 ? (u(this, l).call(this, new C("graph/unfilterable", `no vertex type has every column this clause names: ${p.join(", ")}`)), S) : i.vertices.map((s) => {
36
+ const o = $(i.from, s.name);
37
+ return E.includes(s) ? `SELECT ${y("dense_id")}::DOUBLE AS id FROM ${o} WHERE ${d}` : `SELECT ${y("dense_id")}::DOUBLE AS id FROM ${o}`;
38
+ }).join(" UNION ALL ");
39
+ }
40
+ queryResult(e) {
41
+ var i;
42
+ const n = ((i = e.getChild("id")) == null ? void 0 : i.toArray()) ?? [];
43
+ return u(this, c).call(this, n.length === 1 && n[0] === null ? null : Float64Array.from(n)), this;
44
+ }
45
+ queryError(e) {
46
+ return u(this, l).call(this, e), this;
47
+ }
48
+ }
49
+ a = new WeakMap(), c = new WeakMap(), l = new WeakMap();
50
+ function R(t, r, e) {
51
+ t.update(
52
+ v(["dense_id"], e && e.length > 0 ? e.map((n) => [n]) : void 0, {
53
+ source: r,
54
+ clients: /* @__PURE__ */ new Set([r])
55
+ })
56
+ );
57
+ }
58
+ export {
59
+ N as GraphClient,
60
+ R as publish
61
+ };
62
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sources":["../../src/core/client.ts"],"sourcesContent":["import { MosaicClient, clausePoints, collectColumns, type FilterExpr, type Selection } from \"@kanzo-tech/mosaic\";\nimport { GraphError } from \"./error\";\nimport { ident, relation, type Answer, type Structure } from \"./source\";\n\n/**\n * **The graph as a client of the page's coordinator** — one Mosaic client, like every chart beside\n * it. The coordinator hands it the crossfilter's predicate, minus the clause the graph published\n * itself; it answers with the `dense_id`s that survive, and the canvas greys out the rest on the GPU.\n * No predicate is translated, no position is uploaded again, and the query runs on the coordinator's\n * one connection, through its cache — Cosmograph's crossfilter, on our stack.\n */\n/** The answer that clears the filter. */\nconst UNFILTERED = \"SELECT NULL::DOUBLE AS id\";\n\nexport class GraphClient extends MosaicClient {\n #structure: () => Structure | null;\n #kept: (ids: Float64Array | null) => void;\n #fail: (error: unknown) => void;\n\n constructor(\n filterBy: Selection | undefined,\n structure: () => Structure | null,\n kept: (ids: Float64Array | null) => void,\n fail: (error: unknown) => void,\n ) {\n super(filterBy);\n this.#structure = structure;\n this.#kept = kept;\n this.#fail = fail;\n }\n\n /**\n * Not stable: the answer is a set of ids, not a group-by a pre-aggregate could stand in for. And\n * Mosaic's pre-aggregator calls `query()` with no filter to analyse a client — false keeps it away.\n */\n override get filterStable(): boolean {\n return false;\n }\n\n /**\n * The surviving ids — or, with nothing to filter by, {@link UNFILTERED}: one row whose id is\n * `NULL`, which no `dense_id` is. The answer says which it is, so two statements in flight can\n * never be read as each other's.\n */\n override query(filter?: FilterExpr | null): string {\n const clauses = (Array.isArray(filter) ? filter : [filter]).filter((c) => c !== undefined && c !== null);\n const structure = this.#structure();\n if (!structure || clauses.length === 0) return UNFILTERED;\n const where = clauses.map((c) => `(${String(c)})`).join(\" AND \");\n const named = [...new Set(clauses.flatMap((c) => collectColumns(c as never).map((ref: { column: string }) => ref.column)))];\n // A table that lacks a column the predicate names is not filtered by it — what a `WHERE` over a\n // union of the tables would do. A predicate no table can answer is refused rather than ignored,\n // so the unfiltered picture is never drawn as the filtered one.\n const answering = structure.vertices.filter((t) => named.every((c) => t.columns.has(c)));\n if (answering.length === 0) {\n this.#fail(new GraphError(\"graph/unfilterable\", `no vertex type has every column this clause names: ${named.join(\", \")}`));\n return UNFILTERED;\n }\n return structure.vertices\n .map((t) => {\n const from = relation(structure.from, t.name);\n return answering.includes(t)\n ? `SELECT ${ident(\"dense_id\")}::DOUBLE AS id FROM ${from} WHERE ${where}`\n : `SELECT ${ident(\"dense_id\")}::DOUBLE AS id FROM ${from}`;\n })\n .join(\" UNION ALL \");\n }\n\n override queryResult(data: unknown): this {\n const ids = ((data as Answer).getChild(\"id\")?.toArray() ?? []) as ArrayLike<number | null>;\n this.#kept(ids.length === 1 && ids[0] === null ? null : Float64Array.from(ids as ArrayLike<number>));\n return this;\n }\n\n override queryError(error: Error): this {\n this.#fail(error);\n return this;\n }\n}\n\n/**\n * **The reader's pick, published** — from the graph, so the crossfilter applies it to every chart and\n * skips it for the graph. A canvas that greyed out everything but a lasso of thirteen would hide the\n * neighbourhood the reader was looking at.\n */\nexport function publish(selection: Selection, self: MosaicClient, ids: readonly number[] | null): void {\n selection.update(\n clausePoints([\"dense_id\"], ids && ids.length > 0 ? ids.map((d) => [d]) : undefined, {\n source: self,\n clients: new Set([self]),\n }),\n );\n}\n"],"names":["UNFILTERED","GraphClient","MosaicClient","filterBy","structure","kept","fail","__privateAdd","_structure","_kept","_fail","__privateSet","filter","clauses","c","__privateGet","where","named","collectColumns","ref","answering","t","GraphError","from","relation","ident","data","ids","_a","error","publish","selection","self","clausePoints","d"],"mappings":";;;;;;;;AAYA,MAAMA,IAAa;;AAEZ,MAAMC,UAAoBC,EAAa;AAAA,EAK5C,YACEC,GACAC,GACAC,GACAC,GACA;AACA,UAAMH,CAAQ;AAVhB,IAAAI,EAAA,MAAAC;AACA,IAAAD,EAAA,MAAAE;AACA,IAAAF,EAAA,MAAAG;AASE,IAAAC,EAAA,MAAKH,GAAaJ,IAClBO,EAAA,MAAKF,GAAQJ,IACbM,EAAA,MAAKD,GAAQJ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAa,eAAwB;AACnC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOS,MAAMM,GAAoC;AACjD,UAAMC,KAAW,MAAM,QAAQD,CAAM,IAAIA,IAAS,CAACA,CAAM,GAAG,OAAO,CAACE,MAAyBA,KAAM,IAAI,GACjGV,IAAYW,EAAA,MAAKP,GAAL;AAClB,QAAI,CAACJ,KAAaS,EAAQ,WAAW,EAAG,QAAOb;AAC/C,UAAMgB,IAAQH,EAAQ,IAAI,CAACC,MAAM,IAAI,OAAOA,CAAC,CAAC,GAAG,EAAE,KAAK,OAAO,GACzDG,IAAQ,CAAC,GAAG,IAAI,IAAIJ,EAAQ,QAAQ,CAACC,MAAMI,EAAeJ,CAAU,EAAE,IAAI,CAACK,MAA4BA,EAAI,MAAM,CAAC,CAAC,CAAC,GAIpHC,IAAYhB,EAAU,SAAS,OAAO,CAACiB,MAAMJ,EAAM,MAAM,CAACH,MAAMO,EAAE,QAAQ,IAAIP,CAAC,CAAC,CAAC;AACvF,WAAIM,EAAU,WAAW,KACvBL,EAAA,MAAKL,GAAL,WAAW,IAAIY,EAAW,sBAAsB,sDAAsDL,EAAM,KAAK,IAAI,CAAC,EAAE,IACjHjB,KAEFI,EAAU,SACd,IAAI,CAACiB,MAAM;AACV,YAAME,IAAOC,EAASpB,EAAU,MAAMiB,EAAE,IAAI;AAC5C,aAAOD,EAAU,SAASC,CAAC,IACvB,UAAUI,EAAM,UAAU,CAAC,uBAAuBF,CAAI,UAAUP,CAAK,KACrE,UAAUS,EAAM,UAAU,CAAC,uBAAuBF,CAAI;AAAA,IAC5D,CAAC,EACA,KAAK,aAAa;AAAA,EACvB;AAAA,EAES,YAAYG,GAAqB;;AACxC,UAAMC,MAAQC,IAAAF,EAAgB,SAAS,IAAI,MAA7B,gBAAAE,EAAgC,cAAa,CAAA;AAC3D,WAAAb,EAAA,MAAKN,GAAL,WAAWkB,EAAI,WAAW,KAAKA,EAAI,CAAC,MAAM,OAAO,OAAO,aAAa,KAAKA,CAAwB,IAC3F;AAAA,EACT;AAAA,EAES,WAAWE,GAAoB;AACtC,WAAAd,EAAA,MAAKL,GAAL,WAAWmB,IACJ;AAAA,EACT;AACF;AA/DErB,IAAA,eACAC,IAAA,eACAC,IAAA;AAoEK,SAASoB,EAAQC,GAAsBC,GAAoBL,GAAqC;AACrG,EAAAI,EAAU;AAAA,IACRE,EAAa,CAAC,UAAU,GAAGN,KAAOA,EAAI,SAAS,IAAIA,EAAI,IAAI,CAACO,MAAM,CAACA,CAAC,CAAC,IAAI,QAAW;AAAA,MAClF,QAAQF;AAAA,MACR,SAAS,oBAAI,IAAI,CAACA,CAAI,CAAC;AAAA,IAAA,CACxB;AAAA,EAAA;AAEL;"}
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * The failures the graph names itself: no GPU device to draw with, or the one it had was taken back;
3
- * a corpus with no positioned vertex type to draw; a crossfilter clause it cannot ask the corpus. A
3
+ * a corpus with no vertex to draw; a crossfilter clause no vertex type can answer. A
4
4
  * corpus fossil will not read never gets here: `open` refuses it, coded. `data.after` is set when a deadline fired. Everything else reaches `onFailure` as thrown.
5
5
  */
6
6
  export declare class GraphError extends Error {
7
- readonly code: "graph/no-webgl" | "graph/context-lost" | "graph/nothing-to-draw" | "graph/untranslatable-filter";
7
+ readonly code: "graph/no-webgl" | "graph/context-lost" | "graph/nothing-to-draw" | "graph/unfilterable";
8
8
  readonly data: {
9
9
  readonly after?: number;
10
10
  };
11
11
  readonly name = "GraphError";
12
- constructor(code: "graph/no-webgl" | "graph/context-lost" | "graph/nothing-to-draw" | "graph/untranslatable-filter", message: string, data?: {
12
+ constructor(code: "graph/no-webgl" | "graph/context-lost" | "graph/nothing-to-draw" | "graph/unfilterable", message: string, data?: {
13
13
  readonly after?: number;
14
14
  }, options?: ErrorOptions);
15
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/core/error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAGjC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,6BAA6B;IAEhH,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAJ5C,SAAkB,IAAI,gBAAgB;gBAE3B,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,6BAA6B,EAChH,OAAO,EAAE,MAAM,EACN,IAAI,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,EAC/C,OAAO,CAAC,EAAE,YAAY;CAIzB"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/core/error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;IAGjC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,oBAAoB;IAEvG,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAJ5C,SAAkB,IAAI,gBAAgB;gBAE3B,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,oBAAoB,EACvG,OAAO,EAAE,MAAM,EACN,IAAI,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,EAC/C,OAAO,CAAC,EAAE,YAAY;CAIzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"error.js","sources":["../../src/core/error.ts"],"sourcesContent":["/**\n * The failures the graph names itself: no GPU device to draw with, or the one it had was taken back;\n * a corpus with no positioned vertex type to draw; a crossfilter clause it cannot ask the corpus. A\n * corpus fossil will not read never gets here: `open` refuses it, coded. `data.after` is set when a deadline fired. Everything else reaches `onFailure` as thrown.\n */\nexport class GraphError extends Error {\n override readonly name = \"GraphError\";\n constructor(\n readonly code: \"graph/no-webgl\" | \"graph/context-lost\" | \"graph/nothing-to-draw\" | \"graph/untranslatable-filter\",\n message: string,\n readonly data: { readonly after?: number } = {},\n options?: ErrorOptions,\n ) {\n super(message, options);\n }\n}\n"],"names":["GraphError","code","message","data","options","__publicField"],"mappings":";;;AAKO,MAAMA,UAAmB,MAAM;AAAA,EAEpC,YACWC,GACTC,GACSC,IAAoC,CAAA,GAC7CC,GACA;AACA,UAAMF,GAASE,CAAO;AAPN,IAAAC,EAAA,cAAO;AAEd,SAAA,OAAAJ,GAEA,KAAA,OAAAE;AAAA,EAIX;AACF;"}
1
+ {"version":3,"file":"error.js","sources":["../../src/core/error.ts"],"sourcesContent":["/**\n * The failures the graph names itself: no GPU device to draw with, or the one it had was taken back;\n * a corpus with no vertex to draw; a crossfilter clause no vertex type can answer. A\n * corpus fossil will not read never gets here: `open` refuses it, coded. `data.after` is set when a deadline fired. Everything else reaches `onFailure` as thrown.\n */\nexport class GraphError extends Error {\n override readonly name = \"GraphError\";\n constructor(\n readonly code: \"graph/no-webgl\" | \"graph/context-lost\" | \"graph/nothing-to-draw\" | \"graph/unfilterable\",\n message: string,\n readonly data: { readonly after?: number } = {},\n options?: ErrorOptions,\n ) {\n super(message, options);\n }\n}\n"],"names":["GraphError","code","message","data","options","__publicField"],"mappings":";;;AAKO,MAAMA,UAAmB,MAAM;AAAA,EAEpC,YACWC,GACTC,GACSC,IAAoC,CAAA,GAC7CC,GACA;AACA,UAAMF,GAASE,CAAO;AAPN,IAAAC,EAAA,cAAO;AAEd,SAAA,OAAAJ,GAEA,KAAA,OAAAE;AAAA,EAIX;AACF;"}
@@ -1,63 +1,54 @@
1
+ import { Coordinator } from '@kanzo-tech/mosaic';
1
2
  import { Binding } from './channels';
2
- import { Corpus, Filter, VertexTable } from '@fossil-lang/corpus';
3
+ import { Structure } from './source';
3
4
  /**
4
- * **The whole graph, read once and laid out as cosmos.gl's buffers.** A drawn vertex's `dense_id` is
5
- * its index, so every array is sized from the manifest's `record_count`s before a row arrives, and a
6
- * row is written where its id says. The camera never reaches here: nothing is read because it moved.
5
+ * **The whole graph, read once and laid out as cosmos.gl's buffers.** A vertex's `dense_id` is its
6
+ * index, and a vertex table is one contiguous range of them, so each table's answer is written into
7
+ * its own slice and nothing is resolved row by row.
7
8
  */
8
- /** Where the drawn vertices are and how they connect — read once per corpus. */
9
+ /** Where the vertices start and how they connect — read once per corpus and per position binding. */
9
10
  export interface Geometry {
10
- /** The vertex tables with a position, in the manifest's order. */
11
- readonly tables: readonly VertexTable[];
12
- /** Drawn vertices: ids `0 … size − 1`. */
11
+ readonly structure: Structure;
12
+ /** Every vertex: ids `0 … size − 1`. */
13
13
  readonly size: number;
14
- /** `[x, y, …]` by id; `NaN` where no row has a position. */
14
+ /**
15
+ * `[x, y, …]` by id. With `x` and `y` bound, the columns' values — `NaN` where a table lacks them,
16
+ * which cosmos.gl does not draw. Unbound, a seeded start for the layout, inside `space`.
17
+ */
15
18
  readonly positions: Float32Array;
16
- /** By id, the vertex's index in `tables`. */
17
- readonly table: Uint16Array;
18
- /** `[src, dst, …]` by id, every relation whose two ends are drawn. */
19
+ /** Whether the positions are the data's (`x`/`y` bound) or a start for the layout to move. */
20
+ readonly bound: boolean;
21
+ /** `[src, dst, …]` by id, every relation. */
19
22
  readonly links: Float32Array;
23
+ /** Bound positions' extent; `null` for a layout's start, whose square is `space`. */
20
24
  readonly extent: {
21
25
  readonly x: number;
22
26
  readonly y: number;
23
27
  readonly w: number;
24
28
  readonly h: number;
25
29
  } | null;
30
+ /** The side of the square the layout runs in. */
31
+ readonly space: number;
26
32
  }
27
33
  /** What the bound channels say about each vertex — read again when a binding changes. */
28
34
  export interface Encoding {
29
35
  /** By id, the category's rank. */
30
36
  readonly ranks: Uint32Array;
31
- /** By id, the ramp's raw value, or `null` when `r` is unbound. */
32
- readonly sizes: Float32Array | null;
37
+ /** By id, the size ramp's raw value: the bound `r` column, or the vertex's degree. */
38
+ readonly sizes: Float32Array;
39
+ /** By id, the cluster a layout pulls the vertex toward, or `null` when `cluster` is unbound. */
40
+ readonly clusters: (number | undefined)[] | null;
33
41
  /** What each rank is: the seed, then the other values seen, in rank order. */
34
42
  readonly domain: readonly unknown[];
35
43
  }
36
- /** The vertex tables fossil lays out or the program places; a table without a position is not drawn. */
37
- export declare const drawnTables: (corpus: Corpus) => VertexTable[];
38
44
  /**
39
- * Reads in parallel that end together: the first to fail aborts the rest, so no read outlives the
40
- * answer and no second failure goes unheard behind the first.
45
+ * The layout's square: cosmos.gl's own 4,096 up to 200,000 vertices, and twice that past them —
46
+ * measured on the gate in `/docs/graph/layout`: at 500,000 the default square presses the layout
47
+ * against its border and the communities mix.
41
48
  */
42
- export declare function together<T>(signal: AbortSignal, reads: (signal: AbortSignal) => Promise<T>): Promise<T>;
43
- /** One scan per drawn table and one per relation between them, read whole, in parallel. */
44
- export declare function loadGraph(corpus: Corpus, binding: Binding, seed: readonly unknown[], signal: AbortSignal): Promise<{
45
- geometry: Geometry;
46
- encoding: Encoding;
47
- }>;
48
- /** A new binding re-reads the channels and nothing else: the positions and the links stay uploaded. */
49
- export declare function loadEncoding(corpus: Corpus, geometry: Geometry, binding: Binding, seed: readonly unknown[], signal: AbortSignal): Promise<Encoding>;
50
- /** What a filter kept: per table that holds every column it names, the surviving ids. */
51
- export interface Kept {
52
- readonly filtered: ReadonlySet<number>;
53
- readonly ids: readonly number[];
54
- }
55
- /**
56
- * **A predicate, applied as a mask.** A table that lacks a column the filter names is not filtered,
57
- * which is what a `WHERE` over a union of the tables would do; a filter no drawn table can answer at
58
- * all is refused, so the unfiltered picture is never drawn as the filtered one.
59
- */
60
- export declare function readKept(corpus: Corpus, tables: readonly VertexTable[], filter: Filter, signal: AbortSignal): Promise<Kept>;
61
- /** `1` where a vertex survives the page's filter. */
62
- export declare function maskOf(geometry: Geometry, kept: Kept): Uint8Array;
49
+ export declare const spaceFor: (size: number) => number;
50
+ /** The links, and the positions: two bound columns, or a seeded start for the layout. */
51
+ export declare function loadGeometry(coordinator: Coordinator, structure: Structure, binding: Binding): Promise<Geometry>;
52
+ /** The bound channels — category, size and cluster — over every vertex. */
53
+ export declare function loadEncoding(coordinator: Coordinator, geometry: Geometry, binding: Binding, seed: readonly unknown[]): Promise<Encoding>;
63
54
  //# sourceMappingURL=load.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/core/load.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAS,MAAM,EAAa,MAAM,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGzF;;;;GAIG;AAEH,gFAAgF;AAChF,MAAM,WAAW,QAAQ;IACvB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IACxC,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC5G;AAED,yFAAyF;AACzF,MAAM,WAAW,QAAQ;IACvB,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED,wGAAwG;AACxG,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,KAAG,WAAW,EAAqE,CAAC;AAI9H;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMvG;AA8ED,2FAA2F;AAC3F,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAkCrD;AAED,uGAAuG;AACvG,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,OAAO,EAAE,EACxB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,QAAQ,CAAC,CAUnB;AAED,yFAAyF;AACzF,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBjI;AAED,qDAAqD;AACrD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,UAAU,CAKjE"}
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/core/load.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAElE;;;;GAIG;AAEH,qGAAqG;AACrG,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3G,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,yFAAyF;AACzF,MAAM,WAAW,QAAQ;IACvB,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;IACjD,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,KAAG,MAAwC,CAAC;AA8CjF,yFAAyF;AACzF,wBAAsB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoBtH;AAYD,2EAA2E;AAC3E,wBAAsB,YAAY,CAChC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,OAAO,EAAE,GACvB,OAAO,CAAC,QAAQ,CAAC,CAgCnB"}
package/dist/core/load.js CHANGED
@@ -1,130 +1,76 @@
1
- import { GraphError as I } from "./error.js";
2
- import { Dictionary as O } from "./categories.js";
3
- import { projectionOf as g } from "./channels.js";
4
- import { columnsOf as R } from "./filter.js";
5
- const _ = (o) => o.manifest.vertex_tables.filter((t) => t.position), v = (o) => (t) => o.properties.some((e) => e.name === t);
6
- function C(o, t) {
7
- const e = new AbortController();
8
- return t(AbortSignal.any([o, e.signal])).catch((r) => {
9
- throw e.abort(), r;
10
- });
11
- }
12
- async function x(o, t, e) {
13
- const r = o.scan(t);
14
- return r.read(r.plan(), { signal: e });
15
- }
16
- function E(o, t, e, r) {
17
- const c = new O(r), s = new Uint32Array(t), l = e.size === void 0 ? null : new Float32Array(t).fill(Number.NaN);
18
- return {
19
- add(a, i) {
20
- var d, N, b;
21
- const n = o[a], m = ((d = i.getChild(n.key)) == null ? void 0 : d.toArray()) ?? [], f = e.category === void 0 || (N = i.getChild(e.category)) == null ? void 0 : N.toArray(), u = e.size === void 0 || (b = i.getChild(e.size)) == null ? void 0 : b.toArray(), w = e.byTable ? c.code(n.name) : 0;
22
- for (let y = 0; y < i.numRows; y++) {
23
- const h = Number(m[y]);
24
- h < t && (s[h] = e.byTable || e.category === void 0 ? w : c.code((f == null ? void 0 : f[y]) ?? null), l && (l[h] = Number((u == null ? void 0 : u[y]) ?? Number.NaN)));
25
- }
26
- },
27
- finish() {
28
- const a = c.ranks(), i = s.map((m) => a[m] ?? 0), n = [];
29
- return a.forEach((m, f) => {
30
- n[m] = c.values[f];
31
- }), { ranks: i, sizes: l, domain: n };
32
- }
1
+ import { Dictionary as k } from "./categories.js";
2
+ import { readLinks as P, readColumns as z } from "./source.js";
3
+ const q = (e) => e > 2e5 ? 8192 : 4096;
4
+ function E(e) {
5
+ let o = e >>> 0;
6
+ return () => {
7
+ o = o + 1831565813 >>> 0;
8
+ let t = o;
9
+ return t = Math.imul(t ^ t >>> 15, t | 1), t ^= t + Math.imul(t ^ t >>> 7, t | 61), ((t ^ t >>> 14) >>> 0) / 4294967296;
33
10
  };
34
11
  }
35
- function F(o) {
36
- let [t, e, r, c] = [1 / 0, 1 / 0, -1 / 0, -1 / 0];
37
- for (let s = 0; s < o.length; s += 2) {
38
- const l = o[s], a = o[s + 1];
39
- Number.isNaN(l) || Number.isNaN(a) || (l < t && (t = l), l > r && (r = l), a < e && (e = a), a > c && (c = a));
12
+ function R(e, o) {
13
+ const t = E(e), s = o / 8 * Math.sqrt(Math.min(1, e / 15e5)), n = new Float32Array(2 * e);
14
+ for (let r = 0; r < e; r++) {
15
+ const l = Math.sqrt(-2 * Math.log(1 - t())) * s, a = 2 * Math.PI * t();
16
+ n[2 * r] = o / 2 + l * Math.cos(a), n[2 * r + 1] = o / 2 + l * Math.sin(a);
40
17
  }
41
- return t > r ? null : { x: t, y: e, w: r - t, h: c - e };
18
+ return n;
42
19
  }
43
- async function S(o, t, e, r) {
44
- const c = new Set(t.map((n) => n.name)), s = o.manifest.edge_tables.filter(
45
- (n) => c.has(n.source.references) && c.has(n.destination.references)
46
- ), l = await Promise.all(
47
- s.map((n) => x(o, { table: n.name, select: [n.source.key, n.destination.key] }, r))
48
- ), a = new Float32Array(2 * s.reduce((n, m) => n + m.record_count, 0));
49
- let i = 0;
50
- return l.forEach((n, m) => {
51
- var u, w;
52
- const f = s[m];
53
- for (const d of n) {
54
- const N = ((u = d.getChild(f.source.key)) == null ? void 0 : u.toArray()) ?? [], b = ((w = d.getChild(f.destination.key)) == null ? void 0 : w.toArray()) ?? [];
55
- for (let y = 0; y < d.numRows && i < a.length; y++) {
56
- const h = Number(N[y]), k = Number(b[y]);
57
- h < e && k < e && (a[i++] = h, a[i++] = k);
58
- }
59
- }
60
- }), i === a.length ? a : a.slice(0, i);
20
+ function T(e) {
21
+ let [o, t, s, n] = [1 / 0, 1 / 0, -1 / 0, -1 / 0];
22
+ for (let r = 0; r < e.length; r += 2) {
23
+ const l = e[r], a = e[r + 1];
24
+ Number.isNaN(l) || Number.isNaN(a) || (l < o && (o = l), l > s && (s = l), a < t && (t = a), a > n && (n = a));
25
+ }
26
+ return o > s ? null : { x: o, y: t, w: s - o, h: n - t };
61
27
  }
62
- async function D(o, t, e, r) {
63
- const c = _(o), s = c.reduce((f, u) => f + u.record_count, 0), l = new Float32Array(2 * s).fill(Number.NaN), a = new Uint16Array(s), i = E(c, s, t, e), [n, m] = await C(
64
- r,
65
- (f) => Promise.all([
66
- Promise.all(
67
- c.map((u) => {
68
- const { x: w, y: d } = u.position;
69
- return x(o, { table: u.name, select: g(t, [u.key, w, d], v(u)) }, f);
70
- })
71
- ),
72
- S(o, c, s, f)
73
- ])
74
- );
75
- return n.forEach((f, u) => {
76
- var N, b, y;
77
- const { key: w, position: d } = c[u];
78
- for (const h of f) {
79
- const k = ((N = h.getChild(w)) == null ? void 0 : N.toArray()) ?? [], z = ((b = h.getChild((d == null ? void 0 : d.x) ?? "")) == null ? void 0 : b.toArray()) ?? [], P = ((y = h.getChild((d == null ? void 0 : d.y) ?? "")) == null ? void 0 : y.toArray()) ?? [];
80
- for (let A = 0; A < h.numRows; A++) {
81
- const p = Number(k[A]);
82
- p < s && (l[p * 2] = Number(z[A] ?? Number.NaN), l[p * 2 + 1] = Number(P[A] ?? Number.NaN), a[p] = u);
83
- }
84
- i.add(u, h);
28
+ async function O(e, o, t) {
29
+ var y, d;
30
+ const { size: s } = o, n = q(s), r = t.x !== void 0 && t.y !== void 0, [l, a] = await Promise.all([
31
+ P(e, o),
32
+ r ? z(e, o, [t.x, t.y]) : Promise.resolve([])
33
+ ]);
34
+ if (!r) return { structure: o, size: s, positions: R(s, n), bound: r, links: l, extent: null, space: n };
35
+ const i = new Float32Array(2 * s).fill(Number.NaN);
36
+ for (const { table: h, answer: m } of a) {
37
+ const w = ((y = m.getChild(t.x)) == null ? void 0 : y.toArray()) ?? [], x = ((d = m.getChild(t.y)) == null ? void 0 : d.toArray()) ?? [];
38
+ for (let f = 0; f < m.numRows; f++) {
39
+ const v = 2 * (h.first + f);
40
+ i[v] = w[f] === null ? Number.NaN : Number(w[f]), i[v + 1] = x[f] === null ? Number.NaN : Number(x[f]);
85
41
  }
86
- }), { geometry: { tables: c, size: s, positions: l, table: a, links: m, extent: F(l) }, encoding: i.finish() };
42
+ }
43
+ return { structure: o, size: s, positions: i, bound: r, links: l, extent: T(i), space: n };
87
44
  }
88
- async function K(o, t, e, r, c) {
89
- const { tables: s, size: l } = t, a = E(s, l, e, r);
90
- return (await C(
91
- c,
92
- (n) => Promise.all(s.map((m) => x(o, { table: m.name, select: g(e, [m.key], v(m)) }, n)))
93
- )).forEach((n, m) => {
94
- for (const f of n) a.add(m, f);
95
- }), a.finish();
45
+ function D(e, o) {
46
+ const t = new Float32Array(e);
47
+ for (let s = 0; s < o.length; s++) {
48
+ const n = o[s];
49
+ t[n] = t[n] + 1;
50
+ }
51
+ return t;
96
52
  }
97
- async function L(o, t, e, r) {
98
- const c = R(e), s = t.flatMap((i, n) => c.every(v(i)) ? [n] : []);
99
- if (s.length === 0)
100
- throw new I("graph/untranslatable-filter", `no drawn vertex type has every column this filter names: ${c.join(", ")}`);
101
- const l = await C(
102
- r,
103
- (i) => Promise.all(
104
- s.map((n) => x(o, { table: t[n].name, filter: e, select: [t[n].key] }, i))
105
- )
106
- ), a = [];
107
- return l.forEach((i, n) => {
108
- var f;
109
- const { key: m } = t[s[n]];
110
- for (const u of i) {
111
- const w = ((f = u.getChild(m)) == null ? void 0 : f.toArray()) ?? [];
112
- for (let d = 0; d < u.numRows; d++) a.push(Number(w[d]));
53
+ async function S(e, o, t, s) {
54
+ var v, C, F;
55
+ const { structure: n, size: r } = o, l = [t.category, t.size, t.cluster].filter((c) => c !== void 0), a = l.length > 0 ? await z(e, n, [...new Set(l)]) : [], i = new k(s), y = new Uint32Array(r), d = t.size === void 0 ? D(r, o.links) : new Float32Array(r).fill(Number.NaN), h = t.cluster === void 0 ? null : new k(), m = h ? new Array(r) : null;
56
+ if (t.byTable)
57
+ for (const c of n.vertices) y.fill(i.code(c.name), c.first, c.first + c.rows);
58
+ else t.category === void 0 && y.fill(i.code(null));
59
+ for (const { table: c, answer: N } of a) {
60
+ const I = t.category === void 0 || t.byTable || (v = N.getChild(t.category)) == null ? void 0 : v.toArray(), A = t.size === void 0 || (C = N.getChild(t.size)) == null ? void 0 : C.toArray(), M = t.cluster === void 0 || (F = N.getChild(t.cluster)) == null ? void 0 : F.toArray();
61
+ for (let u = 0; u < N.numRows; u++) {
62
+ const p = c.first + u;
63
+ I && (y[p] = i.code(I[u] ?? null)), A && (d[p] = A[u] === null ? Number.NaN : Number(A[u])), M && m && h && (m[p] = M[u] === null ? void 0 : h.code(M[u]));
113
64
  }
114
- }), { filtered: new Set(s), ids: a };
115
- }
116
- function M(o, t) {
117
- const e = new Uint8Array(o.size);
118
- for (let r = 0; r < o.size; r++) e[r] = t.filtered.has(o.table[r]) ? 0 : 1;
119
- for (const r of t.ids) r < o.size && (e[r] = 1);
120
- return e;
65
+ }
66
+ const w = i.ranks(), x = y.map((c) => w[c] ?? 0), f = [];
67
+ return w.forEach((c, N) => {
68
+ f[c] = i.values[N];
69
+ }), { ranks: x, sizes: d, clusters: m, domain: f };
121
70
  }
122
71
  export {
123
- _ as drawnTables,
124
- K as loadEncoding,
125
- D as loadGraph,
126
- M as maskOf,
127
- L as readKept,
128
- C as together
72
+ S as loadEncoding,
73
+ O as loadGeometry,
74
+ q as spaceFor
129
75
  };
130
76
  //# sourceMappingURL=load.js.map