@tldraw/commenting 0.0.0-bootstrap

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 (242) hide show
  1. package/README.md +11 -0
  2. package/commenting.css +832 -0
  3. package/dist-cjs/canvas/cluster-input.js +40 -0
  4. package/dist-cjs/canvas/cluster-input.js.map +7 -0
  5. package/dist-cjs/canvas/comment-body.js +31 -0
  6. package/dist-cjs/canvas/comment-body.js.map +7 -0
  7. package/dist-cjs/canvas/comment-render.js +72 -0
  8. package/dist-cjs/canvas/comment-render.js.map +7 -0
  9. package/dist-cjs/canvas/comment-store.js +48 -0
  10. package/dist-cjs/canvas/comment-store.js.map +7 -0
  11. package/dist-cjs/canvas/comment-tool.js +160 -0
  12. package/dist-cjs/canvas/comment-tool.js.map +7 -0
  13. package/dist-cjs/canvas/comments-filter-menu.js +109 -0
  14. package/dist-cjs/canvas/comments-filter-menu.js.map +7 -0
  15. package/dist-cjs/canvas/comments-menu-item.js +42 -0
  16. package/dist-cjs/canvas/comments-menu-item.js.map +7 -0
  17. package/dist-cjs/canvas/comments-overflow-menu.js +64 -0
  18. package/dist-cjs/canvas/comments-overflow-menu.js.map +7 -0
  19. package/dist-cjs/canvas/comments-overlay.js +1081 -0
  20. package/dist-cjs/canvas/comments-overlay.js.map +7 -0
  21. package/dist-cjs/canvas/comments-sidebar.js +134 -0
  22. package/dist-cjs/canvas/comments-sidebar.js.map +7 -0
  23. package/dist-cjs/canvas/hooks.js +45 -0
  24. package/dist-cjs/canvas/hooks.js.map +7 -0
  25. package/dist-cjs/canvas/license.js +28 -0
  26. package/dist-cjs/canvas/license.js.map +7 -0
  27. package/dist-cjs/canvas/options.js +45 -0
  28. package/dist-cjs/canvas/options.js.map +7 -0
  29. package/dist-cjs/canvas/region-options.js +49 -0
  30. package/dist-cjs/canvas/region-options.js.map +7 -0
  31. package/dist-cjs/canvas/rich-text.js +28 -0
  32. package/dist-cjs/canvas/rich-text.js.map +7 -0
  33. package/dist-cjs/canvas/sidebar-filters.js +30 -0
  34. package/dist-cjs/canvas/sidebar-filters.js.map +7 -0
  35. package/dist-cjs/canvas/state.js +76 -0
  36. package/dist-cjs/canvas/state.js.map +7 -0
  37. package/dist-cjs/canvas/thread-state.js +81 -0
  38. package/dist-cjs/canvas/thread-state.js.map +7 -0
  39. package/dist-cjs/clustering/computeClusterTable.js +83 -0
  40. package/dist-cjs/clustering/computeClusterTable.js.map +7 -0
  41. package/dist-cjs/clustering/mst.js +117 -0
  42. package/dist-cjs/clustering/mst.js.map +7 -0
  43. package/dist-cjs/clustering/replay.js +275 -0
  44. package/dist-cjs/clustering/replay.js.map +7 -0
  45. package/dist-cjs/clustering/runtime.js +134 -0
  46. package/dist-cjs/clustering/runtime.js.map +7 -0
  47. package/dist-cjs/clustering/schedule.js +170 -0
  48. package/dist-cjs/clustering/schedule.js.map +7 -0
  49. package/dist-cjs/clustering/types.js +17 -0
  50. package/dist-cjs/clustering/types.js.map +7 -0
  51. package/dist-cjs/index.d.ts +868 -0
  52. package/dist-cjs/index.js +126 -0
  53. package/dist-cjs/index.js.map +7 -0
  54. package/dist-cjs/ui/avatar.js +43 -0
  55. package/dist-cjs/ui/avatar.js.map +7 -0
  56. package/dist-cjs/ui/byline.js +35 -0
  57. package/dist-cjs/ui/byline.js.map +7 -0
  58. package/dist-cjs/ui/comment-card.js +37 -0
  59. package/dist-cjs/ui/comment-card.js.map +7 -0
  60. package/dist-cjs/ui/comment-composer.js +136 -0
  61. package/dist-cjs/ui/comment-composer.js.map +7 -0
  62. package/dist-cjs/ui/comment-extensions.js +37 -0
  63. package/dist-cjs/ui/comment-extensions.js.map +7 -0
  64. package/dist-cjs/ui/comment-mention.js +42 -0
  65. package/dist-cjs/ui/comment-mention.js.map +7 -0
  66. package/dist-cjs/ui/comment-pin.js +29 -0
  67. package/dist-cjs/ui/comment-pin.js.map +7 -0
  68. package/dist-cjs/ui/comment-text.js +29 -0
  69. package/dist-cjs/ui/comment-text.js.map +7 -0
  70. package/dist-cjs/ui/comment-thread.js +45 -0
  71. package/dist-cjs/ui/comment-thread.js.map +7 -0
  72. package/dist-cjs/ui/comments-list.js +106 -0
  73. package/dist-cjs/ui/comments-list.js.map +7 -0
  74. package/dist-cjs/ui/count-badge.js +28 -0
  75. package/dist-cjs/ui/count-badge.js.map +7 -0
  76. package/dist-cjs/ui/empty-state.js +31 -0
  77. package/dist-cjs/ui/empty-state.js.map +7 -0
  78. package/dist-cjs/ui/format-time.js +46 -0
  79. package/dist-cjs/ui/format-time.js.map +7 -0
  80. package/dist-cjs/ui/mention-list.js +70 -0
  81. package/dist-cjs/ui/mention-list.js.map +7 -0
  82. package/dist-cjs/ui/mention-suggestion.js +206 -0
  83. package/dist-cjs/ui/mention-suggestion.js.map +7 -0
  84. package/dist-cjs/ui/mention.js +31 -0
  85. package/dist-cjs/ui/mention.js.map +7 -0
  86. package/dist-cjs/ui/reaction.js +31 -0
  87. package/dist-cjs/ui/reaction.js.map +7 -0
  88. package/dist-cjs/ui/reactions.js +34 -0
  89. package/dist-cjs/ui/reactions.js.map +7 -0
  90. package/dist-cjs/ui/render-markdown.js +63 -0
  91. package/dist-cjs/ui/render-markdown.js.map +7 -0
  92. package/dist-cjs/ui/send-button.js +28 -0
  93. package/dist-cjs/ui/send-button.js.map +7 -0
  94. package/dist-esm/canvas/cluster-input.mjs +20 -0
  95. package/dist-esm/canvas/cluster-input.mjs.map +7 -0
  96. package/dist-esm/canvas/comment-body.mjs +11 -0
  97. package/dist-esm/canvas/comment-body.mjs.map +7 -0
  98. package/dist-esm/canvas/comment-render.mjs +52 -0
  99. package/dist-esm/canvas/comment-render.mjs.map +7 -0
  100. package/dist-esm/canvas/comment-store.mjs +28 -0
  101. package/dist-esm/canvas/comment-store.mjs.map +7 -0
  102. package/dist-esm/canvas/comment-tool.mjs +142 -0
  103. package/dist-esm/canvas/comment-tool.mjs.map +7 -0
  104. package/dist-esm/canvas/comments-filter-menu.mjs +99 -0
  105. package/dist-esm/canvas/comments-filter-menu.mjs.map +7 -0
  106. package/dist-esm/canvas/comments-menu-item.mjs +22 -0
  107. package/dist-esm/canvas/comments-menu-item.mjs.map +7 -0
  108. package/dist-esm/canvas/comments-overflow-menu.mjs +53 -0
  109. package/dist-esm/canvas/comments-overflow-menu.mjs.map +7 -0
  110. package/dist-esm/canvas/comments-overlay.mjs +1094 -0
  111. package/dist-esm/canvas/comments-overlay.mjs.map +7 -0
  112. package/dist-esm/canvas/comments-sidebar.mjs +120 -0
  113. package/dist-esm/canvas/comments-sidebar.mjs.map +7 -0
  114. package/dist-esm/canvas/hooks.mjs +25 -0
  115. package/dist-esm/canvas/hooks.mjs.map +7 -0
  116. package/dist-esm/canvas/license.mjs +8 -0
  117. package/dist-esm/canvas/license.mjs.map +7 -0
  118. package/dist-esm/canvas/options.mjs +27 -0
  119. package/dist-esm/canvas/options.mjs.map +7 -0
  120. package/dist-esm/canvas/region-options.mjs +29 -0
  121. package/dist-esm/canvas/region-options.mjs.map +7 -0
  122. package/dist-esm/canvas/rich-text.mjs +8 -0
  123. package/dist-esm/canvas/rich-text.mjs.map +7 -0
  124. package/dist-esm/canvas/sidebar-filters.mjs +10 -0
  125. package/dist-esm/canvas/sidebar-filters.mjs.map +7 -0
  126. package/dist-esm/canvas/state.mjs +60 -0
  127. package/dist-esm/canvas/state.mjs.map +7 -0
  128. package/dist-esm/canvas/thread-state.mjs +61 -0
  129. package/dist-esm/canvas/thread-state.mjs.map +7 -0
  130. package/dist-esm/clustering/computeClusterTable.mjs +63 -0
  131. package/dist-esm/clustering/computeClusterTable.mjs.map +7 -0
  132. package/dist-esm/clustering/mst.mjs +97 -0
  133. package/dist-esm/clustering/mst.mjs.map +7 -0
  134. package/dist-esm/clustering/replay.mjs +255 -0
  135. package/dist-esm/clustering/replay.mjs.map +7 -0
  136. package/dist-esm/clustering/runtime.mjs +114 -0
  137. package/dist-esm/clustering/runtime.mjs.map +7 -0
  138. package/dist-esm/clustering/schedule.mjs +150 -0
  139. package/dist-esm/clustering/schedule.mjs.map +7 -0
  140. package/dist-esm/clustering/types.mjs +1 -0
  141. package/dist-esm/clustering/types.mjs.map +7 -0
  142. package/dist-esm/index.d.mts +868 -0
  143. package/dist-esm/index.mjs +139 -0
  144. package/dist-esm/index.mjs.map +7 -0
  145. package/dist-esm/ui/avatar.mjs +23 -0
  146. package/dist-esm/ui/avatar.mjs.map +7 -0
  147. package/dist-esm/ui/byline.mjs +15 -0
  148. package/dist-esm/ui/byline.mjs.map +7 -0
  149. package/dist-esm/ui/comment-card.mjs +17 -0
  150. package/dist-esm/ui/comment-card.mjs.map +7 -0
  151. package/dist-esm/ui/comment-composer.mjs +116 -0
  152. package/dist-esm/ui/comment-composer.mjs.map +7 -0
  153. package/dist-esm/ui/comment-extensions.mjs +17 -0
  154. package/dist-esm/ui/comment-extensions.mjs.map +7 -0
  155. package/dist-esm/ui/comment-mention.mjs +22 -0
  156. package/dist-esm/ui/comment-mention.mjs.map +7 -0
  157. package/dist-esm/ui/comment-pin.mjs +9 -0
  158. package/dist-esm/ui/comment-pin.mjs.map +7 -0
  159. package/dist-esm/ui/comment-text.mjs +9 -0
  160. package/dist-esm/ui/comment-text.mjs.map +7 -0
  161. package/dist-esm/ui/comment-thread.mjs +25 -0
  162. package/dist-esm/ui/comment-thread.mjs.map +7 -0
  163. package/dist-esm/ui/comments-list.mjs +86 -0
  164. package/dist-esm/ui/comments-list.mjs.map +7 -0
  165. package/dist-esm/ui/count-badge.mjs +8 -0
  166. package/dist-esm/ui/count-badge.mjs.map +7 -0
  167. package/dist-esm/ui/empty-state.mjs +11 -0
  168. package/dist-esm/ui/empty-state.mjs.map +7 -0
  169. package/dist-esm/ui/format-time.mjs +26 -0
  170. package/dist-esm/ui/format-time.mjs.map +7 -0
  171. package/dist-esm/ui/mention-list.mjs +50 -0
  172. package/dist-esm/ui/mention-list.mjs.map +7 -0
  173. package/dist-esm/ui/mention-suggestion.mjs +186 -0
  174. package/dist-esm/ui/mention-suggestion.mjs.map +7 -0
  175. package/dist-esm/ui/mention.mjs +11 -0
  176. package/dist-esm/ui/mention.mjs.map +7 -0
  177. package/dist-esm/ui/reaction.mjs +11 -0
  178. package/dist-esm/ui/reaction.mjs.map +7 -0
  179. package/dist-esm/ui/reactions.mjs +14 -0
  180. package/dist-esm/ui/reactions.mjs.map +7 -0
  181. package/dist-esm/ui/render-markdown.mjs +45 -0
  182. package/dist-esm/ui/render-markdown.mjs.map +7 -0
  183. package/dist-esm/ui/send-button.mjs +8 -0
  184. package/dist-esm/ui/send-button.mjs.map +7 -0
  185. package/package.json +71 -0
  186. package/src/canvas/canvas.css +148 -0
  187. package/src/canvas/cluster-input.test.ts +223 -0
  188. package/src/canvas/cluster-input.ts +29 -0
  189. package/src/canvas/comment-body.tsx +21 -0
  190. package/src/canvas/comment-render.test.ts +90 -0
  191. package/src/canvas/comment-render.ts +92 -0
  192. package/src/canvas/comment-store.ts +55 -0
  193. package/src/canvas/comment-tool.tsx +200 -0
  194. package/src/canvas/comments-filter-menu.tsx +104 -0
  195. package/src/canvas/comments-menu-item.tsx +24 -0
  196. package/src/canvas/comments-overflow-menu.tsx +62 -0
  197. package/src/canvas/comments-overlay.tsx +1460 -0
  198. package/src/canvas/comments-sidebar.tsx +184 -0
  199. package/src/canvas/hooks.ts +28 -0
  200. package/src/canvas/license.ts +15 -0
  201. package/src/canvas/options.test.ts +127 -0
  202. package/src/canvas/options.ts +111 -0
  203. package/src/canvas/region-options.ts +57 -0
  204. package/src/canvas/rich-text.ts +15 -0
  205. package/src/canvas/sidebar-filters.ts +25 -0
  206. package/src/canvas/state.ts +102 -0
  207. package/src/canvas/thread-state.ts +91 -0
  208. package/src/clustering/computeClusterTable.test.ts +299 -0
  209. package/src/clustering/computeClusterTable.ts +82 -0
  210. package/src/clustering/locality.test.ts +189 -0
  211. package/src/clustering/mst.test.ts +383 -0
  212. package/src/clustering/mst.ts +134 -0
  213. package/src/clustering/replay.test.ts +547 -0
  214. package/src/clustering/replay.ts +326 -0
  215. package/src/clustering/runtime.test.ts +596 -0
  216. package/src/clustering/runtime.ts +153 -0
  217. package/src/clustering/schedule.test.ts +514 -0
  218. package/src/clustering/schedule.ts +184 -0
  219. package/src/clustering/types.ts +102 -0
  220. package/src/index.ts +96 -0
  221. package/src/ui/avatar.tsx +31 -0
  222. package/src/ui/byline.tsx +23 -0
  223. package/src/ui/comment-card.tsx +32 -0
  224. package/src/ui/comment-composer.tsx +179 -0
  225. package/src/ui/comment-extensions.ts +25 -0
  226. package/src/ui/comment-mention.ts +47 -0
  227. package/src/ui/comment-pin.tsx +21 -0
  228. package/src/ui/comment-text.tsx +12 -0
  229. package/src/ui/comment-thread.tsx +56 -0
  230. package/src/ui/comments-list.tsx +139 -0
  231. package/src/ui/comments.css +678 -0
  232. package/src/ui/count-badge.tsx +9 -0
  233. package/src/ui/empty-state.tsx +16 -0
  234. package/src/ui/format-time.ts +29 -0
  235. package/src/ui/mention-list.tsx +106 -0
  236. package/src/ui/mention-suggestion.test.ts +18 -0
  237. package/src/ui/mention-suggestion.tsx +285 -0
  238. package/src/ui/mention.tsx +9 -0
  239. package/src/ui/reaction.tsx +16 -0
  240. package/src/ui/reactions.tsx +15 -0
  241. package/src/ui/render-markdown.tsx +72 -0
  242. package/src/ui/send-button.tsx +15 -0
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var replay_exports = {};
20
+ __export(replay_exports, {
21
+ D_FLOOR: () => D_FLOOR,
22
+ cappedReplay: () => cappedReplay
23
+ });
24
+ module.exports = __toCommonJS(replay_exports);
25
+ const D_FLOOR = 1e-9;
26
+ function cappedReplay(leaves, edges, opts) {
27
+ validateOptions(opts);
28
+ if (edges.length === 0) return [];
29
+ const clusters = new ClusterState(leaves);
30
+ const heap = new EdgeMaxHeap(edges, leaves);
31
+ const incident = leaves.map(() => []);
32
+ for (let i = 0; i < edges.length; i++) {
33
+ heap.push({ edgeIndex: i, z: zForEdge(edges[i], clusters, opts) });
34
+ incident[edges[i].a].push(i);
35
+ incident[edges[i].b].push(i);
36
+ }
37
+ const events = [];
38
+ let lastZ = Number.POSITIVE_INFINITY;
39
+ while (events.length < edges.length) {
40
+ const entry = heap.pop();
41
+ if (!entry) break;
42
+ const edge = edges[entry.edgeIndex];
43
+ const aRoot = clusters.find(edge.a);
44
+ const bRoot = clusters.find(edge.b);
45
+ if (aRoot === bRoot) continue;
46
+ const current = { edgeIndex: entry.edgeIndex, z: zForRoots(edge, aRoot, bRoot, clusters, opts) };
47
+ const next = heap.peek();
48
+ if (next && heap.higherPriority(next, current)) {
49
+ heap.push(current);
50
+ continue;
51
+ }
52
+ const z = Math.min(current.z, lastZ);
53
+ lastZ = z;
54
+ events.push(clusters.merge(aRoot, bRoot, z));
55
+ const root = clusters.find(edge.a);
56
+ const other = root === aRoot ? bRoot : aRoot;
57
+ const survivors = [];
58
+ for (const idx of [...incident[root], ...incident[other]]) {
59
+ const e2 = edges[idx];
60
+ const ra = clusters.find(e2.a);
61
+ const rb = clusters.find(e2.b);
62
+ if (ra === rb) continue;
63
+ survivors.push(idx);
64
+ heap.push({ edgeIndex: idx, z: zForRoots(e2, ra, rb, clusters, opts) });
65
+ }
66
+ incident[root] = survivors;
67
+ }
68
+ return events;
69
+ }
70
+ function validateOptions(opts) {
71
+ if (!Number.isFinite(opts.Tc) || opts.Tc <= 0) {
72
+ throw new Error("Tc must be greater than 0");
73
+ }
74
+ if (!Number.isFinite(opts.Dmax) || opts.Dmax <= 0) {
75
+ throw new Error("Dmax must be greater than 0");
76
+ }
77
+ if (opts.Dmax < opts.Tc) {
78
+ throw new Error("Dmax must be greater than or equal to Tc");
79
+ }
80
+ }
81
+ function zForEdge(edge, clusters, opts) {
82
+ return zForRoots(edge, clusters.find(edge.a), clusters.find(edge.b), clusters, opts);
83
+ }
84
+ function zForRoots(edge, aRoot, bRoot, clusters, opts) {
85
+ if (edge.d < D_FLOOR) return Number.POSITIVE_INFINITY;
86
+ const gap = opts.Tc / clusters.centroidDistance(aRoot, bRoot);
87
+ const fit = opts.Dmax / clusters.unionBboxDiag(aRoot, bRoot);
88
+ return Math.min(gap, fit);
89
+ }
90
+ class ClusterState {
91
+ parent;
92
+ minX;
93
+ minY;
94
+ maxX;
95
+ maxY;
96
+ centroidX;
97
+ centroidY;
98
+ counts;
99
+ nodes;
100
+ memberLists;
101
+ minMemberIds;
102
+ constructor(leaves) {
103
+ const n = leaves.length;
104
+ this.parent = new Int32Array(n);
105
+ this.minX = new Float64Array(n);
106
+ this.minY = new Float64Array(n);
107
+ this.maxX = new Float64Array(n);
108
+ this.maxY = new Float64Array(n);
109
+ this.centroidX = new Float64Array(n);
110
+ this.centroidY = new Float64Array(n);
111
+ this.counts = new Int32Array(n);
112
+ this.nodes = new Array(n);
113
+ this.memberLists = new Array(n);
114
+ this.minMemberIds = new Array(n);
115
+ for (let i = 0; i < n; i++) {
116
+ const leaf = leaves[i];
117
+ this.parent[i] = i;
118
+ this.minX[i] = leaf.point.x;
119
+ this.minY[i] = leaf.point.y;
120
+ this.maxX[i] = leaf.point.x;
121
+ this.maxY[i] = leaf.point.y;
122
+ this.centroidX[i] = leaf.point.x;
123
+ this.centroidY[i] = leaf.point.y;
124
+ this.counts[i] = 1;
125
+ this.memberLists[i] = [leaf.id];
126
+ this.minMemberIds[i] = leaf.id;
127
+ this.nodes[i] = {
128
+ id: leaf.id,
129
+ centroid: { x: leaf.point.x, y: leaf.point.y },
130
+ count: 1,
131
+ members: [leaf.id]
132
+ };
133
+ }
134
+ }
135
+ find(index) {
136
+ let root = index;
137
+ while (this.parent[root] !== root) {
138
+ root = this.parent[root];
139
+ }
140
+ while (this.parent[index] !== index) {
141
+ const next = this.parent[index];
142
+ this.parent[index] = root;
143
+ index = next;
144
+ }
145
+ return root;
146
+ }
147
+ centroidDistance(aRoot, bRoot) {
148
+ return Math.hypot(
149
+ this.centroidX[aRoot] - this.centroidX[bRoot],
150
+ this.centroidY[aRoot] - this.centroidY[bRoot]
151
+ );
152
+ }
153
+ unionBboxDiag(aRoot, bRoot) {
154
+ const minX = Math.min(this.minX[aRoot], this.minX[bRoot]);
155
+ const minY = Math.min(this.minY[aRoot], this.minY[bRoot]);
156
+ const maxX = Math.max(this.maxX[aRoot], this.maxX[bRoot]);
157
+ const maxY = Math.max(this.maxY[aRoot], this.maxY[bRoot]);
158
+ return Math.hypot(maxX - minX, maxY - minY);
159
+ }
160
+ merge(aRoot, bRoot, z) {
161
+ const leftRoot = this.minMemberIds[aRoot] < this.minMemberIds[bRoot] ? aRoot : bRoot;
162
+ const rightRoot = leftRoot === aRoot ? bRoot : aRoot;
163
+ const left = this.nodes[leftRoot];
164
+ const right = this.nodes[rightRoot];
165
+ const count = this.counts[leftRoot] + this.counts[rightRoot];
166
+ const members = mergeSortedMembers(this.memberLists[leftRoot], this.memberLists[rightRoot]);
167
+ const minX = Math.min(this.minX[leftRoot], this.minX[rightRoot]);
168
+ const minY = Math.min(this.minY[leftRoot], this.minY[rightRoot]);
169
+ const maxX = Math.max(this.maxX[leftRoot], this.maxX[rightRoot]);
170
+ const maxY = Math.max(this.maxY[leftRoot], this.maxY[rightRoot]);
171
+ const centroidX = (this.counts[leftRoot] * this.centroidX[leftRoot] + this.counts[rightRoot] * this.centroidX[rightRoot]) / count;
172
+ const centroidY = (this.counts[leftRoot] * this.centroidY[leftRoot] + this.counts[rightRoot] * this.centroidY[rightRoot]) / count;
173
+ const result = {
174
+ id: `cluster:${count}:${members[0]}`,
175
+ centroid: { x: centroidX, y: centroidY },
176
+ count,
177
+ members
178
+ };
179
+ this.parent[rightRoot] = leftRoot;
180
+ this.minX[leftRoot] = minX;
181
+ this.minY[leftRoot] = minY;
182
+ this.maxX[leftRoot] = maxX;
183
+ this.maxY[leftRoot] = maxY;
184
+ this.centroidX[leftRoot] = centroidX;
185
+ this.centroidY[leftRoot] = centroidY;
186
+ this.counts[leftRoot] = count;
187
+ this.nodes[leftRoot] = result;
188
+ this.memberLists[leftRoot] = members;
189
+ this.minMemberIds[leftRoot] = members[0];
190
+ return { z, children: [left, right], result };
191
+ }
192
+ }
193
+ function mergeSortedMembers(a, b) {
194
+ const out = new Array(a.length + b.length);
195
+ let i = 0;
196
+ let j = 0;
197
+ let k = 0;
198
+ while (i < a.length && j < b.length) {
199
+ if (a[i] < b[j]) {
200
+ out[k++] = a[i++];
201
+ } else {
202
+ out[k++] = b[j++];
203
+ }
204
+ }
205
+ while (i < a.length) out[k++] = a[i++];
206
+ while (j < b.length) out[k++] = b[j++];
207
+ return out;
208
+ }
209
+ class EdgeMaxHeap {
210
+ constructor(edges, leaves) {
211
+ this.edges = edges;
212
+ this.leaves = leaves;
213
+ }
214
+ edges;
215
+ leaves;
216
+ items = [];
217
+ peek() {
218
+ return this.items[0];
219
+ }
220
+ push(entry) {
221
+ this.items.push(entry);
222
+ this.siftUp(this.items.length - 1);
223
+ }
224
+ pop() {
225
+ if (this.items.length === 0) return void 0;
226
+ const first = this.items[0];
227
+ const last = this.items.pop();
228
+ if (this.items.length > 0) {
229
+ this.items[0] = last;
230
+ this.siftDown(0);
231
+ }
232
+ return first;
233
+ }
234
+ higherPriority(a, b) {
235
+ if (a.z > b.z) return true;
236
+ if (a.z < b.z) return false;
237
+ return edgeIdPairLess(this.edges[a.edgeIndex], this.edges[b.edgeIndex], this.leaves);
238
+ }
239
+ siftUp(index) {
240
+ while (index > 0) {
241
+ const parent = index - 1 >> 1;
242
+ if (!this.higherPriority(this.items[index], this.items[parent])) break;
243
+ [this.items[index], this.items[parent]] = [this.items[parent], this.items[index]];
244
+ index = parent;
245
+ }
246
+ }
247
+ siftDown(index) {
248
+ while (true) {
249
+ const left = index * 2 + 1;
250
+ const right = left + 1;
251
+ let best = index;
252
+ if (left < this.items.length && this.higherPriority(this.items[left], this.items[best])) {
253
+ best = left;
254
+ }
255
+ if (right < this.items.length && this.higherPriority(this.items[right], this.items[best])) {
256
+ best = right;
257
+ }
258
+ if (best === index) break;
259
+ [this.items[index], this.items[best]] = [this.items[best], this.items[index]];
260
+ index = best;
261
+ }
262
+ }
263
+ }
264
+ function edgeIdPairLess(a, b, leaves) {
265
+ const [aLo, aHi] = normalizedEdgeIds(a, leaves);
266
+ const [bLo, bHi] = normalizedEdgeIds(b, leaves);
267
+ if (aLo !== bLo) return aLo < bLo;
268
+ return aHi < bHi;
269
+ }
270
+ function normalizedEdgeIds(edge, leaves) {
271
+ const aId = leaves[edge.a].id;
272
+ const bId = leaves[edge.b].id;
273
+ return aId < bId ? [aId, bId] : [bId, aId];
274
+ }
275
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/clustering/replay.ts"],
4
+ "sourcesContent": ["import type { ClusterNode, LeafInput, MstEdge, RawMergeEvent } from './types'\n\nexport const D_FLOOR = 1e-9\n\nexport function cappedReplay(\n\tleaves: readonly LeafInput[],\n\tedges: readonly MstEdge[],\n\topts: { Tc: number; Dmax: number }\n): RawMergeEvent[] {\n\tvalidateOptions(opts)\n\n\tif (edges.length === 0) return []\n\n\tconst clusters = new ClusterState(leaves)\n\tconst heap = new EdgeMaxHeap(edges, leaves)\n\t// Edges incident to each current cluster root, for eager repricing: a merge\n\t// moves the result's centroid, which can RAISE an incident edge's key (the\n\t// centroid may move toward a neighbor), so the lazy pop-time recheck alone\n\t// is not enough \u2014 every price change pushes a fresh heap entry.\n\tconst incident: number[][] = leaves.map(() => [])\n\tfor (let i = 0; i < edges.length; i++) {\n\t\theap.push({ edgeIndex: i, z: zForEdge(edges[i], clusters, opts) })\n\t\tincident[edges[i].a].push(i)\n\t\tincident[edges[i].b].push(i)\n\t}\n\n\tconst events: RawMergeEvent[] = []\n\t// Emitted thresholds are clamped non-increasing: with centroid pricing a\n\t// later merge's raw price can in principle exceed an earlier one's, and the\n\t// table's descending sort is load-bearing for the runtime cursor.\n\tlet lastZ = Number.POSITIVE_INFINITY\n\twhile (events.length < edges.length) {\n\t\tconst entry = heap.pop()\n\t\tif (!entry) break\n\n\t\tconst edge = edges[entry.edgeIndex]\n\t\tconst aRoot = clusters.find(edge.a)\n\t\tconst bRoot = clusters.find(edge.b)\n\t\tif (aRoot === bRoot) continue // stale duplicate of an already-fired edge\n\n\t\tconst current = { edgeIndex: entry.edgeIndex, z: zForRoots(edge, aRoot, bRoot, clusters, opts) }\n\t\tconst next = heap.peek()\n\t\tif (next && heap.higherPriority(next, current)) {\n\t\t\theap.push(current)\n\t\t\tcontinue\n\t\t}\n\n\t\tconst z = Math.min(current.z, lastZ)\n\t\tlastZ = z\n\t\tevents.push(clusters.merge(aRoot, bRoot, z))\n\n\t\t// eager reprice: the new cluster's centroid and bbox changed, so every\n\t\t// surviving incident edge gets a fresh entry at its current price\n\t\tconst root = clusters.find(edge.a)\n\t\tconst other = root === aRoot ? bRoot : aRoot\n\t\tconst survivors: number[] = []\n\t\tfor (const idx of [...incident[root], ...incident[other]]) {\n\t\t\tconst e2 = edges[idx]\n\t\t\tconst ra = clusters.find(e2.a)\n\t\t\tconst rb = clusters.find(e2.b)\n\t\t\tif (ra === rb) continue\n\t\t\tsurvivors.push(idx)\n\t\t\theap.push({ edgeIndex: idx, z: zForRoots(e2, ra, rb, clusters, opts) })\n\t\t}\n\t\tincident[root] = survivors\n\t}\n\n\treturn events\n}\n\nfunction validateOptions(opts: { Tc: number; Dmax: number }) {\n\tif (!Number.isFinite(opts.Tc) || opts.Tc <= 0) {\n\t\tthrow new Error('Tc must be greater than 0')\n\t}\n\tif (!Number.isFinite(opts.Dmax) || opts.Dmax <= 0) {\n\t\tthrow new Error('Dmax must be greater than 0')\n\t}\n\tif (opts.Dmax < opts.Tc) {\n\t\tthrow new Error('Dmax must be greater than or equal to Tc')\n\t}\n}\n\nfunction zForEdge(\n\tedge: MstEdge,\n\tclusters: ClusterState,\n\topts: { Tc: number; Dmax: number }\n): number {\n\treturn zForRoots(edge, clusters.find(edge.a), clusters.find(edge.b), clusters, opts)\n}\n\nfunction zForRoots(\n\tedge: MstEdge,\n\taRoot: number,\n\tbRoot: number,\n\tclusters: ClusterState,\n\topts: { Tc: number; Dmax: number }\n): number {\n\tif (edge.d < D_FLOOR) return Number.POSITIVE_INFINITY\n\t// Badge-anchored gap pricing: clusters render as badges at their centroids,\n\t// so the merge is priced by the distance between the rendered centers, not\n\t// the nearest members. For leaves the two are identical; for clusters the\n\t// centroid distance is larger, so groups merge later than their closest\n\t// members would suggest \u2014 matching what the user actually sees.\n\t// (Coincident CENTROIDS with non-coincident members leave the gap term\n\t// Infinity and the fit term finite \u2014 the min stays finite, no special case.)\n\tconst gap = opts.Tc / clusters.centroidDistance(aRoot, bRoot)\n\tconst fit = opts.Dmax / clusters.unionBboxDiag(aRoot, bRoot)\n\treturn Math.min(gap, fit)\n}\n\nclass ClusterState {\n\tprivate readonly parent: Int32Array\n\tprivate readonly minX: Float64Array\n\tprivate readonly minY: Float64Array\n\tprivate readonly maxX: Float64Array\n\tprivate readonly maxY: Float64Array\n\tprivate readonly centroidX: Float64Array\n\tprivate readonly centroidY: Float64Array\n\tprivate readonly counts: Int32Array\n\tprivate readonly nodes: ClusterNode[]\n\tprivate readonly memberLists: string[][]\n\tprivate readonly minMemberIds: string[]\n\n\tconstructor(leaves: readonly LeafInput[]) {\n\t\tconst n = leaves.length\n\t\tthis.parent = new Int32Array(n)\n\t\tthis.minX = new Float64Array(n)\n\t\tthis.minY = new Float64Array(n)\n\t\tthis.maxX = new Float64Array(n)\n\t\tthis.maxY = new Float64Array(n)\n\t\tthis.centroidX = new Float64Array(n)\n\t\tthis.centroidY = new Float64Array(n)\n\t\tthis.counts = new Int32Array(n)\n\t\tthis.nodes = new Array(n)\n\t\tthis.memberLists = new Array(n)\n\t\tthis.minMemberIds = new Array(n)\n\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tconst leaf = leaves[i]\n\t\t\tthis.parent[i] = i\n\t\t\tthis.minX[i] = leaf.point.x\n\t\t\tthis.minY[i] = leaf.point.y\n\t\t\tthis.maxX[i] = leaf.point.x\n\t\t\tthis.maxY[i] = leaf.point.y\n\t\t\tthis.centroidX[i] = leaf.point.x\n\t\t\tthis.centroidY[i] = leaf.point.y\n\t\t\tthis.counts[i] = 1\n\t\t\tthis.memberLists[i] = [leaf.id]\n\t\t\tthis.minMemberIds[i] = leaf.id\n\t\t\tthis.nodes[i] = {\n\t\t\t\tid: leaf.id,\n\t\t\t\tcentroid: { x: leaf.point.x, y: leaf.point.y },\n\t\t\t\tcount: 1,\n\t\t\t\tmembers: [leaf.id],\n\t\t\t}\n\t\t}\n\t}\n\n\tfind(index: number): number {\n\t\tlet root = index\n\t\twhile (this.parent[root] !== root) {\n\t\t\troot = this.parent[root]\n\t\t}\n\t\twhile (this.parent[index] !== index) {\n\t\t\tconst next = this.parent[index]\n\t\t\tthis.parent[index] = root\n\t\t\tindex = next\n\t\t}\n\t\treturn root\n\t}\n\n\tcentroidDistance(aRoot: number, bRoot: number): number {\n\t\treturn Math.hypot(\n\t\t\tthis.centroidX[aRoot] - this.centroidX[bRoot],\n\t\t\tthis.centroidY[aRoot] - this.centroidY[bRoot]\n\t\t)\n\t}\n\n\tunionBboxDiag(aRoot: number, bRoot: number): number {\n\t\tconst minX = Math.min(this.minX[aRoot], this.minX[bRoot])\n\t\tconst minY = Math.min(this.minY[aRoot], this.minY[bRoot])\n\t\tconst maxX = Math.max(this.maxX[aRoot], this.maxX[bRoot])\n\t\tconst maxY = Math.max(this.maxY[aRoot], this.maxY[bRoot])\n\t\treturn Math.hypot(maxX - minX, maxY - minY)\n\t}\n\n\tmerge(aRoot: number, bRoot: number, z: number): RawMergeEvent {\n\t\tconst leftRoot = this.minMemberIds[aRoot] < this.minMemberIds[bRoot] ? aRoot : bRoot\n\t\tconst rightRoot = leftRoot === aRoot ? bRoot : aRoot\n\t\tconst left = this.nodes[leftRoot]\n\t\tconst right = this.nodes[rightRoot]\n\t\tconst count = this.counts[leftRoot] + this.counts[rightRoot]\n\t\tconst members = mergeSortedMembers(this.memberLists[leftRoot], this.memberLists[rightRoot])\n\n\t\tconst minX = Math.min(this.minX[leftRoot], this.minX[rightRoot])\n\t\tconst minY = Math.min(this.minY[leftRoot], this.minY[rightRoot])\n\t\tconst maxX = Math.max(this.maxX[leftRoot], this.maxX[rightRoot])\n\t\tconst maxY = Math.max(this.maxY[leftRoot], this.maxY[rightRoot])\n\t\tconst centroidX =\n\t\t\t(this.counts[leftRoot] * this.centroidX[leftRoot] +\n\t\t\t\tthis.counts[rightRoot] * this.centroidX[rightRoot]) /\n\t\t\tcount\n\t\tconst centroidY =\n\t\t\t(this.counts[leftRoot] * this.centroidY[leftRoot] +\n\t\t\t\tthis.counts[rightRoot] * this.centroidY[rightRoot]) /\n\t\t\tcount\n\n\t\t// Leaf ids are assumed not to start with `cluster:`; see the step 2 contract.\n\t\tconst result: ClusterNode = {\n\t\t\tid: `cluster:${count}:${members[0]}`,\n\t\t\tcentroid: { x: centroidX, y: centroidY },\n\t\t\tcount,\n\t\t\tmembers,\n\t\t}\n\n\t\tthis.parent[rightRoot] = leftRoot\n\t\tthis.minX[leftRoot] = minX\n\t\tthis.minY[leftRoot] = minY\n\t\tthis.maxX[leftRoot] = maxX\n\t\tthis.maxY[leftRoot] = maxY\n\t\tthis.centroidX[leftRoot] = centroidX\n\t\tthis.centroidY[leftRoot] = centroidY\n\t\tthis.counts[leftRoot] = count\n\t\tthis.nodes[leftRoot] = result\n\t\tthis.memberLists[leftRoot] = members\n\t\tthis.minMemberIds[leftRoot] = members[0]\n\n\t\treturn { z, children: [left, right], result }\n\t}\n}\n\nfunction mergeSortedMembers(a: readonly string[], b: readonly string[]): string[] {\n\tconst out = new Array<string>(a.length + b.length)\n\tlet i = 0\n\tlet j = 0\n\tlet k = 0\n\twhile (i < a.length && j < b.length) {\n\t\tif (a[i] < b[j]) {\n\t\t\tout[k++] = a[i++]\n\t\t} else {\n\t\t\tout[k++] = b[j++]\n\t\t}\n\t}\n\twhile (i < a.length) out[k++] = a[i++]\n\twhile (j < b.length) out[k++] = b[j++]\n\treturn out\n}\n\ninterface HeapEntry {\n\tedgeIndex: number\n\tz: number\n}\n\nclass EdgeMaxHeap {\n\tprivate readonly items: HeapEntry[] = []\n\n\tconstructor(\n\t\tprivate readonly edges: readonly MstEdge[],\n\t\tprivate readonly leaves: readonly LeafInput[]\n\t) {}\n\n\tpeek(): HeapEntry | undefined {\n\t\treturn this.items[0]\n\t}\n\n\tpush(entry: HeapEntry) {\n\t\tthis.items.push(entry)\n\t\tthis.siftUp(this.items.length - 1)\n\t}\n\n\tpop(): HeapEntry | undefined {\n\t\tif (this.items.length === 0) return undefined\n\t\tconst first = this.items[0]\n\t\tconst last = this.items.pop()!\n\t\tif (this.items.length > 0) {\n\t\t\tthis.items[0] = last\n\t\t\tthis.siftDown(0)\n\t\t}\n\t\treturn first\n\t}\n\n\thigherPriority(a: HeapEntry, b: HeapEntry): boolean {\n\t\tif (a.z > b.z) return true\n\t\tif (a.z < b.z) return false\n\t\treturn edgeIdPairLess(this.edges[a.edgeIndex], this.edges[b.edgeIndex], this.leaves)\n\t}\n\n\tprivate siftUp(index: number) {\n\t\twhile (index > 0) {\n\t\t\tconst parent = (index - 1) >> 1\n\t\t\tif (!this.higherPriority(this.items[index], this.items[parent])) break\n\t\t\t;[this.items[index], this.items[parent]] = [this.items[parent], this.items[index]]\n\t\t\tindex = parent\n\t\t}\n\t}\n\n\tprivate siftDown(index: number) {\n\t\twhile (true) {\n\t\t\tconst left = index * 2 + 1\n\t\t\tconst right = left + 1\n\t\t\tlet best = index\n\t\t\tif (left < this.items.length && this.higherPriority(this.items[left], this.items[best])) {\n\t\t\t\tbest = left\n\t\t\t}\n\t\t\tif (right < this.items.length && this.higherPriority(this.items[right], this.items[best])) {\n\t\t\t\tbest = right\n\t\t\t}\n\t\t\tif (best === index) break\n\t\t\t;[this.items[index], this.items[best]] = [this.items[best], this.items[index]]\n\t\t\tindex = best\n\t\t}\n\t}\n}\n\nfunction edgeIdPairLess(a: MstEdge, b: MstEdge, leaves: readonly LeafInput[]): boolean {\n\tconst [aLo, aHi] = normalizedEdgeIds(a, leaves)\n\tconst [bLo, bHi] = normalizedEdgeIds(b, leaves)\n\tif (aLo !== bLo) return aLo < bLo\n\treturn aHi < bHi\n}\n\nfunction normalizedEdgeIds(edge: MstEdge, leaves: readonly LeafInput[]): [string, string] {\n\tconst aId = leaves[edge.a].id\n\tconst bId = leaves[edge.b].id\n\treturn aId < bId ? [aId, bId] : [bId, aId]\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var runtime_exports = {};
20
+ __export(runtime_exports, {
21
+ createClusterRuntime: () => createClusterRuntime
22
+ });
23
+ module.exports = __toCommonJS(runtime_exports);
24
+ function createClusterRuntime(table) {
25
+ return new ClusterRuntimeImpl(table);
26
+ }
27
+ class ClusterRuntimeImpl {
28
+ constructor(table) {
29
+ this.table = table;
30
+ this.resetVisible();
31
+ }
32
+ table;
33
+ // mutable internally; readonly through the ClusterRuntime interface
34
+ k = 0;
35
+ visible = /* @__PURE__ */ new Map();
36
+ seeded = false;
37
+ seed(zoom) {
38
+ validateZoom(zoom);
39
+ this.k = seedCount(this.table.events, zoom);
40
+ this.resetVisible();
41
+ for (let i = 0; i < this.k; i++) {
42
+ applyEvent(this.visible, this.table.events[i]);
43
+ }
44
+ this.seeded = true;
45
+ }
46
+ seedFrom(zoom, previous) {
47
+ validateZoom(zoom);
48
+ const ownerByMember = /* @__PURE__ */ new Map();
49
+ for (const node of previous.values()) {
50
+ for (const member of node.members) {
51
+ ownerByMember.set(member, node.id);
52
+ }
53
+ }
54
+ const events = this.table.events;
55
+ let k = 0;
56
+ while (k < events.length) {
57
+ const event = events[k];
58
+ if (zoom >= event.zSplit) break;
59
+ if (zoom > event.zMerge && !wasMergedTogether(event.result.members, ownerByMember)) break;
60
+ k++;
61
+ }
62
+ this.k = k;
63
+ this.resetVisible();
64
+ for (let i = 0; i < k; i++) {
65
+ applyEvent(this.visible, events[i]);
66
+ }
67
+ this.seeded = true;
68
+ }
69
+ onCamera(zoom) {
70
+ validateZoom(zoom);
71
+ if (!this.seeded) {
72
+ throw new Error("Cluster runtime must be seeded before onCamera");
73
+ }
74
+ while (this.k < this.table.events.length && zoom <= this.table.events[this.k].zMerge) {
75
+ applyEvent(this.visible, this.table.events[this.k]);
76
+ this.k++;
77
+ }
78
+ while (this.k > 0 && zoom >= this.table.events[this.k - 1].zSplit) {
79
+ this.k--;
80
+ unapplyEvent(this.visible, this.table.events[this.k]);
81
+ }
82
+ }
83
+ getVisible() {
84
+ return this.visible;
85
+ }
86
+ resetVisible() {
87
+ this.visible = /* @__PURE__ */ new Map();
88
+ for (const leaf of this.table.leaves) {
89
+ this.visible.set(leaf.id, leaf);
90
+ }
91
+ }
92
+ }
93
+ function wasMergedTogether(members, ownerByMember) {
94
+ const owner = ownerByMember.get(members[0]);
95
+ if (owner === void 0) return false;
96
+ for (let i = 1; i < members.length; i++) {
97
+ if (ownerByMember.get(members[i]) !== owner) return false;
98
+ }
99
+ return true;
100
+ }
101
+ function seedCount(events, zoom) {
102
+ let lo = 0;
103
+ let hi = events.length;
104
+ while (lo < hi) {
105
+ const mid = lo + hi >> 1;
106
+ if (zoom <= seedThreshold(events[mid])) {
107
+ lo = mid + 1;
108
+ } else {
109
+ hi = mid;
110
+ }
111
+ }
112
+ return lo;
113
+ }
114
+ function seedThreshold(event) {
115
+ return Math.sqrt(event.zMerge * event.zSplit);
116
+ }
117
+ function applyEvent(visible, event) {
118
+ for (const child of event.children) {
119
+ visible.delete(child.id);
120
+ }
121
+ visible.set(event.result.id, event.result);
122
+ }
123
+ function unapplyEvent(visible, event) {
124
+ visible.delete(event.result.id);
125
+ for (const child of event.children) {
126
+ visible.set(child.id, child);
127
+ }
128
+ }
129
+ function validateZoom(zoom) {
130
+ if (!Number.isFinite(zoom) || zoom <= 0) {
131
+ throw new Error("zoom must be finite and greater than 0");
132
+ }
133
+ }
134
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/clustering/runtime.ts"],
4
+ "sourcesContent": ["import type { ClusterNode, ClusterTable, MergeEvent } from './types'\n\n/** @public */\nexport interface ClusterRuntime {\n\t/** Events[0..k) are active. Exposed for tests and debugging. */\n\treadonly k: number\n\t/** Reset state from scratch for the given zoom (cold start / after rebuild). */\n\tseed(zoom: number): void\n\t/**\n\t * Reset state for the given zoom, carrying hysteresis state over from a previous partition\n\t * (the visible map of the model being replaced). Threshold-forced events ignore history:\n\t * zoom \\<= zMerge is always active, zoom \\>= zSplit always inactive. An event inside its band\n\t * is active iff its members were merged together in `previous`; a band event with no history\n\t * (e.g. introduced by the rebuild) stays inactive until the next zoom-out crosses its zMerge.\n\t * Active events must form a prefix of the table, so classification stops at the first\n\t * inactive event; later band-active events conservatively resolve to split.\n\t */\n\tseedFrom(zoom: number, previous: ReadonlyMap<string, ClusterNode>): void\n\t/** Advance/retreat the cursor for a camera change. No-op if zoom sits inside all bands. */\n\tonCamera(zoom: number): void\n\t/** The current partition: cluster id \u2192 node. Do not mutate. */\n\tgetVisible(): ReadonlyMap<string, ClusterNode>\n}\n\n/** @public */\nexport function createClusterRuntime(table: ClusterTable): ClusterRuntime {\n\treturn new ClusterRuntimeImpl(table)\n}\n\nclass ClusterRuntimeImpl implements ClusterRuntime {\n\t// mutable internally; readonly through the ClusterRuntime interface\n\tk = 0\n\tprivate visible = new Map<string, ClusterNode>()\n\tprivate seeded = false\n\n\tconstructor(private readonly table: ClusterTable) {\n\t\tthis.resetVisible()\n\t}\n\n\tseed(zoom: number): void {\n\t\tvalidateZoom(zoom)\n\t\tthis.k = seedCount(this.table.events, zoom)\n\t\tthis.resetVisible()\n\t\tfor (let i = 0; i < this.k; i++) {\n\t\t\tapplyEvent(this.visible, this.table.events[i])\n\t\t}\n\t\tthis.seeded = true\n\t}\n\n\tseedFrom(zoom: number, previous: ReadonlyMap<string, ClusterNode>): void {\n\t\tvalidateZoom(zoom)\n\t\tconst ownerByMember = new Map<string, string>()\n\t\tfor (const node of previous.values()) {\n\t\t\tfor (const member of node.members) {\n\t\t\t\townerByMember.set(member, node.id)\n\t\t\t}\n\t\t}\n\n\t\tconst events = this.table.events\n\t\tlet k = 0\n\t\twhile (k < events.length) {\n\t\t\tconst event = events[k]\n\t\t\tif (zoom >= event.zSplit) break\n\t\t\tif (zoom > event.zMerge && !wasMergedTogether(event.result.members, ownerByMember)) break\n\t\t\tk++\n\t\t}\n\n\t\tthis.k = k\n\t\tthis.resetVisible()\n\t\tfor (let i = 0; i < k; i++) {\n\t\t\tapplyEvent(this.visible, events[i])\n\t\t}\n\t\tthis.seeded = true\n\t}\n\n\tonCamera(zoom: number): void {\n\t\tvalidateZoom(zoom)\n\t\tif (!this.seeded) {\n\t\t\tthrow new Error('Cluster runtime must be seeded before onCamera')\n\t\t}\n\n\t\twhile (this.k < this.table.events.length && zoom <= this.table.events[this.k].zMerge) {\n\t\t\tapplyEvent(this.visible, this.table.events[this.k])\n\t\t\tthis.k++\n\t\t}\n\t\twhile (this.k > 0 && zoom >= this.table.events[this.k - 1].zSplit) {\n\t\t\tthis.k--\n\t\t\tunapplyEvent(this.visible, this.table.events[this.k])\n\t\t}\n\t}\n\n\tgetVisible(): ReadonlyMap<string, ClusterNode> {\n\t\treturn this.visible\n\t}\n\n\tprivate resetVisible() {\n\t\tthis.visible = new Map()\n\t\tfor (const leaf of this.table.leaves) {\n\t\t\tthis.visible.set(leaf.id, leaf)\n\t\t}\n\t}\n}\n\n/** True iff every member id belonged to the same node of the previous partition. */\nfunction wasMergedTogether(\n\tmembers: readonly string[],\n\townerByMember: ReadonlyMap<string, string>\n): boolean {\n\tconst owner = ownerByMember.get(members[0])\n\tif (owner === undefined) return false\n\tfor (let i = 1; i < members.length; i++) {\n\t\tif (ownerByMember.get(members[i]) !== owner) return false\n\t}\n\treturn true\n}\n\nfunction seedCount(events: readonly MergeEvent[], zoom: number): number {\n\tlet lo = 0\n\tlet hi = events.length\n\twhile (lo < hi) {\n\t\tconst mid = (lo + hi) >> 1\n\t\tif (zoom <= seedThreshold(events[mid])) {\n\t\t\tlo = mid + 1\n\t\t} else {\n\t\t\thi = mid\n\t\t}\n\t}\n\treturn lo\n}\n\nfunction seedThreshold(event: MergeEvent): number {\n\treturn Math.sqrt(event.zMerge * event.zSplit)\n}\n\nfunction applyEvent(visible: Map<string, ClusterNode>, event: MergeEvent) {\n\tfor (const child of event.children) {\n\t\tvisible.delete(child.id)\n\t}\n\tvisible.set(event.result.id, event.result)\n}\n\nfunction unapplyEvent(visible: Map<string, ClusterNode>, event: MergeEvent) {\n\tvisible.delete(event.result.id)\n\tfor (const child of event.children) {\n\t\tvisible.set(child.id, child)\n\t}\n}\n\nfunction validateZoom(zoom: number) {\n\tif (!Number.isFinite(zoom) || zoom <= 0) {\n\t\tthrow new Error('zoom must be finite and greater than 0')\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var schedule_exports = {};
20
+ __export(schedule_exports, {
21
+ contract: () => contract,
22
+ finalize: () => finalize
23
+ });
24
+ module.exports = __toCommonJS(schedule_exports);
25
+ function contract(raw, eps) {
26
+ if (!Number.isFinite(eps) || eps < 0) {
27
+ throw new Error("eps must be finite and greater than or equal to 0");
28
+ }
29
+ const out = [];
30
+ let i = 0;
31
+ while (i < raw.length) {
32
+ const anchor = raw[i].z;
33
+ let j = i;
34
+ while (j + 1 < raw.length && raw[j + 1].z >= anchor / (1 + eps)) {
35
+ j++;
36
+ }
37
+ const chains = contractWindow(raw.slice(i, j + 1), anchor);
38
+ out.push(...chains);
39
+ i = j + 1;
40
+ }
41
+ return out;
42
+ }
43
+ function finalize(events, opts) {
44
+ validateFinalizeOptions(opts);
45
+ const r = opts.Tu / opts.Tc;
46
+ const zMergeCap = opts.maxSplitZoom / r;
47
+ const out = [];
48
+ for (const event of events) {
49
+ const zMerge = Math.min(event.zMerge, zMergeCap);
50
+ if (zMerge < opts.minZoom) break;
51
+ let zSplit = zMerge * r;
52
+ if (zMerge < opts.maxZoom) {
53
+ zSplit = Math.min(zSplit, opts.maxZoom);
54
+ }
55
+ out.push({
56
+ zMerge,
57
+ zSplit,
58
+ children: event.children,
59
+ result: event.result
60
+ });
61
+ }
62
+ return out;
63
+ }
64
+ function contractWindow(events, zMerge) {
65
+ const uf = new ComponentUnionFind(events.length);
66
+ const resultToIndex = /* @__PURE__ */ new Map();
67
+ for (let i = 0; i < events.length; i++) {
68
+ resultToIndex.set(events[i].result.id, i);
69
+ }
70
+ for (let i = 0; i < events.length; i++) {
71
+ for (const child of events[i].children) {
72
+ const producer = resultToIndex.get(child.id);
73
+ if (producer !== void 0) {
74
+ uf.union(i, producer);
75
+ }
76
+ }
77
+ }
78
+ const byRoot = /* @__PURE__ */ new Map();
79
+ for (let i = 0; i < events.length; i++) {
80
+ const root = uf.find(i);
81
+ const list = byRoot.get(root);
82
+ if (list) {
83
+ list.push(i);
84
+ } else {
85
+ byRoot.set(root, [i]);
86
+ }
87
+ }
88
+ return Array.from(byRoot.values()).map((indices) => contractChain(events, indices, zMerge)).sort((a, b) => compareNodesByMinMember(a.result, b.result));
89
+ }
90
+ function contractChain(events, indices, zMerge) {
91
+ const produced = /* @__PURE__ */ new Set();
92
+ const consumedProduced = /* @__PURE__ */ new Set();
93
+ for (const index of indices) {
94
+ produced.add(events[index].result.id);
95
+ }
96
+ for (const index of indices) {
97
+ for (const child of events[index].children) {
98
+ if (produced.has(child.id)) consumedProduced.add(child.id);
99
+ }
100
+ }
101
+ const childrenById = /* @__PURE__ */ new Map();
102
+ for (const index of indices) {
103
+ for (const child of events[index].children) {
104
+ if (!produced.has(child.id)) childrenById.set(child.id, child);
105
+ }
106
+ }
107
+ let result;
108
+ for (const index of indices) {
109
+ const candidate = events[index].result;
110
+ if (!consumedProduced.has(candidate.id)) {
111
+ if (!result || compareNodesByMinMember(candidate, result) < 0) result = candidate;
112
+ }
113
+ }
114
+ return {
115
+ zMerge,
116
+ children: Array.from(childrenById.values()).sort(compareNodesByMinMember),
117
+ result
118
+ };
119
+ }
120
+ function validateFinalizeOptions(opts) {
121
+ if (!Number.isFinite(opts.maxSplitZoom) || opts.maxSplitZoom <= 0) {
122
+ throw new Error("maxSplitZoom must be finite and greater than 0");
123
+ }
124
+ if (!Number.isFinite(opts.Tc) || opts.Tc <= 0) {
125
+ throw new Error("Tc must be finite and greater than 0");
126
+ }
127
+ if (!Number.isFinite(opts.Tu) || opts.Tu <= opts.Tc) {
128
+ throw new Error("Tu must be finite and greater than Tc");
129
+ }
130
+ if (!Number.isFinite(opts.minZoom) || opts.minZoom <= 0) {
131
+ throw new Error("minZoom must be finite and greater than 0");
132
+ }
133
+ if (!Number.isFinite(opts.maxZoom) || opts.maxZoom <= opts.minZoom) {
134
+ throw new Error("maxZoom must be finite and greater than minZoom");
135
+ }
136
+ }
137
+ function compareNodesByMinMember(a, b) {
138
+ const aMin = a.members[0];
139
+ const bMin = b.members[0];
140
+ if (aMin < bMin) return -1;
141
+ if (aMin > bMin) return 1;
142
+ return 0;
143
+ }
144
+ class ComponentUnionFind {
145
+ parent;
146
+ constructor(n) {
147
+ this.parent = new Int32Array(n);
148
+ for (let i = 0; i < n; i++) {
149
+ this.parent[i] = i;
150
+ }
151
+ }
152
+ find(index) {
153
+ let root = index;
154
+ while (this.parent[root] !== root) {
155
+ root = this.parent[root];
156
+ }
157
+ while (this.parent[index] !== index) {
158
+ const next = this.parent[index];
159
+ this.parent[index] = root;
160
+ index = next;
161
+ }
162
+ return root;
163
+ }
164
+ union(a, b) {
165
+ const rootA = this.find(a);
166
+ const rootB = this.find(b);
167
+ if (rootA !== rootB) this.parent[rootB] = rootA;
168
+ }
169
+ }
170
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/clustering/schedule.ts"],
4
+ "sourcesContent": ["import type { ClusterNode, ContractedEvent, MergeEvent, RawMergeEvent } from './types'\n\nexport function contract(raw: readonly RawMergeEvent[], eps: number): ContractedEvent[] {\n\tif (!Number.isFinite(eps) || eps < 0) {\n\t\tthrow new Error('eps must be finite and greater than or equal to 0')\n\t}\n\n\tconst out: ContractedEvent[] = []\n\tlet i = 0\n\twhile (i < raw.length) {\n\t\tconst anchor = raw[i].z\n\t\tlet j = i\n\t\twhile (j + 1 < raw.length && raw[j + 1].z >= anchor / (1 + eps)) {\n\t\t\tj++\n\t\t}\n\n\t\tconst chains = contractWindow(raw.slice(i, j + 1), anchor)\n\t\tout.push(...chains)\n\t\ti = j + 1\n\t}\n\n\treturn out\n}\n\nexport function finalize(\n\tevents: readonly ContractedEvent[],\n\topts: { Tc: number; Tu: number; minZoom: number; maxZoom: number; maxSplitZoom: number }\n): MergeEvent[] {\n\tvalidateFinalizeOptions(opts)\n\n\tconst r = opts.Tu / opts.Tc\n\t// Every cluster must have split by maxSplitZoom, however close (or coincident) its members.\n\t// Capping zMerge at maxSplitZoom / r keeps the whole band below the cap, preserving\n\t// zSplit > zMerge and the table's sort order (min with a constant is order-preserving).\n\tconst zMergeCap = opts.maxSplitZoom / r\n\tconst out: MergeEvent[] = []\n\tfor (const event of events) {\n\t\tconst zMerge = Math.min(event.zMerge, zMergeCap)\n\t\tif (zMerge < opts.minZoom) break\n\t\tlet zSplit = zMerge * r\n\t\tif (zMerge < opts.maxZoom) {\n\t\t\tzSplit = Math.min(zSplit, opts.maxZoom)\n\t\t}\n\t\tout.push({\n\t\t\tzMerge,\n\t\t\tzSplit,\n\t\t\tchildren: event.children,\n\t\t\tresult: event.result,\n\t\t})\n\t}\n\treturn out\n}\n\nfunction contractWindow(events: readonly RawMergeEvent[], zMerge: number): ContractedEvent[] {\n\tconst uf = new ComponentUnionFind(events.length)\n\tconst resultToIndex = new Map<string, number>()\n\tfor (let i = 0; i < events.length; i++) {\n\t\tresultToIndex.set(events[i].result.id, i)\n\t}\n\n\tfor (let i = 0; i < events.length; i++) {\n\t\tfor (const child of events[i].children) {\n\t\t\tconst producer = resultToIndex.get(child.id)\n\t\t\tif (producer !== undefined) {\n\t\t\t\tuf.union(i, producer)\n\t\t\t}\n\t\t}\n\t}\n\n\tconst byRoot = new Map<number, number[]>()\n\tfor (let i = 0; i < events.length; i++) {\n\t\tconst root = uf.find(i)\n\t\tconst list = byRoot.get(root)\n\t\tif (list) {\n\t\t\tlist.push(i)\n\t\t} else {\n\t\t\tbyRoot.set(root, [i])\n\t\t}\n\t}\n\n\treturn Array.from(byRoot.values())\n\t\t.map((indices) => contractChain(events, indices, zMerge))\n\t\t.sort((a, b) => compareNodesByMinMember(a.result, b.result))\n}\n\nfunction contractChain(\n\tevents: readonly RawMergeEvent[],\n\tindices: readonly number[],\n\tzMerge: number\n): ContractedEvent {\n\tconst produced = new Set<string>()\n\tconst consumedProduced = new Set<string>()\n\tfor (const index of indices) {\n\t\tproduced.add(events[index].result.id)\n\t}\n\tfor (const index of indices) {\n\t\tfor (const child of events[index].children) {\n\t\t\tif (produced.has(child.id)) consumedProduced.add(child.id)\n\t\t}\n\t}\n\n\tconst childrenById = new Map<string, ClusterNode>()\n\tfor (const index of indices) {\n\t\tfor (const child of events[index].children) {\n\t\t\tif (!produced.has(child.id)) childrenById.set(child.id, child)\n\t\t}\n\t}\n\n\tlet result: ClusterNode | undefined\n\tfor (const index of indices) {\n\t\tconst candidate = events[index].result\n\t\tif (!consumedProduced.has(candidate.id)) {\n\t\t\tif (!result || compareNodesByMinMember(candidate, result) < 0) result = candidate\n\t\t}\n\t}\n\n\treturn {\n\t\tzMerge,\n\t\tchildren: Array.from(childrenById.values()).sort(compareNodesByMinMember),\n\t\tresult: result!,\n\t}\n}\n\nfunction validateFinalizeOptions(opts: {\n\tTc: number\n\tTu: number\n\tminZoom: number\n\tmaxZoom: number\n\tmaxSplitZoom: number\n}) {\n\tif (!Number.isFinite(opts.maxSplitZoom) || opts.maxSplitZoom <= 0) {\n\t\tthrow new Error('maxSplitZoom must be finite and greater than 0')\n\t}\n\tif (!Number.isFinite(opts.Tc) || opts.Tc <= 0) {\n\t\tthrow new Error('Tc must be finite and greater than 0')\n\t}\n\tif (!Number.isFinite(opts.Tu) || opts.Tu <= opts.Tc) {\n\t\tthrow new Error('Tu must be finite and greater than Tc')\n\t}\n\tif (!Number.isFinite(opts.minZoom) || opts.minZoom <= 0) {\n\t\tthrow new Error('minZoom must be finite and greater than 0')\n\t}\n\tif (!Number.isFinite(opts.maxZoom) || opts.maxZoom <= opts.minZoom) {\n\t\tthrow new Error('maxZoom must be finite and greater than minZoom')\n\t}\n}\n\nfunction compareNodesByMinMember(a: ClusterNode, b: ClusterNode): number {\n\tconst aMin = a.members[0]\n\tconst bMin = b.members[0]\n\tif (aMin < bMin) return -1\n\tif (aMin > bMin) return 1\n\treturn 0\n}\n\nclass ComponentUnionFind {\n\tprivate readonly parent: Int32Array\n\n\tconstructor(n: number) {\n\t\tthis.parent = new Int32Array(n)\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tthis.parent[i] = i\n\t\t}\n\t}\n\n\tfind(index: number): number {\n\t\tlet root = index\n\t\twhile (this.parent[root] !== root) {\n\t\t\troot = this.parent[root]\n\t\t}\n\t\twhile (this.parent[index] !== index) {\n\t\t\tconst next = this.parent[index]\n\t\t\tthis.parent[index] = root\n\t\t\tindex = next\n\t\t}\n\t\treturn root\n\t}\n\n\tunion(a: number, b: number) {\n\t\tconst rootA = this.find(a)\n\t\tconst rootB = this.find(b)\n\t\tif (rootA !== rootB) this.parent[rootB] = rootA\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }