@net7/components 3.8.5 → 3.9.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.
@@ -124,22 +124,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImpor
124
124
  class BubbleChartComponent {
125
125
  constructor() {
126
126
  this._loaded = false;
127
- this.measureWidth = (text) => {
128
- const context = document.createElement('canvas').getContext('2d');
129
- // measure text with the correct font family and weight
130
- if (this.data?.fontRendering?.label?.family && this.data?.fontRendering?.label?.weight) {
131
- context.font = `${this.data.fontRendering.label.weight} ${this.data.fontRendering.label.family}`;
132
- }
133
- return context.measureText(text).width;
134
- };
135
- this.isValidNumber = (value) => !Number.isNaN(Number.parseFloat(value));
136
127
  this.draw = () => {
137
128
  const { d3 } = this;
138
129
  const { containerId, data, height, width, selected, transition, colorMatch, shuffle, fontRendering } = this.data;
139
130
  const closeIconPath = 'M -50,40 L-40,50 0,10 40,50 50,40 10,0 50,-40 40,-50 0,-10 -40,-50 -50,-40 -10,0 -50,40';
140
- const defaultLineHeight = 13;
141
- const ellipsisThreshold = 4; // words
142
- const textScalingFactor = 0.95;
143
131
  if (!Array.isArray(data)) {
144
132
  // Check if it is possible to draw with the current dataset
145
133
  console.warn('(n7-bubble-chart) The data object is not in the expected format!');
@@ -175,23 +163,19 @@ class BubbleChartComponent {
175
163
  const svg = d3
176
164
  .select(`#${containerId}`)
177
165
  .attr('viewBox', [0, 0, width, height])
178
- // .attr('font-family', 'Verdana, Geneva, sans-serif')
179
- // .attr('font-size', '10px')
180
- .style('font', '10px Verdana, Geneva, sans-serif')
181
- .style('height', 'auto')
182
- .style('max-width', '100%')
166
+ .attr('font-family', 'Verdana, Geneva, sans-serif')
183
167
  .attr('text-anchor', 'middle');
184
168
  const leaf = svg.selectAll('g').data(root().leaves(), (d) => d.data.entity.id);
185
169
  leaf
186
170
  .transition(t) // update transition on <g>
187
171
  .attr('fill-opacity', 1)
188
- .attr('transform', (d) => `translate(${d.x + 1},${d.y + 1})`);
189
- // .attr('font-size', (d) => {
190
- // let size = d.r / 5.5;
191
- // size *= 1;
192
- // size += 1;
193
- // return `${Math.round(size)}px`;
194
- // });
172
+ .attr('transform', (d) => `translate(${d.x + 1},${d.y + 1})`)
173
+ .attr('font-size', (d) => {
174
+ let size = d.r / 5.5;
175
+ size *= 1;
176
+ size += 1;
177
+ return `${Math.round(size)}px`;
178
+ });
195
179
  leaf.selectAll('.close-icon').remove(); // clear all existing close icons
196
180
  if (selected) {
197
181
  leaf // render necessary close icons
@@ -212,8 +196,86 @@ class BubbleChartComponent {
212
196
  .transition(t) // update transition on <circle>
213
197
  .attr('fill-opacity', 1)
214
198
  .attr('r', (d) => d.r);
199
+ leaf
200
+ .select('text')
201
+ .attr('font-family', () => {
202
+ if (fontRendering && fontRendering.label && fontRendering.label.family) {
203
+ return fontRendering.label.family;
204
+ }
205
+ return 'inherit';
206
+ })
207
+ .attr('font-weight', () => {
208
+ if (fontRendering && fontRendering.label && fontRendering.label.weight) {
209
+ return fontRendering.label.weight;
210
+ }
211
+ return 'inherit';
212
+ })
213
+ .selectAll('tspan')
214
+ .data((d) => {
215
+ if (d.r / 4 > 4.5) {
216
+ // show text and number threshhold
217
+ let label = (d.data.entity.label.charAt(0).toUpperCase()
218
+ + d.data.entity.label.slice(1)).split(/ +/g);
219
+ if (label.length > 3) {
220
+ label = label.slice(0, 3);
221
+ label[2] += '…';
222
+ }
223
+ return label;
224
+ }
225
+ if (d.r / 4 > 2.5) {
226
+ // show text threshhold
227
+ let label = (d.data.entity.label.charAt(0).toUpperCase()
228
+ + d.data.entity.label.slice(1)).split(/ +/g);
229
+ if (label.length > 3) {
230
+ label = label.slice(0, 3);
231
+ label[2] += '…';
232
+ }
233
+ return label;
234
+ }
235
+ return '';
236
+ })
237
+ .join('tspan')
238
+ .attr('x', 0)
239
+ .attr('y', (d, i, nodes) => `${i - (nodes.length + 1) / 2 + 0.97}em`)
240
+ .attr('fill', 'white')
241
+ .text((d) => d);
242
+ leaf
243
+ .select('.label-count')
244
+ .attr('font-family', () => {
245
+ if (fontRendering && fontRendering.counter && fontRendering.counter.family) {
246
+ return fontRendering.counter.family;
247
+ }
248
+ return 'inherit';
249
+ })
250
+ .attr('font-weight', () => {
251
+ if (fontRendering && fontRendering.counter && fontRendering.counter.weight) {
252
+ return fontRendering.counter.weight;
253
+ }
254
+ return 'inherit';
255
+ })
256
+ .attr('fill', 'white')
257
+ .text((d) => {
258
+ if (d.r / 4 > 2.5) {
259
+ // show text and number threshhold
260
+ return d.data.count;
261
+ }
262
+ return '';
263
+ })
264
+ .attr('y', (d) => {
265
+ let labelLength = d.data.entity.label.split(/ +/g);
266
+ if (labelLength.length > 3) {
267
+ labelLength = labelLength.slice(0, 3);
268
+ }
269
+ return `${labelLength.length - (labelLength.length + 1) / 2 + 0.97}em`;
270
+ });
215
271
  const g = leaf.enter().append('g');
216
272
  g.attr('transform', (d) => `translate(${d.x + 1},${d.y + 1})`)
273
+ .attr('font-size', (d) => {
274
+ let size = d.r / 5.5;
275
+ size *= 1;
276
+ size += 1;
277
+ return `${Math.round(size)}px`;
278
+ })
217
279
  .attr('cursor', 'pointer')
218
280
  .on('click', (event, d) => {
219
281
  this.onClick(d.data.entity.id);
@@ -230,88 +292,6 @@ class BubbleChartComponent {
230
292
  .attr('id', (d) => { d.clipUid = `Clip-${d.data.entity.id}`; })
231
293
  .append('use')
232
294
  .attr('xlink:href', (d) => d.leafUid.href);
233
- // g.append('text')
234
- // .attr('font-family', () => {
235
- // if (fontRendering && fontRendering.label && fontRendering.label.family) {
236
- // return fontRendering.label.family;
237
- // }
238
- // return 'inherit';
239
- // })
240
- // .attr('font-weight', () => {
241
- // if (fontRendering && fontRendering
242
- // && fontRendering.label && fontRendering.label.weight) {
243
- // return fontRendering.label.weight;
244
- // }
245
- // return 'inherit';
246
- // })
247
- // .selectAll('tspan')
248
- // .data((d) => {
249
- // if (d.r / 4 > 4.5) {
250
- // // show text and number threshhold
251
- // let label = (
252
- // d.data.entity.label.charAt(0).toUpperCase()
253
- // + d.data.entity.label.slice(1)
254
- // ).split(/ +/g);
255
- // if (label.length > 3) {
256
- // label = label.slice(0, 3);
257
- // label[2] += '…';
258
- // }
259
- // return label;
260
- // } if (d.r / 4 > 2.5) {
261
- // // show text threshhold
262
- // let label = (
263
- // d.data.entity.label.charAt(0).toUpperCase()
264
- // + d.data.entity.label.slice(1)
265
- // ).split(/ +/g);
266
- // if (label.length > 3) {
267
- // label = label.slice(0, 3);
268
- // label[2] += '…';
269
- // }
270
- // return label;
271
- // }
272
- // return '';
273
- // })
274
- // .join('tspan')
275
- // .attr('x', 0)
276
- // .attr('y', (d, i, nodes) => `${i - (nodes.length + 1) / 2 + 0.97}em`)
277
- // .attr('fill', 'white')
278
- // .text((d) => d)
279
- // .attr('fill-opacity', 0)
280
- // .transition(t) // enter() transition on <tspan>
281
- // .attr('fill-opacity', 1);
282
- // g.append('text') // Count label
283
- // .attr('class', 'label-count')
284
- // .attr('font-family', () => {
285
- // if (fontRendering && fontRendering.counter && fontRendering.counter.family) {
286
- // return fontRendering.counter.family;
287
- // }
288
- // return 'inherit';
289
- // })
290
- // .attr('font-weight', () => {
291
- // if (fontRendering && fontRendering.counter && fontRendering.counter.weight) {
292
- // return fontRendering.counter.weight;
293
- // }
294
- // return 'inherit';
295
- // })
296
- // .attr('fill', 'white')
297
- // .text((d) => {
298
- // if (d.r / 4 > 2.5) {
299
- // // show text and number threshhold
300
- // return d.data.count;
301
- // }
302
- // return '';
303
- // })
304
- // .attr('y', (d) => {
305
- // let labelLength = d.data.entity.label.split(/ +/g);
306
- // if (labelLength.length > 3) {
307
- // labelLength = labelLength.slice(0, 3);
308
- // }
309
- // return `${labelLength.length - (labelLength.length + 1) / 2 + 0.97}em`;
310
- // })
311
- // .attr('fill-opacity', 0)
312
- // .transition(t) // enter() transition on <text>
313
- // .attr('fill-opacity', 1);
314
- /** NEW TEXT LOGIC */
315
295
  g.append('text')
316
296
  .attr('font-family', () => {
317
297
  if (fontRendering && fontRendering.label && fontRendering.label.family) {
@@ -325,83 +305,40 @@ class BubbleChartComponent {
325
305
  }
326
306
  return 'inherit';
327
307
  })
328
- .attr('fill', 'white')
329
- .each((d) => {
330
- // Capitalize the first letter of the label
331
- d.data.entity.label = d.data.entity
332
- .label.charAt(0).toUpperCase()
333
- + d.data.entity.label.slice(1);
334
- // 1. initialize meta object
335
- if (!d._meta || typeof d._meta !== 'object')
336
- d._meta = {};
337
- // 2. tokenize label & count into words
338
- const words = d.data.entity.label.split(/\s+/g); // To hyphenate: /\s+|(?<=-)/
339
- // Truncate with ellipsis if the label is longer than the threshold
340
- if (words.length > ellipsisThreshold) {
341
- words.splice(ellipsisThreshold, words.length - ellipsisThreshold);
342
- words[ellipsisThreshold - 1] += '…';
343
- }
344
- // add counter
345
- if (d.r / 4 > 2.5) {
346
- // show text threshold
347
- if (!words[words.length - 1])
348
- words.pop();
349
- if (!words[0])
350
- words.shift();
351
- }
308
+ .selectAll('tspan')
309
+ .data((d) => {
352
310
  if (d.r / 4 > 4.5) {
353
- // show number threshold
354
- words.push(`${d.data.count}`);
355
- }
356
- d._meta.words = words;
357
- d._meta.lineHeight = defaultLineHeight;
358
- const targetWidth = Math.sqrt(this.measureWidth(d._meta.words.join(' ').trim()) * defaultLineHeight);
359
- // 3. build lines of text
360
- d._meta.lines = [];
361
- let line;
362
- let lineWidth0 = Infinity;
363
- for (let i = 0, n = d._meta.words.length; i < n; i += 1) {
364
- const lineText1 = (line ? `${line.text} ` : '') + words[i];
365
- const lineWidth1 = this.measureWidth(lineText1);
366
- if ((lineWidth0 + lineWidth1) / 2 < targetWidth && i !== n - 1) {
367
- line.width = lineWidth0;
368
- lineWidth0 = lineWidth1;
369
- line.text = lineText1;
370
- }
371
- else {
372
- // if line is too long or this is the last line (counter), push to next line
373
- lineWidth0 = this.measureWidth(words[i]);
374
- line = { width: lineWidth0, text: words[i] };
375
- d._meta.lines.push(line);
311
+ // show text and number threshhold
312
+ let label = (d.data.entity.label.charAt(0).toUpperCase()
313
+ + d.data.entity.label.slice(1)).split(/ +/g);
314
+ if (label.length > 3) {
315
+ label = label.slice(0, 3);
316
+ label[2] += '';
376
317
  }
318
+ return label;
377
319
  }
378
- // 4. compute the bounding radius
379
- let radius = 0;
380
- for (let i = 0, n = d._meta.lines.length; i < n; i += 1) {
381
- const dy = (Math.abs(i - n / 2) + 0.8) * d._meta.lineHeight;
382
- const dx = d._meta.lines[i].width / 2;
383
- radius = Math.max(radius, Math.sqrt(dx * dx + dy * dy));
320
+ if (d.r / 4 > 2.5) {
321
+ // show text threshhold
322
+ let label = (d.data.entity.label.charAt(0).toUpperCase()
323
+ + d.data.entity.label.slice(1)).split(/ +/g);
324
+ if (label.length > 3) {
325
+ label = label.slice(0, 3);
326
+ label[2] += '…';
327
+ }
328
+ return label;
384
329
  }
385
- d._meta.textRadius = radius;
386
- return d;
330
+ return '';
387
331
  })
388
- .attr('transform', (d) => `scale(${(d.r / d._meta.textRadius) * textScalingFactor})`)
389
- .filter((d) => (d.r / 4 > 2.5))
390
- .selectAll('tspan')
391
- .data((d) => d._meta.lines)
392
- .enter()
393
- .append('tspan')
332
+ .join('tspan')
394
333
  .attr('x', 0)
395
- .attr('y', (d, i, n) => (i - n.length / 2 + 0.8) * defaultLineHeight)
396
- .attr('class', (d, i, n) => (
397
- // if it's the last label and a valid number, mark as counter
398
- i === n.length - 1 && this.isValidNumber(d.text) ? 'label-counter' : 'label-text'))
399
- .text((d) => d.text)
334
+ .attr('y', (d, i, nodes) => `${i - (nodes.length + 1) / 2 + 0.97}em`)
335
+ .attr('fill', 'white')
336
+ .text((d) => d)
400
337
  .attr('fill-opacity', 0)
401
338
  .transition(t) // enter() transition on <tspan>
402
339
  .attr('fill-opacity', 1);
403
- // custom style for the counter
404
- g.selectAll('tspan.label-counter')
340
+ g.append('text') // Count label
341
+ .attr('class', 'label-count')
405
342
  .attr('font-family', () => {
406
343
  if (fontRendering && fontRendering.counter && fontRendering.counter.family) {
407
344
  return fontRendering.counter.family;
@@ -413,7 +350,25 @@ class BubbleChartComponent {
413
350
  return fontRendering.counter.weight;
414
351
  }
415
352
  return 'inherit';
416
- });
353
+ })
354
+ .attr('fill', 'white')
355
+ .text((d) => {
356
+ if (d.r / 4 > 2.5) {
357
+ // show text and number threshhold
358
+ return d.data.count;
359
+ }
360
+ return '';
361
+ })
362
+ .attr('y', (d) => {
363
+ let labelLength = d.data.entity.label.split(/ +/g);
364
+ if (labelLength.length > 3) {
365
+ labelLength = labelLength.slice(0, 3);
366
+ }
367
+ return `${labelLength.length - (labelLength.length + 1) / 2 + 0.97}em`;
368
+ })
369
+ .attr('fill-opacity', 0)
370
+ .transition(t) // enter() transition on <text>
371
+ .attr('fill-opacity', 1);
417
372
  leaf
418
373
  .exit() // EXIT CYCLE
419
374
  .remove();