@memberjunction/ng-clustering 5.43.0 → 5.44.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.
- package/dist/lib/cluster-config-panel.component.d.ts +2 -2
- package/dist/lib/cluster-config-panel.component.d.ts.map +1 -1
- package/dist/lib/cluster-config-panel.component.dom.test.d.ts +2 -0
- package/dist/lib/cluster-config-panel.component.dom.test.d.ts.map +1 -0
- package/dist/lib/cluster-config-panel.component.dom.test.js +147 -0
- package/dist/lib/cluster-config-panel.component.dom.test.js.map +1 -0
- package/dist/lib/cluster-config-panel.component.js +52 -51
- package/dist/lib/cluster-config-panel.component.js.map +1 -1
- package/dist/lib/cluster-scatter.component.dom.test.d.ts +2 -0
- package/dist/lib/cluster-scatter.component.dom.test.d.ts.map +1 -0
- package/dist/lib/cluster-scatter.component.dom.test.js +102 -0
- package/dist/lib/cluster-scatter.component.dom.test.js.map +1 -0
- package/dist/lib/cluster-scatter.component.js +89 -95
- package/dist/lib/cluster-scatter.component.js.map +1 -1
- package/dist/lib/clustering.module.d.ts +2 -1
- package/dist/lib/clustering.module.d.ts.map +1 -1
- package/dist/lib/clustering.module.js +9 -2
- package/dist/lib/clustering.module.js.map +1 -1
- package/dist/lib/view-type/cluster-view-prop-sheet.component.dom.test.d.ts +2 -0
- package/dist/lib/view-type/cluster-view-prop-sheet.component.dom.test.d.ts.map +1 -0
- package/dist/lib/view-type/cluster-view-prop-sheet.component.dom.test.js +64 -0
- package/dist/lib/view-type/cluster-view-prop-sheet.component.dom.test.js.map +1 -0
- package/package.json +12 -10
|
@@ -32,6 +32,7 @@ import { CLUSTER_COLORS, } from './clustering.types';
|
|
|
32
32
|
import * as i0 from "@angular/core";
|
|
33
33
|
import * as i1 from "@angular/forms";
|
|
34
34
|
import * as i2 from "@memberjunction/ng-entity-card";
|
|
35
|
+
import * as i3 from "@memberjunction/ng-ui-components";
|
|
35
36
|
const _c0 = ["svgElement"];
|
|
36
37
|
const _forTrack0 = ($index, $item) => $item.ClusterId;
|
|
37
38
|
const _forTrack1 = ($index, $item) => $item.Name;
|
|
@@ -43,19 +44,12 @@ function ClusterScatterComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
|
43
44
|
i0.ɵɵelementEnd()()();
|
|
44
45
|
} }
|
|
45
46
|
function ClusterScatterComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
46
|
-
i0.ɵɵ
|
|
47
|
-
i0.ɵɵelement(1, "i", 11);
|
|
48
|
-
i0.ɵɵelementStart(2, "p");
|
|
49
|
-
i0.ɵɵtext(3, "No data to display");
|
|
50
|
-
i0.ɵɵelementEnd();
|
|
51
|
-
i0.ɵɵelementStart(4, "p", 12);
|
|
52
|
-
i0.ɵɵtext(5, "Configure and run clustering to see results");
|
|
53
|
-
i0.ɵɵelementEnd()();
|
|
47
|
+
i0.ɵɵelement(0, "mj-empty-state", 3);
|
|
54
48
|
} }
|
|
55
49
|
function ClusterScatterComponent_Conditional_3_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
56
50
|
i0.ɵɵnamespaceSVG();
|
|
57
|
-
i0.ɵɵelementStart(0, "radialGradient",
|
|
58
|
-
i0.ɵɵelement(1, "stop",
|
|
51
|
+
i0.ɵɵelementStart(0, "radialGradient", 12);
|
|
52
|
+
i0.ɵɵelement(1, "stop", 15)(2, "stop", 16);
|
|
59
53
|
i0.ɵɵelementEnd();
|
|
60
54
|
} if (rf & 2) {
|
|
61
55
|
const centroid_r3 = ctx.$implicit;
|
|
@@ -88,7 +82,7 @@ function ClusterScatterComponent_Conditional_3_Conditional_10_For_1_Template(rf,
|
|
|
88
82
|
} }
|
|
89
83
|
function ClusterScatterComponent_Conditional_3_Conditional_10_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
90
84
|
i0.ɵɵnamespaceSVG();
|
|
91
|
-
i0.ɵɵelementStart(0, "text",
|
|
85
|
+
i0.ɵɵelementStart(0, "text", 17);
|
|
92
86
|
i0.ɵɵtext(1);
|
|
93
87
|
i0.ɵɵelementEnd();
|
|
94
88
|
} if (rf & 2) {
|
|
@@ -98,7 +92,7 @@ function ClusterScatterComponent_Conditional_3_Conditional_10_For_3_Conditional_
|
|
|
98
92
|
i0.ɵɵtextInterpolate(ctx);
|
|
99
93
|
} }
|
|
100
94
|
function ClusterScatterComponent_Conditional_3_Conditional_10_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
101
|
-
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_Conditional_10_For_3_Conditional_0_Template, 2, 4, ":svg:text",
|
|
95
|
+
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_Conditional_10_For_3_Conditional_0_Template, 2, 4, ":svg:text", 17);
|
|
102
96
|
} if (rf & 2) {
|
|
103
97
|
let tmp_13_0;
|
|
104
98
|
const centroid_r7 = ctx.$implicit;
|
|
@@ -117,7 +111,7 @@ function ClusterScatterComponent_Conditional_3_Conditional_10_Template(rf, ctx)
|
|
|
117
111
|
function ClusterScatterComponent_Conditional_3_For_12_Template(rf, ctx) { if (rf & 1) {
|
|
118
112
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
119
113
|
i0.ɵɵnamespaceSVG();
|
|
120
|
-
i0.ɵɵelementStart(0, "circle",
|
|
114
|
+
i0.ɵɵelementStart(0, "circle", 18);
|
|
121
115
|
i0.ɵɵlistener("mouseenter", function ClusterScatterComponent_Conditional_3_For_12_Template_circle_mouseenter_0_listener($event) { const point_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPointMouseEnter(point_r9, $event)); })("mouseleave", function ClusterScatterComponent_Conditional_3_For_12_Template_circle_mouseleave_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPointMouseLeave()); })("click", function ClusterScatterComponent_Conditional_3_For_12_Template_circle_click_0_listener($event) { const point_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.OnPointClick(point_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
122
116
|
i0.ɵɵelementEnd();
|
|
123
117
|
} if (rf & 2) {
|
|
@@ -127,7 +121,7 @@ function ClusterScatterComponent_Conditional_3_For_12_Template(rf, ctx) { if (rf
|
|
|
127
121
|
} }
|
|
128
122
|
function ClusterScatterComponent_Conditional_3_Conditional_13_For_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
129
123
|
i0.ɵɵnamespaceSVG();
|
|
130
|
-
i0.ɵɵelementStart(0, "text",
|
|
124
|
+
i0.ɵɵelementStart(0, "text", 19);
|
|
131
125
|
i0.ɵɵtext(1);
|
|
132
126
|
i0.ɵɵelementEnd();
|
|
133
127
|
} if (rf & 2) {
|
|
@@ -137,7 +131,7 @@ function ClusterScatterComponent_Conditional_3_Conditional_13_For_1_Conditional_
|
|
|
137
131
|
i0.ɵɵtextInterpolate(ctx);
|
|
138
132
|
} }
|
|
139
133
|
function ClusterScatterComponent_Conditional_3_Conditional_13_For_1_Template(rf, ctx) { if (rf & 1) {
|
|
140
|
-
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_Conditional_13_For_1_Conditional_0_Template, 2, 4, ":svg:text",
|
|
134
|
+
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_Conditional_13_For_1_Conditional_0_Template, 2, 4, ":svg:text", 19);
|
|
141
135
|
} if (rf & 2) {
|
|
142
136
|
let tmp_13_0;
|
|
143
137
|
const lbl_r10 = ctx.$implicit;
|
|
@@ -152,14 +146,14 @@ function ClusterScatterComponent_Conditional_3_Conditional_13_Template(rf, ctx)
|
|
|
152
146
|
} }
|
|
153
147
|
function ClusterScatterComponent_Conditional_3_For_15_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
154
148
|
i0.ɵɵnamespaceSVG();
|
|
155
|
-
i0.ɵɵelement(0, "circle",
|
|
149
|
+
i0.ɵɵelement(0, "circle", 20);
|
|
156
150
|
} if (rf & 2) {
|
|
157
151
|
const point_r11 = i0.ɵɵnextContext().$implicit;
|
|
158
152
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
159
153
|
i0.ɵɵattribute("cx", ctx_r1.PX(point_r11))("cy", ctx_r1.PY(point_r11))("r", ctx_r1.HighlightRadius + 2)("stroke", ctx_r1.GetPointColor(point_r11));
|
|
160
154
|
} }
|
|
161
155
|
function ClusterScatterComponent_Conditional_3_For_15_Template(rf, ctx) { if (rf & 1) {
|
|
162
|
-
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_For_15_Conditional_0_Template, 1, 4, ":svg:circle",
|
|
156
|
+
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_For_15_Conditional_0_Template, 1, 4, ":svg:circle", 20);
|
|
163
157
|
} if (rf & 2) {
|
|
164
158
|
const point_r11 = ctx.$implicit;
|
|
165
159
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -167,14 +161,14 @@ function ClusterScatterComponent_Conditional_3_For_15_Template(rf, ctx) { if (rf
|
|
|
167
161
|
} }
|
|
168
162
|
function ClusterScatterComponent_Conditional_3_Conditional_16_For_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
169
163
|
i0.ɵɵnamespaceSVG();
|
|
170
|
-
i0.ɵɵelement(0, "circle",
|
|
164
|
+
i0.ɵɵelement(0, "circle", 21);
|
|
171
165
|
} if (rf & 2) {
|
|
172
166
|
const point_r12 = i0.ɵɵnextContext().$implicit;
|
|
173
167
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
174
168
|
i0.ɵɵattribute("cx", ctx_r1.PX(point_r12))("cy", ctx_r1.PY(point_r12))("r", ctx_r1.HighlightRadius + 4)("stroke", ctx_r1.GetPointColor(point_r12));
|
|
175
169
|
} }
|
|
176
170
|
function ClusterScatterComponent_Conditional_3_Conditional_16_For_1_Template(rf, ctx) { if (rf & 1) {
|
|
177
|
-
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_Conditional_16_For_1_Conditional_0_Template, 1, 4, ":svg:circle",
|
|
171
|
+
i0.ɵɵconditionalCreate(0, ClusterScatterComponent_Conditional_3_Conditional_16_For_1_Conditional_0_Template, 1, 4, ":svg:circle", 21);
|
|
178
172
|
} if (rf & 2) {
|
|
179
173
|
const point_r12 = ctx.$implicit;
|
|
180
174
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -189,17 +183,17 @@ function ClusterScatterComponent_Conditional_3_Conditional_16_Template(rf, ctx)
|
|
|
189
183
|
function ClusterScatterComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
190
184
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
191
185
|
i0.ɵɵnamespaceSVG();
|
|
192
|
-
i0.ɵɵelementStart(0, "svg",
|
|
186
|
+
i0.ɵɵelementStart(0, "svg", 11, 0);
|
|
193
187
|
i0.ɵɵlistener("wheel", function ClusterScatterComponent_Conditional_3_Template_svg_wheel_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnWheel($event)); })("mousedown", function ClusterScatterComponent_Conditional_3_Template_svg_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnMouseDown($event)); });
|
|
194
188
|
i0.ɵɵelementStart(2, "defs");
|
|
195
|
-
i0.ɵɵrepeaterCreate(3, ClusterScatterComponent_Conditional_3_For_4_Template, 3, 3, ":svg:radialGradient",
|
|
189
|
+
i0.ɵɵrepeaterCreate(3, ClusterScatterComponent_Conditional_3_For_4_Template, 3, 3, ":svg:radialGradient", 12, i0.ɵɵcomponentInstance().TrackCentroidBy, true);
|
|
196
190
|
i0.ɵɵelementEnd();
|
|
197
|
-
i0.ɵɵelementStart(5, "g",
|
|
191
|
+
i0.ɵɵelementStart(5, "g", 13);
|
|
198
192
|
i0.ɵɵrepeaterCreate(6, ClusterScatterComponent_Conditional_3_For_7_Template, 1, 4, ":svg:line", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
199
193
|
i0.ɵɵrepeaterCreate(8, ClusterScatterComponent_Conditional_3_For_9_Template, 1, 4, ":svg:line", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
200
194
|
i0.ɵɵelementEnd();
|
|
201
195
|
i0.ɵɵconditionalCreate(10, ClusterScatterComponent_Conditional_3_Conditional_10_Template, 4, 0);
|
|
202
|
-
i0.ɵɵrepeaterCreate(11, ClusterScatterComponent_Conditional_3_For_12_Template, 1, 5, ":svg:circle",
|
|
196
|
+
i0.ɵɵrepeaterCreate(11, ClusterScatterComponent_Conditional_3_For_12_Template, 1, 5, ":svg:circle", 14, i0.ɵɵcomponentInstance().TrackPointBy, true);
|
|
203
197
|
i0.ɵɵconditionalCreate(13, ClusterScatterComponent_Conditional_3_Conditional_13_Template, 2, 0);
|
|
204
198
|
i0.ɵɵrepeaterCreate(14, ClusterScatterComponent_Conditional_3_For_15_Template, 1, 1, null, null, i0.ɵɵcomponentInstance().TrackPointBy, true);
|
|
205
199
|
i0.ɵɵconditionalCreate(16, ClusterScatterComponent_Conditional_3_Conditional_16_Template, 2, 0);
|
|
@@ -228,22 +222,22 @@ function ClusterScatterComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
|
228
222
|
function ClusterScatterComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
229
223
|
const _r13 = i0.ɵɵgetCurrentView();
|
|
230
224
|
i0.ɵɵelementStart(0, "div", 5);
|
|
231
|
-
i0.ɵɵelement(1, "i",
|
|
225
|
+
i0.ɵɵelement(1, "i", 22);
|
|
232
226
|
i0.ɵɵelementStart(2, "span");
|
|
233
227
|
i0.ɵɵtext(3, "3D \u00B7 drag to rotate");
|
|
234
228
|
i0.ɵɵelementEnd();
|
|
235
|
-
i0.ɵɵelementStart(4, "button",
|
|
229
|
+
i0.ɵɵelementStart(4, "button", 23);
|
|
236
230
|
i0.ɵɵlistener("click", function ClusterScatterComponent_Conditional_4_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ResetRotation()); });
|
|
237
|
-
i0.ɵɵelement(5, "i",
|
|
231
|
+
i0.ɵɵelement(5, "i", 24);
|
|
238
232
|
i0.ɵɵelementEnd()();
|
|
239
233
|
} }
|
|
240
234
|
function ClusterScatterComponent_Conditional_5_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
241
|
-
i0.ɵɵelementStart(0, "div",
|
|
242
|
-
i0.ɵɵelement(1, "div",
|
|
243
|
-
i0.ɵɵelementStart(2, "span",
|
|
235
|
+
i0.ɵɵelementStart(0, "div", 26);
|
|
236
|
+
i0.ɵɵelement(1, "div", 27);
|
|
237
|
+
i0.ɵɵelementStart(2, "span", 28);
|
|
244
238
|
i0.ɵɵtext(3);
|
|
245
239
|
i0.ɵɵelementEnd();
|
|
246
|
-
i0.ɵɵelementStart(4, "span",
|
|
240
|
+
i0.ɵɵelementStart(4, "span", 29);
|
|
247
241
|
i0.ɵɵtext(5);
|
|
248
242
|
i0.ɵɵelementEnd()();
|
|
249
243
|
} if (rf & 2) {
|
|
@@ -256,10 +250,10 @@ function ClusterScatterComponent_Conditional_5_For_4_Template(rf, ctx) { if (rf
|
|
|
256
250
|
i0.ɵɵtextInterpolate(ent_r14.Count);
|
|
257
251
|
} }
|
|
258
252
|
function ClusterScatterComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
259
|
-
i0.ɵɵelementStart(0, "div", 6)(1, "div",
|
|
253
|
+
i0.ɵɵelementStart(0, "div", 6)(1, "div", 25);
|
|
260
254
|
i0.ɵɵtext(2, "Entities");
|
|
261
255
|
i0.ɵɵelementEnd();
|
|
262
|
-
i0.ɵɵrepeaterCreate(3, ClusterScatterComponent_Conditional_5_For_4_Template, 6, 4, "div",
|
|
256
|
+
i0.ɵɵrepeaterCreate(3, ClusterScatterComponent_Conditional_5_For_4_Template, 6, 4, "div", 26, _forTrack1);
|
|
263
257
|
i0.ɵɵelementEnd();
|
|
264
258
|
} if (rf & 2) {
|
|
265
259
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -268,7 +262,7 @@ function ClusterScatterComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
|
268
262
|
} }
|
|
269
263
|
function ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
270
264
|
const _r17 = i0.ɵɵgetCurrentView();
|
|
271
|
-
i0.ɵɵelementStart(0, "input",
|
|
265
|
+
i0.ɵɵelementStart(0, "input", 32);
|
|
272
266
|
i0.ɵɵtwoWayListener("ngModelChange", function ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template_input_ngModelChange_0_listener($event) { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.EditingLabelDraft, $event) || (ctx_r1.EditingLabelDraft = $event); return i0.ɵɵresetView($event); });
|
|
273
267
|
i0.ɵɵlistener("keydown", function ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template_input_keydown_0_listener($event) { i0.ɵɵrestoreView(_r17); const cluster_r16 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnLabelEditKeydown($event, cluster_r16)); })("blur", function ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template_input_blur_0_listener() { i0.ɵɵrestoreView(_r17); const cluster_r16 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.CommitLabelEdit(cluster_r16)); })("click", function ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template_input_click_0_listener($event) { i0.ɵɵrestoreView(_r17); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
274
268
|
i0.ɵɵelementEnd();
|
|
@@ -278,12 +272,12 @@ function ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template(rf,
|
|
|
278
272
|
} }
|
|
279
273
|
function ClusterScatterComponent_Conditional_6_For_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
280
274
|
const _r18 = i0.ɵɵgetCurrentView();
|
|
281
|
-
i0.ɵɵelementStart(0, "span",
|
|
275
|
+
i0.ɵɵelementStart(0, "span", 28);
|
|
282
276
|
i0.ɵɵtext(1);
|
|
283
277
|
i0.ɵɵelementEnd();
|
|
284
|
-
i0.ɵɵelementStart(2, "button",
|
|
278
|
+
i0.ɵɵelementStart(2, "button", 33);
|
|
285
279
|
i0.ɵɵlistener("click", function ClusterScatterComponent_Conditional_6_For_4_Conditional_3_Template_button_click_2_listener($event) { i0.ɵɵrestoreView(_r18); const cluster_r16 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.StartLabelEdit(cluster_r16, $event)); });
|
|
286
|
-
i0.ɵɵelement(3, "i",
|
|
280
|
+
i0.ɵɵelement(3, "i", 34);
|
|
287
281
|
i0.ɵɵelementEnd();
|
|
288
282
|
} if (rf & 2) {
|
|
289
283
|
const cluster_r16 = i0.ɵɵnextContext().$implicit;
|
|
@@ -292,11 +286,11 @@ function ClusterScatterComponent_Conditional_6_For_4_Conditional_3_Template(rf,
|
|
|
292
286
|
} }
|
|
293
287
|
function ClusterScatterComponent_Conditional_6_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
294
288
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
295
|
-
i0.ɵɵelementStart(0, "div",
|
|
289
|
+
i0.ɵɵelementStart(0, "div", 30);
|
|
296
290
|
i0.ɵɵlistener("click", function ClusterScatterComponent_Conditional_6_For_4_Template_div_click_0_listener() { const cluster_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnClusterLegendClick(cluster_r16)); });
|
|
297
|
-
i0.ɵɵelement(1, "div",
|
|
298
|
-
i0.ɵɵconditionalCreate(2, ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template, 1, 1, "input",
|
|
299
|
-
i0.ɵɵelementStart(4, "span",
|
|
291
|
+
i0.ɵɵelement(1, "div", 27);
|
|
292
|
+
i0.ɵɵconditionalCreate(2, ClusterScatterComponent_Conditional_6_For_4_Conditional_2_Template, 1, 1, "input", 31)(3, ClusterScatterComponent_Conditional_6_For_4_Conditional_3_Template, 4, 1);
|
|
293
|
+
i0.ɵɵelementStart(4, "span", 29);
|
|
300
294
|
i0.ɵɵtext(5);
|
|
301
295
|
i0.ɵɵelementEnd()();
|
|
302
296
|
} if (rf & 2) {
|
|
@@ -310,10 +304,10 @@ function ClusterScatterComponent_Conditional_6_For_4_Template(rf, ctx) { if (rf
|
|
|
310
304
|
i0.ɵɵtextInterpolate(cluster_r16.MemberCount);
|
|
311
305
|
} }
|
|
312
306
|
function ClusterScatterComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
313
|
-
i0.ɵɵelementStart(0, "div", 6)(1, "div",
|
|
307
|
+
i0.ɵɵelementStart(0, "div", 6)(1, "div", 25);
|
|
314
308
|
i0.ɵɵtext(2, "Clusters");
|
|
315
309
|
i0.ɵɵelementEnd();
|
|
316
|
-
i0.ɵɵrepeaterCreate(3, ClusterScatterComponent_Conditional_6_For_4_Template, 6, 4, "div",
|
|
310
|
+
i0.ɵɵrepeaterCreate(3, ClusterScatterComponent_Conditional_6_For_4_Template, 6, 4, "div", 26, i0.ɵɵcomponentInstance().TrackClusterBy, true);
|
|
317
311
|
i0.ɵɵelementEnd();
|
|
318
312
|
} if (rf & 2) {
|
|
319
313
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -321,14 +315,14 @@ function ClusterScatterComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
|
321
315
|
i0.ɵɵrepeater(ctx_r1.Clusters);
|
|
322
316
|
} }
|
|
323
317
|
function ClusterScatterComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
324
|
-
i0.ɵɵelementStart(0, "div",
|
|
325
|
-
i0.ɵɵelement(1, "mj-entity-card",
|
|
326
|
-
i0.ɵɵelementStart(2, "div",
|
|
327
|
-
i0.ɵɵelement(3, "i",
|
|
318
|
+
i0.ɵɵelementStart(0, "div", 35);
|
|
319
|
+
i0.ɵɵelement(1, "mj-entity-card", 36);
|
|
320
|
+
i0.ɵɵelementStart(2, "div", 37);
|
|
321
|
+
i0.ɵɵelement(3, "i", 38);
|
|
328
322
|
i0.ɵɵtext(4);
|
|
329
323
|
i0.ɵɵelementEnd();
|
|
330
|
-
i0.ɵɵelementStart(5, "div",
|
|
331
|
-
i0.ɵɵelement(6, "i",
|
|
324
|
+
i0.ɵɵelementStart(5, "div", 39);
|
|
325
|
+
i0.ɵɵelement(6, "i", 40);
|
|
332
326
|
i0.ɵɵtext(7, " Click to view details ");
|
|
333
327
|
i0.ɵɵelementEnd()();
|
|
334
328
|
} if (rf & 2) {
|
|
@@ -340,7 +334,7 @@ function ClusterScatterComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
|
340
334
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.GetClusterLabel(ctx_r1.HoveredPoint), " ");
|
|
341
335
|
} }
|
|
342
336
|
function ClusterScatterComponent_Conditional_9_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
343
|
-
i0.ɵɵelementStart(0, "div",
|
|
337
|
+
i0.ɵɵelementStart(0, "div", 43);
|
|
344
338
|
i0.ɵɵelement(1, "i");
|
|
345
339
|
i0.ɵɵelementEnd();
|
|
346
340
|
} if (rf & 2) {
|
|
@@ -349,7 +343,7 @@ function ClusterScatterComponent_Conditional_9_Conditional_2_Template(rf, ctx) {
|
|
|
349
343
|
i0.ɵɵclassMap(ctx_r1.SelectedPoint.Metadata["EntityIcon"]);
|
|
350
344
|
} }
|
|
351
345
|
function ClusterScatterComponent_Conditional_9_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
352
|
-
i0.ɵɵelementStart(0, "span",
|
|
346
|
+
i0.ɵɵelementStart(0, "span", 46);
|
|
353
347
|
i0.ɵɵtext(1);
|
|
354
348
|
i0.ɵɵelementEnd();
|
|
355
349
|
} if (rf & 2) {
|
|
@@ -357,32 +351,42 @@ function ClusterScatterComponent_Conditional_9_Conditional_6_Template(rf, ctx) {
|
|
|
357
351
|
i0.ɵɵadvance();
|
|
358
352
|
i0.ɵɵtextInterpolate(ctx_r1.SelectedPoint.Metadata["Entity"]);
|
|
359
353
|
} }
|
|
360
|
-
function
|
|
361
|
-
i0.ɵɵ
|
|
354
|
+
function ClusterScatterComponent_Conditional_9_ng_template_15_Template(rf, ctx) { if (rf & 1) {
|
|
355
|
+
i0.ɵɵtext(0, " Cluster Members ");
|
|
356
|
+
i0.ɵɵelementStart(1, "span", 58);
|
|
357
|
+
i0.ɵɵtext(2);
|
|
358
|
+
i0.ɵɵelementEnd();
|
|
359
|
+
} if (rf & 2) {
|
|
360
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
361
|
+
i0.ɵɵadvance(2);
|
|
362
|
+
i0.ɵɵtextInterpolate(ctx_r1.ClusterMembers.length);
|
|
363
|
+
} }
|
|
364
|
+
function ClusterScatterComponent_Conditional_9_ng_template_16_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
+
i0.ɵɵelement(0, "i", 64);
|
|
362
366
|
} if (rf & 2) {
|
|
363
367
|
const member_r21 = i0.ɵɵnextContext().$implicit;
|
|
364
368
|
i0.ɵɵclassMap(member_r21.Metadata["EntityIcon"]);
|
|
365
369
|
} }
|
|
366
|
-
function
|
|
370
|
+
function ClusterScatterComponent_Conditional_9_ng_template_16_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
367
371
|
const _r20 = i0.ɵɵgetCurrentView();
|
|
368
|
-
i0.ɵɵelementStart(0, "div",
|
|
369
|
-
i0.ɵɵlistener("click", function
|
|
370
|
-
i0.ɵɵconditionalCreate(1,
|
|
371
|
-
i0.ɵɵelementStart(2, "span",
|
|
372
|
+
i0.ɵɵelementStart(0, "div", 61);
|
|
373
|
+
i0.ɵɵlistener("click", function ClusterScatterComponent_Conditional_9_ng_template_16_For_2_Template_div_click_0_listener() { const member_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnClusterMemberClick(member_r21)); });
|
|
374
|
+
i0.ɵɵconditionalCreate(1, ClusterScatterComponent_Conditional_9_ng_template_16_For_2_Conditional_1_Template, 1, 2, "i", 62);
|
|
375
|
+
i0.ɵɵelementStart(2, "span", 63);
|
|
372
376
|
i0.ɵɵtext(3);
|
|
373
377
|
i0.ɵɵelementEnd()();
|
|
374
378
|
} if (rf & 2) {
|
|
375
379
|
const member_r21 = ctx.$implicit;
|
|
376
380
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
377
|
-
i0.ɵɵclassProp("active", member_r21.VectorKey === ctx_r1.SelectedPoint.VectorKey);
|
|
381
|
+
i0.ɵɵclassProp("active", member_r21.VectorKey === (ctx_r1.SelectedPoint == null ? null : ctx_r1.SelectedPoint.VectorKey));
|
|
378
382
|
i0.ɵɵadvance();
|
|
379
383
|
i0.ɵɵconditional((member_r21.Metadata == null ? null : member_r21.Metadata["EntityIcon"]) ? 1 : -1);
|
|
380
384
|
i0.ɵɵadvance(2);
|
|
381
385
|
i0.ɵɵtextInterpolate(member_r21.Label);
|
|
382
386
|
} }
|
|
383
|
-
function
|
|
384
|
-
i0.ɵɵelementStart(0, "div",
|
|
385
|
-
i0.ɵɵrepeaterCreate(1,
|
|
387
|
+
function ClusterScatterComponent_Conditional_9_ng_template_16_Template(rf, ctx) { if (rf & 1) {
|
|
388
|
+
i0.ɵɵelementStart(0, "div", 59);
|
|
389
|
+
i0.ɵɵrepeaterCreate(1, ClusterScatterComponent_Conditional_9_ng_template_16_For_2_Template, 4, 4, "div", 60, i0.ɵɵcomponentInstance().TrackMemberBy, true);
|
|
386
390
|
i0.ɵɵelementEnd();
|
|
387
391
|
} if (rf & 2) {
|
|
388
392
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -391,37 +395,30 @@ function ClusterScatterComponent_Conditional_9_Conditional_20_Template(rf, ctx)
|
|
|
391
395
|
} }
|
|
392
396
|
function ClusterScatterComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
393
397
|
const _r19 = i0.ɵɵgetCurrentView();
|
|
394
|
-
i0.ɵɵelementStart(0, "div",
|
|
395
|
-
i0.ɵɵconditionalCreate(2, ClusterScatterComponent_Conditional_9_Conditional_2_Template, 2, 2, "div",
|
|
396
|
-
i0.ɵɵelementStart(3, "div",
|
|
398
|
+
i0.ɵɵelementStart(0, "div", 41)(1, "div", 42);
|
|
399
|
+
i0.ɵɵconditionalCreate(2, ClusterScatterComponent_Conditional_9_Conditional_2_Template, 2, 2, "div", 43);
|
|
400
|
+
i0.ɵɵelementStart(3, "div", 44)(4, "div", 45);
|
|
397
401
|
i0.ɵɵtext(5);
|
|
398
402
|
i0.ɵɵelementEnd();
|
|
399
|
-
i0.ɵɵconditionalCreate(6, ClusterScatterComponent_Conditional_9_Conditional_6_Template, 2, 1, "span",
|
|
403
|
+
i0.ɵɵconditionalCreate(6, ClusterScatterComponent_Conditional_9_Conditional_6_Template, 2, 1, "span", 46);
|
|
400
404
|
i0.ɵɵelementEnd()();
|
|
401
|
-
i0.ɵɵelementStart(7, "button",
|
|
405
|
+
i0.ɵɵelementStart(7, "button", 47);
|
|
402
406
|
i0.ɵɵlistener("click", function ClusterScatterComponent_Conditional_9_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseDetailPanel()); });
|
|
403
|
-
i0.ɵɵelement(8, "i",
|
|
407
|
+
i0.ɵɵelement(8, "i", 48);
|
|
404
408
|
i0.ɵɵelementEnd()();
|
|
405
|
-
i0.ɵɵelementStart(9, "div",
|
|
406
|
-
i0.ɵɵelement(10, "span",
|
|
409
|
+
i0.ɵɵelementStart(9, "div", 49);
|
|
410
|
+
i0.ɵɵelement(10, "span", 50);
|
|
407
411
|
i0.ɵɵtext(11);
|
|
408
412
|
i0.ɵɵelementEnd();
|
|
409
|
-
i0.ɵɵelement(12, "mj-entity-card",
|
|
410
|
-
i0.ɵɵelementStart(13, "div",
|
|
411
|
-
i0.ɵɵ
|
|
412
|
-
i0.ɵɵ
|
|
413
|
-
i0.ɵɵelementStart(16, "span");
|
|
414
|
-
i0.ɵɵtext(17, "Cluster Members");
|
|
415
|
-
i0.ɵɵelementEnd();
|
|
416
|
-
i0.ɵɵelementStart(18, "span", 57);
|
|
417
|
-
i0.ɵɵtext(19);
|
|
413
|
+
i0.ɵɵelement(12, "mj-entity-card", 51);
|
|
414
|
+
i0.ɵɵelementStart(13, "div", 52)(14, "mj-accordion-panel", 53);
|
|
415
|
+
i0.ɵɵtwoWayListener("ExpandedChange", function ClusterScatterComponent_Conditional_9_Template_mj_accordion_panel_ExpandedChange_14_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.ClusterMembersExpanded, $event) || (ctx_r1.ClusterMembersExpanded = $event); return i0.ɵɵresetView($event); });
|
|
416
|
+
i0.ɵɵtemplate(15, ClusterScatterComponent_Conditional_9_ng_template_15_Template, 3, 1, "ng-template", 54)(16, ClusterScatterComponent_Conditional_9_ng_template_16_Template, 3, 0, "ng-template", 55);
|
|
418
417
|
i0.ɵɵelementEnd()();
|
|
419
|
-
i0.ɵɵ
|
|
420
|
-
i0.ɵɵ
|
|
421
|
-
i0.ɵɵ
|
|
422
|
-
i0.ɵɵ
|
|
423
|
-
i0.ɵɵelement(23, "i", 42);
|
|
424
|
-
i0.ɵɵtext(24, " Open Record ");
|
|
418
|
+
i0.ɵɵelementStart(17, "div", 56)(18, "button", 57);
|
|
419
|
+
i0.ɵɵlistener("click", function ClusterScatterComponent_Conditional_9_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnOpenRecordClick()); });
|
|
420
|
+
i0.ɵɵelement(19, "i", 40);
|
|
421
|
+
i0.ɵɵtext(20, " Open Record ");
|
|
425
422
|
i0.ɵɵelementEnd()();
|
|
426
423
|
} if (rf & 2) {
|
|
427
424
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -437,12 +434,9 @@ function ClusterScatterComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
|
437
434
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.GetClusterLabel(ctx_r1.SelectedPoint), " ");
|
|
438
435
|
i0.ɵɵadvance();
|
|
439
436
|
i0.ɵɵproperty("EntityName", ctx_r1.EntityName)("Record", ctx_r1.SelectedPoint.Metadata);
|
|
440
|
-
i0.ɵɵadvance(
|
|
441
|
-
i0.ɵɵ
|
|
442
|
-
i0.ɵɵ
|
|
443
|
-
i0.ɵɵtextInterpolate(ctx_r1.ClusterMembers.length);
|
|
444
|
-
i0.ɵɵadvance();
|
|
445
|
-
i0.ɵɵconditional(ctx_r1.ClusterMembersExpanded ? 20 : -1);
|
|
437
|
+
i0.ɵɵadvance(2);
|
|
438
|
+
i0.ɵɵproperty("Fill", true)("FlushBody", true);
|
|
439
|
+
i0.ɵɵtwoWayProperty("Expanded", ctx_r1.ClusterMembersExpanded);
|
|
446
440
|
} }
|
|
447
441
|
export class ClusterScatterComponent {
|
|
448
442
|
constructor() {
|
|
@@ -1554,17 +1548,17 @@ export class ClusterScatterComponent {
|
|
|
1554
1548
|
} if (rf & 2) {
|
|
1555
1549
|
let _t;
|
|
1556
1550
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.svgRef = _t.first);
|
|
1557
|
-
} }, inputs: { Points: "Points", Clusters: "Clusters", ColorBy: "ColorBy", IsLoading: "IsLoading", DotRadius: "DotRadius", DotOpacity: "DotOpacity", HighlightRadius: "HighlightRadius", ShowLegend: "ShowLegend", ShowTooltip: "ShowTooltip", TooltipFields: "TooltipFields", FieldPriority: "FieldPriority", FieldDisplayNames: "FieldDisplayNames", EntityName: "EntityName", ColorPalette: "ColorPalette", EnableZoom: "EnableZoom", EnablePan: "EnablePan", AnimateTransitions: "AnimateTransitions", SelectedPointIds: "SelectedPointIds", MinZoom: "MinZoom", MaxZoom: "MaxZoom" }, outputs: { PointClicked: "PointClicked", OpenRecordRequested: "OpenRecordRequested", PointHovered: "PointHovered", BeforePointClick: "BeforePointClick", BeforePointHover: "BeforePointHover", BeforeZoom: "BeforeZoom", AfterClusteringComplete: "AfterClusteringComplete", ClusterSelected: "ClusterSelected", SelectionChanged: "SelectionChanged", ViewportChanged: "ViewportChanged", LabelEdited: "LabelEdited" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 10, vars: 10, consts: [["svgElement", ""], [1, "scatter-container"], [1, "loading-overlay"], [1, "empty-state"], ["preserveAspectRatio", "xMidYMid meet", 1, "scatter-svg", 3, "no-transitions"], [1, "threed-hint"], [1, "legend"], [1, "tooltip", 3, "left", "top"], [1, "detail-panel"], [1, "loading-spinner"], [1, "fa-solid", "fa-circle-nodes", "fa-spin"], [
|
|
1551
|
+
} }, inputs: { Points: "Points", Clusters: "Clusters", ColorBy: "ColorBy", IsLoading: "IsLoading", DotRadius: "DotRadius", DotOpacity: "DotOpacity", HighlightRadius: "HighlightRadius", ShowLegend: "ShowLegend", ShowTooltip: "ShowTooltip", TooltipFields: "TooltipFields", FieldPriority: "FieldPriority", FieldDisplayNames: "FieldDisplayNames", EntityName: "EntityName", ColorPalette: "ColorPalette", EnableZoom: "EnableZoom", EnablePan: "EnablePan", AnimateTransitions: "AnimateTransitions", SelectedPointIds: "SelectedPointIds", MinZoom: "MinZoom", MaxZoom: "MaxZoom" }, outputs: { PointClicked: "PointClicked", OpenRecordRequested: "OpenRecordRequested", PointHovered: "PointHovered", BeforePointClick: "BeforePointClick", BeforePointHover: "BeforePointHover", BeforeZoom: "BeforeZoom", AfterClusteringComplete: "AfterClusteringComplete", ClusterSelected: "ClusterSelected", SelectionChanged: "SelectionChanged", ViewportChanged: "ViewportChanged", LabelEdited: "LabelEdited" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 10, vars: 10, consts: [["svgElement", ""], [1, "scatter-container"], [1, "loading-overlay"], ["Icon", "fa-solid fa-chart-simple", "Title", "No data to display", "Message", "Configure and run clustering to see results", 1, "empty-state-fill"], ["preserveAspectRatio", "xMidYMid meet", 1, "scatter-svg", 3, "no-transitions"], [1, "threed-hint"], [1, "legend"], [1, "tooltip", 3, "left", "top"], [1, "detail-panel"], [1, "loading-spinner"], [1, "fa-solid", "fa-circle-nodes", "fa-spin"], ["preserveAspectRatio", "xMidYMid meet", 1, "scatter-svg", 3, "wheel", "mousedown"], ["cx", "50%", "cy", "50%", "r", "50%"], [1, "grid-lines"], [1, "data-point"], ["offset", "0%", "stop-opacity", "0.12"], ["offset", "100%", "stop-opacity", "0"], ["text-anchor", "middle", 1, "cluster-label"], [1, "data-point", 3, "mouseenter", "mouseleave", "click"], ["text-anchor", "middle", 1, "cluster-label", "cluster-label-3d"], ["fill", "none", "stroke-width", "2", "opacity", "0.8", 1, "selection-ring"], ["fill", "none", "stroke-width", "2.5", "opacity", "0.9"], [1, "fa-solid", "fa-cube"], ["title", "Reset view", 1, "threed-reset", 3, "click"], [1, "fa-solid", "fa-rotate-left"], [1, "legend-title"], [1, "legend-item"], [1, "legend-dot"], [1, "legend-label"], [1, "legend-count"], [1, "legend-item", 3, "click"], ["autofocus", "", 1, "legend-label-input", 3, "ngModel"], ["autofocus", "", 1, "legend-label-input", 3, "ngModelChange", "keydown", "blur", "click", "ngModel"], ["title", "Edit label", 1, "legend-edit-btn", 3, "click"], [1, "fa-solid", "fa-pencil"], [1, "tooltip"], ["Variant", "compact", 3, "EntityName", "Record"], [1, "tt-cluster"], [1, "fa-solid", "fa-circle", 2, "font-size", "7px", "vertical-align", "middle"], [1, "tt-action"], [1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "detail-header"], [1, "detail-header-content"], [1, "detail-icon"], [1, "detail-header-text"], [1, "detail-name"], [1, "detail-entity-badge"], ["title", "Close", 1, "detail-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "detail-cluster"], [1, "detail-cluster-dot"], ["Variant", "detail", "CssClass", "detail-entity-card", 3, "EntityName", "Record"], [1, "detail-members-section"], ["Size", "sm", 3, "ExpandedChange", "Fill", "FlushBody", "Expanded"], ["mjAccordionTitle", ""], ["mjAccordionBody", ""], [1, "detail-footer"], [1, "detail-open-btn", 3, "click"], [1, "mj-accordion-badge", "mj-accordion-badge--right"], [1, "detail-members-list"], [1, "detail-member-row", 3, "active"], [1, "detail-member-row", 3, "click"], [1, "member-icon", 3, "class"], [1, "member-label"], [1, "member-icon"]], template: function ClusterScatterComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1558
1552
|
i0.ɵɵelementStart(0, "div", 1);
|
|
1559
1553
|
i0.ɵɵconditionalCreate(1, ClusterScatterComponent_Conditional_1_Template, 5, 0, "div", 2);
|
|
1560
|
-
i0.ɵɵconditionalCreate(2, ClusterScatterComponent_Conditional_2_Template,
|
|
1554
|
+
i0.ɵɵconditionalCreate(2, ClusterScatterComponent_Conditional_2_Template, 1, 0, "mj-empty-state", 3);
|
|
1561
1555
|
i0.ɵɵconditionalCreate(3, ClusterScatterComponent_Conditional_3_Template, 17, 6, ":svg:svg", 4);
|
|
1562
1556
|
i0.ɵɵconditionalCreate(4, ClusterScatterComponent_Conditional_4_Template, 6, 0, "div", 5);
|
|
1563
1557
|
i0.ɵɵconditionalCreate(5, ClusterScatterComponent_Conditional_5_Template, 5, 0, "div", 6);
|
|
1564
1558
|
i0.ɵɵconditionalCreate(6, ClusterScatterComponent_Conditional_6_Template, 5, 0, "div", 6);
|
|
1565
1559
|
i0.ɵɵconditionalCreate(7, ClusterScatterComponent_Conditional_7_Template, 8, 7, "div", 7);
|
|
1566
1560
|
i0.ɵɵelementStart(8, "div", 8);
|
|
1567
|
-
i0.ɵɵconditionalCreate(9, ClusterScatterComponent_Conditional_9_Template,
|
|
1561
|
+
i0.ɵɵconditionalCreate(9, ClusterScatterComponent_Conditional_9_Template, 21, 11);
|
|
1568
1562
|
i0.ɵɵelementEnd()();
|
|
1569
1563
|
} if (rf & 2) {
|
|
1570
1564
|
i0.ɵɵadvance();
|
|
@@ -1585,11 +1579,11 @@ export class ClusterScatterComponent {
|
|
|
1585
1579
|
i0.ɵɵclassProp("detail-panel-open", ctx.ShowDetailPanel && ctx.SelectedPoint);
|
|
1586
1580
|
i0.ɵɵadvance();
|
|
1587
1581
|
i0.ɵɵconditional(ctx.SelectedPoint ? 9 : -1);
|
|
1588
|
-
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEntityCardComponent], styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.scatter-container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n/* SVG */\n.scatter-svg {\n width: 100%;\n height: 100%;\n cursor: grab;\n user-select: none;\n}\n\n.scatter-svg:active {\n cursor: grabbing;\n}\n\n/* Grid lines */\n.grid-lines line {\n stroke: var(--mj-border-subtle);\n stroke-width: 0.5;\n}\n\n/* Data points */\n.data-point {\n cursor: pointer;\n transition: opacity 0.15s ease, r 0.15s ease;\n}\n\n.data-point:hover {\n filter: brightness(1.2);\n}\n\n/* Selection rings */\n.selection-ring {\n pointer-events: none;\n transition: r 0.15s ease;\n}\n\n/* Disable transitions when AnimateTransitions is false */\n.no-transitions .data-point,\n.no-transitions .selection-ring {\n transition: none;\n}\n\n/* Loading overlay */\n.loading-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-page) 80%, transparent);\n z-index: 5;\n}\n\n.loading-spinner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-secondary);\n font-size: 0.9rem;\n}\n\n.loading-spinner i {\n font-size: 2rem;\n color: var(--mj-brand-primary);\n}\n\n/* Empty state */\n.empty-state {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n gap: 8px;\n}\n\n.empty-state i {\n font-size: 3rem;\n margin-bottom: 8px;\n opacity: 0.4;\n}\n\n.empty-state p {\n font-size: 1rem;\n margin: 0;\n}\n\n.empty-hint {\n font-size: 0.8rem !important;\n opacity: 0.7;\n}\n\n/* Legend */\n.legend {\n position: absolute;\n bottom: 20px;\n left: 20px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(12px);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px 18px;\n z-index: 3;\n}\n\n.legend-title {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 0.78rem;\n margin-bottom: 4px;\n color: var(--mj-text-primary);\n cursor: pointer;\n border-radius: 4px;\n padding: 2px 4px;\n margin-left: -4px;\n margin-right: -4px;\n transition: background 0.15s ease;\n}\n\n.legend-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.legend-label {\n flex: 1;\n}\n\n.legend-edit-btn {\n display: none;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.6rem;\n border-radius: 4px;\n transition: color 0.15s ease;\n}\n\n.legend-item:hover .legend-edit-btn {\n display: inline-flex;\n}\n\n.legend-edit-btn:hover {\n color: var(--mj-brand-primary);\n}\n\n.legend-label-input {\n flex: 1;\n padding: 2px 4px;\n border: 1px solid var(--mj-border-focus);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.75rem;\n outline: none;\n min-width: 60px;\n}\n\n.legend-count {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n margin-left: auto;\n padding-left: 16px;\n}\n\n/* Cluster labels on chart */\n.cluster-label {\n font-size: 14px;\n font-weight: 600;\n opacity: 0.85;\n pointer-events: none;\n text-shadow:\n 0 0 6px var(--mj-bg-page),\n 0 0 12px var(--mj-bg-page),\n 1px 1px 2px var(--mj-bg-page);\n}\n\n/* Tooltip */\n.tooltip {\n position: fixed;\n background: color-mix(in srgb, var(--mj-bg-surface-elevated) 96%, transparent);\n backdrop-filter: blur(16px);\n border: 1px solid var(--mj-border-strong);\n border-radius: 10px;\n padding: 14px 16px;\n width: 280px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--mj-bg-page) 40%, transparent);\n pointer-events: none;\n z-index: 50;\n}\n\n.tt-header {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.tt-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.tt-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.tt-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-entity {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n.tt-cluster {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.tt-fields {\n font-size: 0.72rem;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n}\n\n.tt-field-row {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-action {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-default);\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n\n.tt-action i {\n margin-right: 4px;\n}\n\n/* ================================================================\n Detail Panel (right slide-in)\n ================================================================ */\n\n.detail-panel {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 320px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(16px);\n border-left: 1px solid var(--mj-border-default);\n z-index: 10;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-bg-page) 30%, transparent);\n overflow: hidden;\n}\n\n.detail-panel-open {\n transform: translateX(0);\n}\n\n/* Header */\n.detail-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 16px 16px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-header-content {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.detail-icon {\n width: 2.25rem;\n height: 2.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.95rem;\n flex-shrink: 0;\n}\n\n.detail-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.detail-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n word-wrap: break-word;\n}\n\n.detail-entity-badge {\n display: inline-block;\n margin-top: 4px;\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 0.68rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.detail-close {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n padding: 4px 6px;\n border-radius: 4px;\n transition: color 0.15s ease, background 0.15s ease;\n flex-shrink: 0;\n}\n\n.detail-close:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Cluster badge */\n.detail-cluster {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 0.78rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.detail-cluster-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n/* Metadata fields */\n.detail-fields {\n padding: 4px 16px 8px;\n overflow-y: auto;\n flex-shrink: 0;\n}\n\n.detail-field {\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-field:last-child {\n border-bottom: none;\n}\n\n.detail-field-key {\n font-size: 0.68rem;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n\n.detail-field-value {\n font-size: 0.8rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n/* Cluster Members Section */\n.detail-members-section {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.detail-members-toggle {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 16px;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 0.78rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-align: left;\n transition: background 0.15s ease;\n}\n\n.detail-members-toggle:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.detail-members-toggle i {\n font-size: 0.65rem;\n width: 12px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.detail-members-count {\n margin-left: auto;\n font-size: 0.7rem;\n font-weight: 400;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 1px 7px;\n border-radius: 8px;\n}\n\n.detail-members-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 8px 8px;\n}\n\n.detail-member-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n transition: background 0.12s ease;\n}\n\n.detail-member-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.detail-member-row.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 500;\n}\n\n.detail-member-row .member-icon {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.detail-member-row.active .member-icon {\n color: var(--mj-brand-primary);\n}\n\n.member-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Footer */\n.detail-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.detail-open-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n padding: 8px 16px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 0.82rem;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.detail-open-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.detail-open-btn i {\n font-size: 0.75rem;\n}\n\n/* 3D orbit hint + reset */\n.threed-hint {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 6;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 5px 8px 5px 10px;\n background: color-mix(in srgb, var(--mj-bg-surface) 88%, transparent);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n backdrop-filter: blur(4px);\n}\n.threed-hint > i { color: var(--mj-brand-primary); }\n.threed-reset {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n.threed-reset:hover { color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n\n/* 3D cluster labels \u2014 halo for readability over points */\n.cluster-label-3d {\n font-weight: 700;\n font-size: 13px;\n paint-order: stroke;\n stroke: var(--mj-bg-surface);\n stroke-width: 3px;\n stroke-linejoin: round;\n pointer-events: none;\n}\n"], encapsulation: 2 }); }
|
|
1582
|
+
} }, dependencies: [i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, i2.MJEntityCardComponent, i3.MJEmptyStateComponent, i3.MJAccordionPanelComponent, i3.MJAccordionTitleDirective, i3.MJAccordionBodyDirective], styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.scatter-container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n/* SVG */\n.scatter-svg {\n width: 100%;\n height: 100%;\n cursor: grab;\n user-select: none;\n}\n\n.scatter-svg:active {\n cursor: grabbing;\n}\n\n/* Grid lines */\n.grid-lines line {\n stroke: var(--mj-border-subtle);\n stroke-width: 0.5;\n}\n\n/* Data points */\n.data-point {\n cursor: pointer;\n transition: opacity 0.15s ease, r 0.15s ease;\n}\n\n.data-point:hover {\n filter: brightness(1.2);\n}\n\n/* Selection rings */\n.selection-ring {\n pointer-events: none;\n transition: r 0.15s ease;\n}\n\n/* Disable transitions when AnimateTransitions is false */\n.no-transitions .data-point,\n.no-transitions .selection-ring {\n transition: none;\n}\n\n/* Loading overlay */\n.loading-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-page) 80%, transparent);\n z-index: 5;\n}\n\n.loading-spinner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-secondary);\n font-size: 0.9rem;\n}\n\n.loading-spinner i {\n font-size: 2rem;\n color: var(--mj-brand-primary);\n}\n\n/* Empty state \u2014 overlay the full scatter container */\n.empty-state-fill {\n position: absolute;\n inset: 0;\n}\n\n/* Legend */\n.legend {\n position: absolute;\n bottom: 20px;\n left: 20px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(12px);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px 18px;\n z-index: 3;\n}\n\n.legend-title {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 0.78rem;\n margin-bottom: 4px;\n color: var(--mj-text-primary);\n cursor: pointer;\n border-radius: 4px;\n padding: 2px 4px;\n margin-left: -4px;\n margin-right: -4px;\n transition: background 0.15s ease;\n}\n\n.legend-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.legend-label {\n flex: 1;\n}\n\n.legend-edit-btn {\n display: none;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.6rem;\n border-radius: 4px;\n transition: color 0.15s ease;\n}\n\n.legend-item:hover .legend-edit-btn {\n display: inline-flex;\n}\n\n.legend-edit-btn:hover {\n color: var(--mj-brand-primary);\n}\n\n.legend-label-input {\n flex: 1;\n padding: 2px 4px;\n border: 1px solid var(--mj-border-focus);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.75rem;\n outline: none;\n min-width: 60px;\n}\n\n.legend-count {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n margin-left: auto;\n padding-left: 16px;\n}\n\n/* Cluster labels on chart */\n.cluster-label {\n font-size: 14px;\n font-weight: 600;\n opacity: 0.85;\n pointer-events: none;\n text-shadow:\n 0 0 6px var(--mj-bg-page),\n 0 0 12px var(--mj-bg-page),\n 1px 1px 2px var(--mj-bg-page);\n}\n\n/* Tooltip */\n.tooltip {\n position: fixed;\n background: color-mix(in srgb, var(--mj-bg-surface-elevated) 96%, transparent);\n backdrop-filter: blur(16px);\n border: 1px solid var(--mj-border-strong);\n border-radius: 10px;\n padding: 14px 16px;\n width: 280px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--mj-bg-page) 40%, transparent);\n pointer-events: none;\n z-index: 50;\n}\n\n.tt-header {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.tt-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.tt-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.tt-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-entity {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n.tt-cluster {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.tt-fields {\n font-size: 0.72rem;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n}\n\n.tt-field-row {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-action {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-default);\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n\n.tt-action i {\n margin-right: 4px;\n}\n\n/* ================================================================\n Detail Panel (right slide-in)\n ================================================================ */\n\n.detail-panel {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 320px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(16px);\n border-left: 1px solid var(--mj-border-default);\n z-index: 10;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-bg-page) 30%, transparent);\n overflow: hidden;\n}\n\n.detail-panel-open {\n transform: translateX(0);\n}\n\n/* Header */\n.detail-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 16px 16px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-header-content {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.detail-icon {\n width: 2.25rem;\n height: 2.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.95rem;\n flex-shrink: 0;\n}\n\n.detail-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.detail-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n word-wrap: break-word;\n}\n\n.detail-entity-badge {\n display: inline-block;\n margin-top: 4px;\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 0.68rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.detail-close {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n padding: 4px 6px;\n border-radius: 4px;\n transition: color 0.15s ease, background 0.15s ease;\n flex-shrink: 0;\n}\n\n.detail-close:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Cluster badge */\n.detail-cluster {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 0.78rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.detail-cluster-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n/* Metadata fields */\n.detail-fields {\n padding: 4px 16px 8px;\n overflow-y: auto;\n flex-shrink: 0;\n}\n\n.detail-field {\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-field:last-child {\n border-bottom: none;\n}\n\n.detail-field-key {\n font-size: 0.68rem;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n\n.detail-field-value {\n font-size: 0.8rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n/* Cluster Members Section */\n.detail-members-section {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* .detail-members-toggle / .detail-members-count removed: the bespoke\n disclosure toggle + count pill were replaced by <mj-accordion-panel>\n (header/chevron) and the standard .mj-accordion-badge--right. */\n\n.detail-members-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 8px 8px;\n}\n\n.detail-member-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n transition: background 0.12s ease;\n}\n\n.detail-member-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.detail-member-row.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 500;\n}\n\n.detail-member-row .member-icon {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.detail-member-row.active .member-icon {\n color: var(--mj-brand-primary);\n}\n\n.member-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Footer */\n.detail-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.detail-open-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n padding: 8px 16px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 0.82rem;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.detail-open-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.detail-open-btn i {\n font-size: 0.75rem;\n}\n\n/* 3D orbit hint + reset */\n.threed-hint {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 6;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 5px 8px 5px 10px;\n background: color-mix(in srgb, var(--mj-bg-surface) 88%, transparent);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n backdrop-filter: blur(4px);\n}\n.threed-hint > i { color: var(--mj-brand-primary); }\n.threed-reset {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n.threed-reset:hover { color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n\n/* 3D cluster labels \u2014 halo for readability over points */\n.cluster-label-3d {\n font-weight: 700;\n font-size: 13px;\n paint-order: stroke;\n stroke: var(--mj-bg-surface);\n stroke-width: 3px;\n stroke-linejoin: round;\n pointer-events: none;\n}\n"], encapsulation: 2 }); }
|
|
1589
1583
|
}
|
|
1590
1584
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClusterScatterComponent, [{
|
|
1591
1585
|
type: Component,
|
|
1592
|
-
args: [{ standalone: false, selector: 'mj-cluster-scatter', encapsulation: ViewEncapsulation.None, template: "<div class=\"scatter-container\">\n <!-- Loading overlay -->\n @if (IsLoading) {\n <div class=\"loading-overlay\">\n <div class=\"loading-spinner\">\n <i class=\"fa-solid fa-circle-nodes fa-spin\"></i>\n <span>Computing clusters...</span>\n </div>\n </div>\n }\n\n <!-- Empty state -->\n @if (!IsLoading && Points.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-chart-scatter\"></i>\n <p>No data to display</p>\n <p class=\"empty-hint\">Configure and run clustering to see results</p>\n </div>\n }\n\n <!-- SVG scatter plot -->\n @if (Points.length > 0) {\n <svg #svgElement\n class=\"scatter-svg\"\n [class.no-transitions]=\"!AnimateTransitions\"\n [attr.viewBox]=\"ViewBoxString\"\n preserveAspectRatio=\"xMidYMid meet\"\n (wheel)=\"OnWheel($event)\"\n (mousedown)=\"OnMouseDown($event)\">\n\n <!-- Gradient definitions for cluster glow -->\n <defs>\n @for (centroid of ClusterCentroids; track TrackCentroidBy($index, centroid)) {\n <radialGradient [attr.id]=\"'cluster-glow-' + centroid.ClusterId\"\n cx=\"50%\" cy=\"50%\" r=\"50%\">\n <stop offset=\"0%\" [attr.stop-color]=\"centroid.Color\" stop-opacity=\"0.12\"/>\n <stop offset=\"100%\" [attr.stop-color]=\"centroid.Color\" stop-opacity=\"0\"/>\n </radialGradient>\n }\n </defs>\n\n <!-- Background grid lines -->\n <g class=\"grid-lines\">\n @for (y of HorizontalGridLines; track y) {\n <line [attr.x1]=\"0\" [attr.y1]=\"y\" [attr.x2]=\"1000\" [attr.y2]=\"y\"/>\n }\n @for (x of VerticalGridLines; track x) {\n <line [attr.x1]=\"x\" [attr.y1]=\"0\" [attr.x2]=\"x\" [attr.y2]=\"700\"/>\n }\n </g>\n\n <!-- Cluster glow + labels (2D only; centroids are 2D aesthetics) -->\n @if (!Is3D) {\n @for (centroid of ClusterCentroids; track TrackCentroidBy($index, centroid)) {\n <circle [attr.cx]=\"centroid.Cx\"\n [attr.cy]=\"centroid.Cy\"\n [attr.r]=\"centroid.R\"\n [attr.fill]=\"'url(#cluster-glow-' + centroid.ClusterId + ')'\"/>\n }\n @for (centroid of ClusterCentroids; track TrackCentroidBy($index, centroid)) {\n @if (GetClusterLabelById(centroid.ClusterId); as label) {\n <text class=\"cluster-label\"\n [attr.x]=\"centroid.Cx\"\n [attr.y]=\"centroid.Cy - centroid.R - 8\"\n text-anchor=\"middle\"\n [attr.fill]=\"centroid.Color\">{{ label }}</text>\n }\n }\n }\n\n <!-- Data points (RenderPoints is depth-sorted in 3D) -->\n @for (point of RenderPoints; track TrackPointBy($index, point)) {\n <circle class=\"data-point\"\n [attr.cx]=\"PX(point)\"\n [attr.cy]=\"PY(point)\"\n [attr.r]=\"GetPointRadius(point)\"\n [attr.fill]=\"GetPointColor(point)\"\n [attr.opacity]=\"GetPointOpacity(point)\"\n (mouseenter)=\"OnPointMouseEnter(point, $event)\"\n (mouseleave)=\"OnPointMouseLeave()\"\n (click)=\"OnPointClick(point); $event.stopPropagation()\"/>\n }\n\n <!-- 3D cluster labels (at projected centroids; follow rotation) -->\n @if (Is3D && ColorBy !== 'entity') {\n @for (lbl of ProjectedClusterLabels; track lbl.ClusterId) {\n @if (GetClusterLabelById(lbl.ClusterId); as text) {\n <text class=\"cluster-label cluster-label-3d\"\n [attr.x]=\"lbl.X\"\n [attr.y]=\"lbl.Y\"\n text-anchor=\"middle\"\n [attr.fill]=\"lbl.Color\">{{ text }}</text>\n }\n }\n }\n\n <!-- Selection rings for selected points -->\n @for (point of Points; track TrackPointBy($index, point)) {\n @if (IsSelected(point)) {\n <circle class=\"selection-ring\"\n [attr.cx]=\"PX(point)\"\n [attr.cy]=\"PY(point)\"\n [attr.r]=\"HighlightRadius + 2\"\n fill=\"none\"\n [attr.stroke]=\"GetPointColor(point)\"\n stroke-width=\"2\"\n opacity=\"0.8\"/>\n }\n }\n\n <!-- Highlight ring for last-clicked point -->\n @if (HighlightedKey) {\n @for (point of Points; track TrackPointBy($index, point)) {\n @if (IsHighlighted(point)) {\n <circle [attr.cx]=\"PX(point)\"\n [attr.cy]=\"PY(point)\"\n [attr.r]=\"HighlightRadius + 4\"\n fill=\"none\"\n [attr.stroke]=\"GetPointColor(point)\"\n stroke-width=\"2.5\"\n opacity=\"0.9\"/>\n }\n }\n }\n </svg>\n }\n\n <!-- 3D orbit hint + reset -->\n @if (Points.length > 0 && Is3D) {\n <div class=\"threed-hint\">\n <i class=\"fa-solid fa-cube\"></i>\n <span>3D \u00B7 drag to rotate</span>\n <button class=\"threed-reset\" (click)=\"ResetRotation()\" title=\"Reset view\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n </div>\n }\n\n <!-- Entity legend (multi-entity color mode) -->\n @if (ShowLegend && ColorBy === 'entity' && EntityLegend.length > 0) {\n <div class=\"legend\">\n <div class=\"legend-title\">Entities</div>\n @for (ent of EntityLegend; track ent.Name) {\n <div class=\"legend-item\">\n <div class=\"legend-dot\" [style.background]=\"ent.Color\"></div>\n <span class=\"legend-label\">{{ ent.Name }}</span>\n <span class=\"legend-count\">{{ ent.Count }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Legend overlay (cluster color mode) -->\n @if (ShowLegend && ColorBy !== 'entity' && Clusters.length > 0) {\n <div class=\"legend\">\n <div class=\"legend-title\">Clusters</div>\n @for (cluster of Clusters; track TrackClusterBy($index, cluster)) {\n <div class=\"legend-item\" (click)=\"OnClusterLegendClick(cluster)\">\n <div class=\"legend-dot\" [style.background]=\"cluster.Color\"></div>\n @if (EditingClusterId === cluster.Id) {\n <input class=\"legend-label-input\"\n [(ngModel)]=\"EditingLabelDraft\"\n (keydown)=\"OnLabelEditKeydown($event, cluster)\"\n (blur)=\"CommitLabelEdit(cluster)\"\n (click)=\"$event.stopPropagation()\"\n autofocus />\n } @else {\n <span class=\"legend-label\">{{ cluster.Label }}</span>\n <button class=\"legend-edit-btn\"\n title=\"Edit label\"\n (click)=\"StartLabelEdit(cluster, $event)\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n }\n <span class=\"legend-count\">{{ cluster.MemberCount }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Tooltip -->\n @if (ShowTooltip && HoveredPoint) {\n <div class=\"tooltip\"\n [style.left.px]=\"TooltipX\"\n [style.top.px]=\"TooltipY\">\n <mj-entity-card\n [EntityName]=\"EntityName\"\n [Record]=\"HoveredPoint.Metadata\"\n Variant=\"compact\">\n </mj-entity-card>\n <div class=\"tt-cluster\">\n <i class=\"fa-solid fa-circle\" style=\"font-size: 7px; vertical-align: middle\"></i>\n {{ GetClusterLabel(HoveredPoint) }}\n </div>\n <div class=\"tt-action\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Click to view details\n </div>\n </div>\n }\n\n <!-- Detail Panel (slide-in from right) -->\n <div class=\"detail-panel\" [class.detail-panel-open]=\"ShowDetailPanel && SelectedPoint\">\n @if (SelectedPoint) {\n <!-- Panel Header -->\n <div class=\"detail-header\">\n <div class=\"detail-header-content\">\n @if (SelectedPoint.Metadata?.['EntityIcon']) {\n <div class=\"detail-icon\">\n <i [class]=\"SelectedPoint.Metadata['EntityIcon']\"></i>\n </div>\n }\n <div class=\"detail-header-text\">\n <div class=\"detail-name\">{{ SelectedPoint.Label }}</div>\n @if (SelectedPoint.Metadata?.['Entity']) {\n <span class=\"detail-entity-badge\">{{ SelectedPoint.Metadata['Entity'] }}</span>\n }\n </div>\n </div>\n <button class=\"detail-close\" (click)=\"CloseDetailPanel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Cluster badge -->\n <div class=\"detail-cluster\">\n <span class=\"detail-cluster-dot\"\n [style.background]=\"GetClusterColor(SelectedPoint.ClusterId)\"></span>\n {{ GetClusterLabel(SelectedPoint) }}\n </div>\n\n <!-- Metadata fields via entity card -->\n <mj-entity-card\n [EntityName]=\"EntityName\"\n [Record]=\"SelectedPoint.Metadata\"\n Variant=\"detail\"\n CssClass=\"detail-entity-card\">\n </mj-entity-card>\n\n <!-- Cluster Members -->\n <div class=\"detail-members-section\">\n <button class=\"detail-members-toggle\" (click)=\"ToggleClusterMembers()\">\n <i class=\"fa-solid\"\n [class.fa-chevron-down]=\"ClusterMembersExpanded\"\n [class.fa-chevron-right]=\"!ClusterMembersExpanded\"></i>\n <span>Cluster Members</span>\n <span class=\"detail-members-count\">{{ ClusterMembers.length }}</span>\n </button>\n\n @if (ClusterMembersExpanded) {\n <div class=\"detail-members-list\">\n @for (member of ClusterMembers; track TrackMemberBy($index, member)) {\n <div class=\"detail-member-row\"\n [class.active]=\"member.VectorKey === SelectedPoint.VectorKey\"\n (click)=\"OnClusterMemberClick(member)\">\n @if (member.Metadata?.['EntityIcon']) {\n <i [class]=\"member.Metadata['EntityIcon']\" class=\"member-icon\"></i>\n }\n <span class=\"member-label\">{{ member.Label }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Open Record button -->\n <div class=\"detail-footer\">\n <button class=\"detail-open-btn\" (click)=\"OnOpenRecordClick()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n Open Record\n </button>\n </div>\n }\n </div>\n</div>\n", styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.scatter-container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n/* SVG */\n.scatter-svg {\n width: 100%;\n height: 100%;\n cursor: grab;\n user-select: none;\n}\n\n.scatter-svg:active {\n cursor: grabbing;\n}\n\n/* Grid lines */\n.grid-lines line {\n stroke: var(--mj-border-subtle);\n stroke-width: 0.5;\n}\n\n/* Data points */\n.data-point {\n cursor: pointer;\n transition: opacity 0.15s ease, r 0.15s ease;\n}\n\n.data-point:hover {\n filter: brightness(1.2);\n}\n\n/* Selection rings */\n.selection-ring {\n pointer-events: none;\n transition: r 0.15s ease;\n}\n\n/* Disable transitions when AnimateTransitions is false */\n.no-transitions .data-point,\n.no-transitions .selection-ring {\n transition: none;\n}\n\n/* Loading overlay */\n.loading-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-page) 80%, transparent);\n z-index: 5;\n}\n\n.loading-spinner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-secondary);\n font-size: 0.9rem;\n}\n\n.loading-spinner i {\n font-size: 2rem;\n color: var(--mj-brand-primary);\n}\n\n/* Empty state */\n.empty-state {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n gap: 8px;\n}\n\n.empty-state i {\n font-size: 3rem;\n margin-bottom: 8px;\n opacity: 0.4;\n}\n\n.empty-state p {\n font-size: 1rem;\n margin: 0;\n}\n\n.empty-hint {\n font-size: 0.8rem !important;\n opacity: 0.7;\n}\n\n/* Legend */\n.legend {\n position: absolute;\n bottom: 20px;\n left: 20px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(12px);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px 18px;\n z-index: 3;\n}\n\n.legend-title {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 0.78rem;\n margin-bottom: 4px;\n color: var(--mj-text-primary);\n cursor: pointer;\n border-radius: 4px;\n padding: 2px 4px;\n margin-left: -4px;\n margin-right: -4px;\n transition: background 0.15s ease;\n}\n\n.legend-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.legend-label {\n flex: 1;\n}\n\n.legend-edit-btn {\n display: none;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.6rem;\n border-radius: 4px;\n transition: color 0.15s ease;\n}\n\n.legend-item:hover .legend-edit-btn {\n display: inline-flex;\n}\n\n.legend-edit-btn:hover {\n color: var(--mj-brand-primary);\n}\n\n.legend-label-input {\n flex: 1;\n padding: 2px 4px;\n border: 1px solid var(--mj-border-focus);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.75rem;\n outline: none;\n min-width: 60px;\n}\n\n.legend-count {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n margin-left: auto;\n padding-left: 16px;\n}\n\n/* Cluster labels on chart */\n.cluster-label {\n font-size: 14px;\n font-weight: 600;\n opacity: 0.85;\n pointer-events: none;\n text-shadow:\n 0 0 6px var(--mj-bg-page),\n 0 0 12px var(--mj-bg-page),\n 1px 1px 2px var(--mj-bg-page);\n}\n\n/* Tooltip */\n.tooltip {\n position: fixed;\n background: color-mix(in srgb, var(--mj-bg-surface-elevated) 96%, transparent);\n backdrop-filter: blur(16px);\n border: 1px solid var(--mj-border-strong);\n border-radius: 10px;\n padding: 14px 16px;\n width: 280px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--mj-bg-page) 40%, transparent);\n pointer-events: none;\n z-index: 50;\n}\n\n.tt-header {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.tt-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.tt-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.tt-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-entity {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n.tt-cluster {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.tt-fields {\n font-size: 0.72rem;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n}\n\n.tt-field-row {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-action {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-default);\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n\n.tt-action i {\n margin-right: 4px;\n}\n\n/* ================================================================\n Detail Panel (right slide-in)\n ================================================================ */\n\n.detail-panel {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 320px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(16px);\n border-left: 1px solid var(--mj-border-default);\n z-index: 10;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-bg-page) 30%, transparent);\n overflow: hidden;\n}\n\n.detail-panel-open {\n transform: translateX(0);\n}\n\n/* Header */\n.detail-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 16px 16px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-header-content {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.detail-icon {\n width: 2.25rem;\n height: 2.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.95rem;\n flex-shrink: 0;\n}\n\n.detail-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.detail-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n word-wrap: break-word;\n}\n\n.detail-entity-badge {\n display: inline-block;\n margin-top: 4px;\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 0.68rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.detail-close {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n padding: 4px 6px;\n border-radius: 4px;\n transition: color 0.15s ease, background 0.15s ease;\n flex-shrink: 0;\n}\n\n.detail-close:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Cluster badge */\n.detail-cluster {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 0.78rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.detail-cluster-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n/* Metadata fields */\n.detail-fields {\n padding: 4px 16px 8px;\n overflow-y: auto;\n flex-shrink: 0;\n}\n\n.detail-field {\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-field:last-child {\n border-bottom: none;\n}\n\n.detail-field-key {\n font-size: 0.68rem;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n\n.detail-field-value {\n font-size: 0.8rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n/* Cluster Members Section */\n.detail-members-section {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.detail-members-toggle {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 10px 16px;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 0.78rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-align: left;\n transition: background 0.15s ease;\n}\n\n.detail-members-toggle:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.detail-members-toggle i {\n font-size: 0.65rem;\n width: 12px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n.detail-members-count {\n margin-left: auto;\n font-size: 0.7rem;\n font-weight: 400;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 1px 7px;\n border-radius: 8px;\n}\n\n.detail-members-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 8px 8px;\n}\n\n.detail-member-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n transition: background 0.12s ease;\n}\n\n.detail-member-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.detail-member-row.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 500;\n}\n\n.detail-member-row .member-icon {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.detail-member-row.active .member-icon {\n color: var(--mj-brand-primary);\n}\n\n.member-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Footer */\n.detail-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.detail-open-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n padding: 8px 16px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 0.82rem;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.detail-open-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.detail-open-btn i {\n font-size: 0.75rem;\n}\n\n/* 3D orbit hint + reset */\n.threed-hint {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 6;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 5px 8px 5px 10px;\n background: color-mix(in srgb, var(--mj-bg-surface) 88%, transparent);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n backdrop-filter: blur(4px);\n}\n.threed-hint > i { color: var(--mj-brand-primary); }\n.threed-reset {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n.threed-reset:hover { color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n\n/* 3D cluster labels \u2014 halo for readability over points */\n.cluster-label-3d {\n font-weight: 700;\n font-size: 13px;\n paint-order: stroke;\n stroke: var(--mj-bg-surface);\n stroke-width: 3px;\n stroke-linejoin: round;\n pointer-events: none;\n}\n"] }]
|
|
1586
|
+
args: [{ standalone: false, selector: 'mj-cluster-scatter', encapsulation: ViewEncapsulation.None, template: "<div class=\"scatter-container\">\n <!-- Loading overlay -->\n @if (IsLoading) {\n <div class=\"loading-overlay\">\n <div class=\"loading-spinner\">\n <i class=\"fa-solid fa-circle-nodes fa-spin\"></i>\n <span>Computing clusters...</span>\n </div>\n </div>\n }\n\n <!-- Empty state -->\n @if (!IsLoading && Points.length === 0) {\n <mj-empty-state\n class=\"empty-state-fill\"\n Icon=\"fa-solid fa-chart-simple\"\n Title=\"No data to display\"\n Message=\"Configure and run clustering to see results\" />\n }\n\n <!-- SVG scatter plot -->\n @if (Points.length > 0) {\n <svg #svgElement\n class=\"scatter-svg\"\n [class.no-transitions]=\"!AnimateTransitions\"\n [attr.viewBox]=\"ViewBoxString\"\n preserveAspectRatio=\"xMidYMid meet\"\n (wheel)=\"OnWheel($event)\"\n (mousedown)=\"OnMouseDown($event)\">\n\n <!-- Gradient definitions for cluster glow -->\n <defs>\n @for (centroid of ClusterCentroids; track TrackCentroidBy($index, centroid)) {\n <radialGradient [attr.id]=\"'cluster-glow-' + centroid.ClusterId\"\n cx=\"50%\" cy=\"50%\" r=\"50%\">\n <stop offset=\"0%\" [attr.stop-color]=\"centroid.Color\" stop-opacity=\"0.12\"/>\n <stop offset=\"100%\" [attr.stop-color]=\"centroid.Color\" stop-opacity=\"0\"/>\n </radialGradient>\n }\n </defs>\n\n <!-- Background grid lines -->\n <g class=\"grid-lines\">\n @for (y of HorizontalGridLines; track y) {\n <line [attr.x1]=\"0\" [attr.y1]=\"y\" [attr.x2]=\"1000\" [attr.y2]=\"y\"/>\n }\n @for (x of VerticalGridLines; track x) {\n <line [attr.x1]=\"x\" [attr.y1]=\"0\" [attr.x2]=\"x\" [attr.y2]=\"700\"/>\n }\n </g>\n\n <!-- Cluster glow + labels (2D only; centroids are 2D aesthetics) -->\n @if (!Is3D) {\n @for (centroid of ClusterCentroids; track TrackCentroidBy($index, centroid)) {\n <circle [attr.cx]=\"centroid.Cx\"\n [attr.cy]=\"centroid.Cy\"\n [attr.r]=\"centroid.R\"\n [attr.fill]=\"'url(#cluster-glow-' + centroid.ClusterId + ')'\"/>\n }\n @for (centroid of ClusterCentroids; track TrackCentroidBy($index, centroid)) {\n @if (GetClusterLabelById(centroid.ClusterId); as label) {\n <text class=\"cluster-label\"\n [attr.x]=\"centroid.Cx\"\n [attr.y]=\"centroid.Cy - centroid.R - 8\"\n text-anchor=\"middle\"\n [attr.fill]=\"centroid.Color\">{{ label }}</text>\n }\n }\n }\n\n <!-- Data points (RenderPoints is depth-sorted in 3D) -->\n @for (point of RenderPoints; track TrackPointBy($index, point)) {\n <circle class=\"data-point\"\n [attr.cx]=\"PX(point)\"\n [attr.cy]=\"PY(point)\"\n [attr.r]=\"GetPointRadius(point)\"\n [attr.fill]=\"GetPointColor(point)\"\n [attr.opacity]=\"GetPointOpacity(point)\"\n (mouseenter)=\"OnPointMouseEnter(point, $event)\"\n (mouseleave)=\"OnPointMouseLeave()\"\n (click)=\"OnPointClick(point); $event.stopPropagation()\"/>\n }\n\n <!-- 3D cluster labels (at projected centroids; follow rotation) -->\n @if (Is3D && ColorBy !== 'entity') {\n @for (lbl of ProjectedClusterLabels; track lbl.ClusterId) {\n @if (GetClusterLabelById(lbl.ClusterId); as text) {\n <text class=\"cluster-label cluster-label-3d\"\n [attr.x]=\"lbl.X\"\n [attr.y]=\"lbl.Y\"\n text-anchor=\"middle\"\n [attr.fill]=\"lbl.Color\">{{ text }}</text>\n }\n }\n }\n\n <!-- Selection rings for selected points -->\n @for (point of Points; track TrackPointBy($index, point)) {\n @if (IsSelected(point)) {\n <circle class=\"selection-ring\"\n [attr.cx]=\"PX(point)\"\n [attr.cy]=\"PY(point)\"\n [attr.r]=\"HighlightRadius + 2\"\n fill=\"none\"\n [attr.stroke]=\"GetPointColor(point)\"\n stroke-width=\"2\"\n opacity=\"0.8\"/>\n }\n }\n\n <!-- Highlight ring for last-clicked point -->\n @if (HighlightedKey) {\n @for (point of Points; track TrackPointBy($index, point)) {\n @if (IsHighlighted(point)) {\n <circle [attr.cx]=\"PX(point)\"\n [attr.cy]=\"PY(point)\"\n [attr.r]=\"HighlightRadius + 4\"\n fill=\"none\"\n [attr.stroke]=\"GetPointColor(point)\"\n stroke-width=\"2.5\"\n opacity=\"0.9\"/>\n }\n }\n }\n </svg>\n }\n\n <!-- 3D orbit hint + reset -->\n @if (Points.length > 0 && Is3D) {\n <div class=\"threed-hint\">\n <i class=\"fa-solid fa-cube\"></i>\n <span>3D \u00B7 drag to rotate</span>\n <button class=\"threed-reset\" (click)=\"ResetRotation()\" title=\"Reset view\">\n <i class=\"fa-solid fa-rotate-left\"></i>\n </button>\n </div>\n }\n\n <!-- Entity legend (multi-entity color mode) -->\n @if (ShowLegend && ColorBy === 'entity' && EntityLegend.length > 0) {\n <div class=\"legend\">\n <div class=\"legend-title\">Entities</div>\n @for (ent of EntityLegend; track ent.Name) {\n <div class=\"legend-item\">\n <div class=\"legend-dot\" [style.background]=\"ent.Color\"></div>\n <span class=\"legend-label\">{{ ent.Name }}</span>\n <span class=\"legend-count\">{{ ent.Count }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Legend overlay (cluster color mode) -->\n @if (ShowLegend && ColorBy !== 'entity' && Clusters.length > 0) {\n <div class=\"legend\">\n <div class=\"legend-title\">Clusters</div>\n @for (cluster of Clusters; track TrackClusterBy($index, cluster)) {\n <div class=\"legend-item\" (click)=\"OnClusterLegendClick(cluster)\">\n <div class=\"legend-dot\" [style.background]=\"cluster.Color\"></div>\n @if (EditingClusterId === cluster.Id) {\n <input class=\"legend-label-input\"\n [(ngModel)]=\"EditingLabelDraft\"\n (keydown)=\"OnLabelEditKeydown($event, cluster)\"\n (blur)=\"CommitLabelEdit(cluster)\"\n (click)=\"$event.stopPropagation()\"\n autofocus />\n } @else {\n <span class=\"legend-label\">{{ cluster.Label }}</span>\n <button class=\"legend-edit-btn\"\n title=\"Edit label\"\n (click)=\"StartLabelEdit(cluster, $event)\">\n <i class=\"fa-solid fa-pencil\"></i>\n </button>\n }\n <span class=\"legend-count\">{{ cluster.MemberCount }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Tooltip -->\n @if (ShowTooltip && HoveredPoint) {\n <div class=\"tooltip\"\n [style.left.px]=\"TooltipX\"\n [style.top.px]=\"TooltipY\">\n <mj-entity-card\n [EntityName]=\"EntityName\"\n [Record]=\"HoveredPoint.Metadata\"\n Variant=\"compact\">\n </mj-entity-card>\n <div class=\"tt-cluster\">\n <i class=\"fa-solid fa-circle\" style=\"font-size: 7px; vertical-align: middle\"></i>\n {{ GetClusterLabel(HoveredPoint) }}\n </div>\n <div class=\"tt-action\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Click to view details\n </div>\n </div>\n }\n\n <!-- Detail Panel (slide-in from right) -->\n <div class=\"detail-panel\" [class.detail-panel-open]=\"ShowDetailPanel && SelectedPoint\">\n @if (SelectedPoint) {\n <!-- Panel Header -->\n <div class=\"detail-header\">\n <div class=\"detail-header-content\">\n @if (SelectedPoint.Metadata?.['EntityIcon']) {\n <div class=\"detail-icon\">\n <i [class]=\"SelectedPoint.Metadata['EntityIcon']\"></i>\n </div>\n }\n <div class=\"detail-header-text\">\n <div class=\"detail-name\">{{ SelectedPoint.Label }}</div>\n @if (SelectedPoint.Metadata?.['Entity']) {\n <span class=\"detail-entity-badge\">{{ SelectedPoint.Metadata['Entity'] }}</span>\n }\n </div>\n </div>\n <button class=\"detail-close\" (click)=\"CloseDetailPanel()\" title=\"Close\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Cluster badge -->\n <div class=\"detail-cluster\">\n <span class=\"detail-cluster-dot\"\n [style.background]=\"GetClusterColor(SelectedPoint.ClusterId)\"></span>\n {{ GetClusterLabel(SelectedPoint) }}\n </div>\n\n <!-- Metadata fields via entity card -->\n <mj-entity-card\n [EntityName]=\"EntityName\"\n [Record]=\"SelectedPoint.Metadata\"\n Variant=\"detail\"\n CssClass=\"detail-entity-card\">\n </mj-entity-card>\n\n <!-- Cluster Members -->\n <div class=\"detail-members-section\">\n <mj-accordion-panel\n Size=\"sm\"\n [Fill]=\"true\"\n [FlushBody]=\"true\"\n [(Expanded)]=\"ClusterMembersExpanded\">\n <ng-template mjAccordionTitle>\n Cluster Members\n <span class=\"mj-accordion-badge mj-accordion-badge--right\">{{ ClusterMembers.length }}</span>\n </ng-template>\n <ng-template mjAccordionBody>\n <div class=\"detail-members-list\">\n @for (member of ClusterMembers; track TrackMemberBy($index, member)) {\n <div class=\"detail-member-row\"\n [class.active]=\"member.VectorKey === SelectedPoint?.VectorKey\"\n (click)=\"OnClusterMemberClick(member)\">\n @if (member.Metadata?.['EntityIcon']) {\n <i [class]=\"member.Metadata['EntityIcon']\" class=\"member-icon\"></i>\n }\n <span class=\"member-label\">{{ member.Label }}</span>\n </div>\n }\n </div>\n </ng-template>\n </mj-accordion-panel>\n </div>\n\n <!-- Open Record button -->\n <div class=\"detail-footer\">\n <button class=\"detail-open-btn\" (click)=\"OnOpenRecordClick()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n Open Record\n </button>\n </div>\n }\n </div>\n</div>\n", styles: [":host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.scatter-container {\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n background: var(--mj-bg-page);\n}\n\n/* SVG */\n.scatter-svg {\n width: 100%;\n height: 100%;\n cursor: grab;\n user-select: none;\n}\n\n.scatter-svg:active {\n cursor: grabbing;\n}\n\n/* Grid lines */\n.grid-lines line {\n stroke: var(--mj-border-subtle);\n stroke-width: 0.5;\n}\n\n/* Data points */\n.data-point {\n cursor: pointer;\n transition: opacity 0.15s ease, r 0.15s ease;\n}\n\n.data-point:hover {\n filter: brightness(1.2);\n}\n\n/* Selection rings */\n.selection-ring {\n pointer-events: none;\n transition: r 0.15s ease;\n}\n\n/* Disable transitions when AnimateTransitions is false */\n.no-transitions .data-point,\n.no-transitions .selection-ring {\n transition: none;\n}\n\n/* Loading overlay */\n.loading-overlay {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-bg-page) 80%, transparent);\n z-index: 5;\n}\n\n.loading-spinner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n color: var(--mj-text-secondary);\n font-size: 0.9rem;\n}\n\n.loading-spinner i {\n font-size: 2rem;\n color: var(--mj-brand-primary);\n}\n\n/* Empty state \u2014 overlay the full scatter container */\n.empty-state-fill {\n position: absolute;\n inset: 0;\n}\n\n/* Legend */\n.legend {\n position: absolute;\n bottom: 20px;\n left: 20px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(12px);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 14px 18px;\n z-index: 3;\n}\n\n.legend-title {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 0.78rem;\n margin-bottom: 4px;\n color: var(--mj-text-primary);\n cursor: pointer;\n border-radius: 4px;\n padding: 2px 4px;\n margin-left: -4px;\n margin-right: -4px;\n transition: background 0.15s ease;\n}\n\n.legend-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.legend-label {\n flex: 1;\n}\n\n.legend-edit-btn {\n display: none;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n padding: 0;\n border: none;\n background: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.6rem;\n border-radius: 4px;\n transition: color 0.15s ease;\n}\n\n.legend-item:hover .legend-edit-btn {\n display: inline-flex;\n}\n\n.legend-edit-btn:hover {\n color: var(--mj-brand-primary);\n}\n\n.legend-label-input {\n flex: 1;\n padding: 2px 4px;\n border: 1px solid var(--mj-border-focus);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.75rem;\n outline: none;\n min-width: 60px;\n}\n\n.legend-count {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n margin-left: auto;\n padding-left: 16px;\n}\n\n/* Cluster labels on chart */\n.cluster-label {\n font-size: 14px;\n font-weight: 600;\n opacity: 0.85;\n pointer-events: none;\n text-shadow:\n 0 0 6px var(--mj-bg-page),\n 0 0 12px var(--mj-bg-page),\n 1px 1px 2px var(--mj-bg-page);\n}\n\n/* Tooltip */\n.tooltip {\n position: fixed;\n background: color-mix(in srgb, var(--mj-bg-surface-elevated) 96%, transparent);\n backdrop-filter: blur(16px);\n border: 1px solid var(--mj-border-strong);\n border-radius: 10px;\n padding: 14px 16px;\n width: 280px;\n box-shadow: 0 12px 40px color-mix(in srgb, var(--mj-bg-page) 40%, transparent);\n pointer-events: none;\n z-index: 50;\n}\n\n.tt-header {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n margin-bottom: 6px;\n}\n\n.tt-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.tt-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.tt-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-entity {\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n margin-top: 1px;\n}\n\n.tt-cluster {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.tt-fields {\n font-size: 0.72rem;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n}\n\n.tt-field-row {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tt-action {\n margin-top: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-default);\n font-size: 0.7rem;\n color: var(--mj-text-muted);\n}\n\n.tt-action i {\n margin-right: 4px;\n}\n\n/* ================================================================\n Detail Panel (right slide-in)\n ================================================================ */\n\n.detail-panel {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 320px;\n background: color-mix(in srgb, var(--mj-bg-surface) 92%, transparent);\n backdrop-filter: blur(16px);\n border-left: 1px solid var(--mj-border-default);\n z-index: 10;\n display: flex;\n flex-direction: column;\n transform: translateX(100%);\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-bg-page) 30%, transparent);\n overflow: hidden;\n}\n\n.detail-panel-open {\n transform: translateX(0);\n}\n\n/* Header */\n.detail-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 16px 16px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-header-content {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.detail-icon {\n width: 2.25rem;\n height: 2.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.95rem;\n flex-shrink: 0;\n}\n\n.detail-header-text {\n min-width: 0;\n flex: 1;\n}\n\n.detail-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n word-wrap: break-word;\n}\n\n.detail-entity-badge {\n display: inline-block;\n margin-top: 4px;\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 0.68rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.detail-close {\n background: none;\n border: none;\n cursor: pointer;\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n padding: 4px 6px;\n border-radius: 4px;\n transition: color 0.15s ease, background 0.15s ease;\n flex-shrink: 0;\n}\n\n.detail-close:hover {\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Cluster badge */\n.detail-cluster {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n font-size: 0.78rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n}\n\n.detail-cluster-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n/* Metadata fields */\n.detail-fields {\n padding: 4px 16px 8px;\n overflow-y: auto;\n flex-shrink: 0;\n}\n\n.detail-field {\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.detail-field:last-child {\n border-bottom: none;\n}\n\n.detail-field-key {\n font-size: 0.68rem;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 2px;\n}\n\n.detail-field-value {\n font-size: 0.8rem;\n color: var(--mj-text-primary);\n line-height: 1.4;\n word-wrap: break-word;\n}\n\n/* Cluster Members Section */\n.detail-members-section {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n border-top: 1px solid var(--mj-border-default);\n}\n\n/* .detail-members-toggle / .detail-members-count removed: the bespoke\n disclosure toggle + count pill were replaced by <mj-accordion-panel>\n (header/chevron) and the standard .mj-accordion-badge--right. */\n\n.detail-members-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 8px 8px;\n}\n\n.detail-member-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n transition: background 0.12s ease;\n}\n\n.detail-member-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.detail-member-row.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 500;\n}\n\n.detail-member-row .member-icon {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.detail-member-row.active .member-icon {\n color: var(--mj-brand-primary);\n}\n\n.member-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Footer */\n.detail-footer {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.detail-open-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n width: 100%;\n padding: 8px 16px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 0.82rem;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.detail-open-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.detail-open-btn i {\n font-size: 0.75rem;\n}\n\n/* 3D orbit hint + reset */\n.threed-hint {\n position: absolute;\n top: 12px;\n right: 12px;\n z-index: 6;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 5px 8px 5px 10px;\n background: color-mix(in srgb, var(--mj-bg-surface) 88%, transparent);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n backdrop-filter: blur(4px);\n}\n.threed-hint > i { color: var(--mj-brand-primary); }\n.threed-reset {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 22px;\n height: 22px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 6px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n.threed-reset:hover { color: var(--mj-brand-primary); border-color: var(--mj-brand-primary); }\n\n/* 3D cluster labels \u2014 halo for readability over points */\n.cluster-label-3d {\n font-weight: 700;\n font-size: 13px;\n paint-order: stroke;\n stroke: var(--mj-bg-surface);\n stroke-width: 3px;\n stroke-linejoin: round;\n pointer-events: none;\n}\n"] }]
|
|
1593
1587
|
}], null, { Points: [{
|
|
1594
1588
|
type: Input
|
|
1595
1589
|
}], Clusters: [{
|