@bezda/rhp-mcp 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +1 -6
  2. package/skill/recipes/area.html +6 -2
  3. package/skill/recipes/bar.html +6 -2
  4. package/skill/recipes/box-plot.html +6 -2
  5. package/skill/recipes/bubble.html +6 -2
  6. package/skill/recipes/bullet.html +6 -2
  7. package/skill/recipes/candlestick.html +6 -2
  8. package/skill/recipes/column.html +6 -2
  9. package/skill/recipes/dial.html +6 -2
  10. package/skill/recipes/diverging-bars.html +6 -2
  11. package/skill/recipes/donut.html +6 -2
  12. package/skill/recipes/dumbbell.html +6 -2
  13. package/skill/recipes/gantt.html +6 -2
  14. package/skill/recipes/grouped-bars.html +6 -2
  15. package/skill/recipes/heatmap.html +6 -2
  16. package/skill/recipes/histogram.html +6 -2
  17. package/skill/recipes/line.html +6 -2
  18. package/skill/recipes/live.html +6 -2
  19. package/skill/recipes/log-line.html +6 -2
  20. package/skill/recipes/lollipop.html +6 -2
  21. package/skill/recipes/multi-line.html +6 -2
  22. package/skill/recipes/pyramid.html +6 -2
  23. package/skill/recipes/race.html +6 -2
  24. package/skill/recipes/radial-bars.html +6 -2
  25. package/skill/recipes/scatter.html +6 -2
  26. package/skill/recipes/silhouettes.html +6 -2
  27. package/skill/recipes/slope.html +6 -2
  28. package/skill/recipes/sparklines.html +6 -2
  29. package/skill/recipes/stacked-100.html +6 -2
  30. package/skill/recipes/stacked-bars.html +6 -2
  31. package/skill/recipes/strip.html +6 -2
  32. package/skill/recipes/unit-stack.html +6 -2
  33. package/skill/recipes/violin.html +6 -2
  34. package/skill/recipes/waffle.html +6 -2
  35. package/skill/recipes/waterfall.html +6 -2
  36. package/skill/references/download.md +6 -2
@@ -536,6 +536,8 @@ function addPosterDownloads() {
536
536
  event.stopPropagation();
537
537
  });
538
538
  button.addEventListener('mousedown', event => {
539
+ // Pointer activation downloads without taking focus from the selected chart item.
540
+ event.preventDefault();
539
541
  event.stopPropagation();
540
542
  });
541
543
  poster.addEventListener('focusout', event => {
@@ -577,12 +579,14 @@ function addPosterDownloads() {
577
579
  const margins = [...document.styleSheets].map(sheet => {
578
580
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
579
581
  }).join('\n');
582
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
583
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
580
584
  const restoreMargins = (source, clone) => {
581
585
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
582
586
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
583
587
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
584
588
  }
585
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
589
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
586
590
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
587
591
  };
588
592
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -638,7 +642,7 @@ function addPosterDownloads() {
638
642
  node.style.backgroundImage = background;
639
643
  };
640
644
  const blob = await domToBlob(poster, {
641
- scale: 2, style: { margin: '0' },
645
+ scale: 2, style: { margin: '0' }, filter: includeNode,
642
646
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
643
647
  onCloneNode: clone => {
644
648
  restoreMargins(poster, clone);
@@ -195,6 +195,8 @@ function addPosterDownloads() {
195
195
  event.stopPropagation();
196
196
  });
197
197
  button.addEventListener('mousedown', event => {
198
+ // Pointer activation downloads without taking focus from the selected chart item.
199
+ event.preventDefault();
198
200
  event.stopPropagation();
199
201
  });
200
202
  poster.addEventListener('focusout', event => {
@@ -236,12 +238,14 @@ function addPosterDownloads() {
236
238
  const margins = [...document.styleSheets].map(sheet => {
237
239
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
238
240
  }).join('\n');
241
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
242
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
239
243
  const restoreMargins = (source, clone) => {
240
244
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
241
245
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
242
246
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
243
247
  }
244
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
248
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
245
249
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
246
250
  };
247
251
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -297,7 +301,7 @@ function addPosterDownloads() {
297
301
  node.style.backgroundImage = background;
298
302
  };
299
303
  const blob = await domToBlob(poster, {
300
- scale: 2, style: { margin: '0' },
304
+ scale: 2, style: { margin: '0' }, filter: includeNode,
301
305
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
302
306
  onCloneNode: clone => {
303
307
  restoreMargins(poster, clone);
@@ -271,6 +271,8 @@ function addPosterDownloads() {
271
271
  event.stopPropagation();
272
272
  });
273
273
  button.addEventListener('mousedown', event => {
274
+ // Pointer activation downloads without taking focus from the selected chart item.
275
+ event.preventDefault();
274
276
  event.stopPropagation();
275
277
  });
276
278
  poster.addEventListener('focusout', event => {
@@ -312,12 +314,14 @@ function addPosterDownloads() {
312
314
  const margins = [...document.styleSheets].map(sheet => {
313
315
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
314
316
  }).join('\n');
317
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
318
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
315
319
  const restoreMargins = (source, clone) => {
316
320
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
317
321
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
318
322
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
319
323
  }
320
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
324
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
321
325
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
322
326
  };
323
327
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -373,7 +377,7 @@ function addPosterDownloads() {
373
377
  node.style.backgroundImage = background;
374
378
  };
375
379
  const blob = await domToBlob(poster, {
376
- scale: 2, style: { margin: '0' },
380
+ scale: 2, style: { margin: '0' }, filter: includeNode,
377
381
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
378
382
  onCloneNode: clone => {
379
383
  restoreMargins(poster, clone);
@@ -207,6 +207,8 @@ function addPosterDownloads() {
207
207
  event.stopPropagation();
208
208
  });
209
209
  button.addEventListener('mousedown', event => {
210
+ // Pointer activation downloads without taking focus from the selected chart item.
211
+ event.preventDefault();
210
212
  event.stopPropagation();
211
213
  });
212
214
  poster.addEventListener('focusout', event => {
@@ -248,12 +250,14 @@ function addPosterDownloads() {
248
250
  const margins = [...document.styleSheets].map(sheet => {
249
251
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
250
252
  }).join('\n');
253
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
254
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
251
255
  const restoreMargins = (source, clone) => {
252
256
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
253
257
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
254
258
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
255
259
  }
256
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
260
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
257
261
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
258
262
  };
259
263
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -309,7 +313,7 @@ function addPosterDownloads() {
309
313
  node.style.backgroundImage = background;
310
314
  };
311
315
  const blob = await domToBlob(poster, {
312
- scale: 2, style: { margin: '0' },
316
+ scale: 2, style: { margin: '0' }, filter: includeNode,
313
317
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
314
318
  onCloneNode: clone => {
315
319
  restoreMargins(poster, clone);
@@ -321,6 +321,8 @@ function addPosterDownloads() {
321
321
  event.stopPropagation();
322
322
  });
323
323
  button.addEventListener('mousedown', event => {
324
+ // Pointer activation downloads without taking focus from the selected chart item.
325
+ event.preventDefault();
324
326
  event.stopPropagation();
325
327
  });
326
328
  poster.addEventListener('focusout', event => {
@@ -362,12 +364,14 @@ function addPosterDownloads() {
362
364
  const margins = [...document.styleSheets].map(sheet => {
363
365
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
364
366
  }).join('\n');
367
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
368
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
365
369
  const restoreMargins = (source, clone) => {
366
370
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
367
371
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
368
372
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
369
373
  }
370
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
374
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
371
375
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
372
376
  };
373
377
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -423,7 +427,7 @@ function addPosterDownloads() {
423
427
  node.style.backgroundImage = background;
424
428
  };
425
429
  const blob = await domToBlob(poster, {
426
- scale: 2, style: { margin: '0' },
430
+ scale: 2, style: { margin: '0' }, filter: includeNode,
427
431
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
428
432
  onCloneNode: clone => {
429
433
  restoreMargins(poster, clone);
@@ -200,6 +200,8 @@ function addPosterDownloads() {
200
200
  event.stopPropagation();
201
201
  });
202
202
  button.addEventListener('mousedown', event => {
203
+ // Pointer activation downloads without taking focus from the selected chart item.
204
+ event.preventDefault();
203
205
  event.stopPropagation();
204
206
  });
205
207
  poster.addEventListener('focusout', event => {
@@ -241,12 +243,14 @@ function addPosterDownloads() {
241
243
  const margins = [...document.styleSheets].map(sheet => {
242
244
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
243
245
  }).join('\n');
246
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
247
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
244
248
  const restoreMargins = (source, clone) => {
245
249
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
246
250
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
247
251
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
248
252
  }
249
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
253
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
250
254
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
251
255
  };
252
256
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -302,7 +306,7 @@ function addPosterDownloads() {
302
306
  node.style.backgroundImage = background;
303
307
  };
304
308
  const blob = await domToBlob(poster, {
305
- scale: 2, style: { margin: '0' },
309
+ scale: 2, style: { margin: '0' }, filter: includeNode,
306
310
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
307
311
  onCloneNode: clone => {
308
312
  restoreMargins(poster, clone);
@@ -255,6 +255,8 @@ function addPosterDownloads() {
255
255
  event.stopPropagation();
256
256
  });
257
257
  button.addEventListener('mousedown', event => {
258
+ // Pointer activation downloads without taking focus from the selected chart item.
259
+ event.preventDefault();
258
260
  event.stopPropagation();
259
261
  });
260
262
  poster.addEventListener('focusout', event => {
@@ -296,12 +298,14 @@ function addPosterDownloads() {
296
298
  const margins = [...document.styleSheets].map(sheet => {
297
299
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
298
300
  }).join('\n');
301
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
302
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
299
303
  const restoreMargins = (source, clone) => {
300
304
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
301
305
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
302
306
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
303
307
  }
304
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
308
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
305
309
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
306
310
  };
307
311
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -357,7 +361,7 @@ function addPosterDownloads() {
357
361
  node.style.backgroundImage = background;
358
362
  };
359
363
  const blob = await domToBlob(poster, {
360
- scale: 2, style: { margin: '0' },
364
+ scale: 2, style: { margin: '0' }, filter: includeNode,
361
365
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
362
366
  onCloneNode: clone => {
363
367
  restoreMargins(poster, clone);
@@ -397,6 +397,8 @@ function addPosterDownloads() {
397
397
  event.stopPropagation();
398
398
  });
399
399
  button.addEventListener('mousedown', event => {
400
+ // Pointer activation downloads without taking focus from the selected chart item.
401
+ event.preventDefault();
400
402
  event.stopPropagation();
401
403
  });
402
404
  poster.addEventListener('focusout', event => {
@@ -438,12 +440,14 @@ function addPosterDownloads() {
438
440
  const margins = [...document.styleSheets].map(sheet => {
439
441
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
440
442
  }).join('\n');
443
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
444
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
441
445
  const restoreMargins = (source, clone) => {
442
446
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
443
447
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
444
448
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
445
449
  }
446
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
450
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
447
451
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
448
452
  };
449
453
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -499,7 +503,7 @@ function addPosterDownloads() {
499
503
  node.style.backgroundImage = background;
500
504
  };
501
505
  const blob = await domToBlob(poster, {
502
- scale: 2, style: { margin: '0' },
506
+ scale: 2, style: { margin: '0' }, filter: includeNode,
503
507
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
504
508
  onCloneNode: clone => {
505
509
  restoreMargins(poster, clone);
@@ -255,6 +255,8 @@ function addPosterDownloads() {
255
255
  event.stopPropagation();
256
256
  });
257
257
  button.addEventListener('mousedown', event => {
258
+ // Pointer activation downloads without taking focus from the selected chart item.
259
+ event.preventDefault();
258
260
  event.stopPropagation();
259
261
  });
260
262
  poster.addEventListener('focusout', event => {
@@ -296,12 +298,14 @@ function addPosterDownloads() {
296
298
  const margins = [...document.styleSheets].map(sheet => {
297
299
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
298
300
  }).join('\n');
301
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
302
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
299
303
  const restoreMargins = (source, clone) => {
300
304
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
301
305
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
302
306
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
303
307
  }
304
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
308
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
305
309
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
306
310
  };
307
311
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -357,7 +361,7 @@ function addPosterDownloads() {
357
361
  node.style.backgroundImage = background;
358
362
  };
359
363
  const blob = await domToBlob(poster, {
360
- scale: 2, style: { margin: '0' },
364
+ scale: 2, style: { margin: '0' }, filter: includeNode,
361
365
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
362
366
  onCloneNode: clone => {
363
367
  restoreMargins(poster, clone);
@@ -218,6 +218,8 @@ function addPosterDownloads() {
218
218
  event.stopPropagation();
219
219
  });
220
220
  button.addEventListener('mousedown', event => {
221
+ // Pointer activation downloads without taking focus from the selected chart item.
222
+ event.preventDefault();
221
223
  event.stopPropagation();
222
224
  });
223
225
  poster.addEventListener('focusout', event => {
@@ -259,12 +261,14 @@ function addPosterDownloads() {
259
261
  const margins = [...document.styleSheets].map(sheet => {
260
262
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
261
263
  }).join('\n');
264
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
265
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
262
266
  const restoreMargins = (source, clone) => {
263
267
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
264
268
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
265
269
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
266
270
  }
267
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
271
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
268
272
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
269
273
  };
270
274
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -320,7 +324,7 @@ function addPosterDownloads() {
320
324
  node.style.backgroundImage = background;
321
325
  };
322
326
  const blob = await domToBlob(poster, {
323
- scale: 2, style: { margin: '0' },
327
+ scale: 2, style: { margin: '0' }, filter: includeNode,
324
328
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
325
329
  onCloneNode: clone => {
326
330
  restoreMargins(poster, clone);
@@ -201,6 +201,8 @@ function addPosterDownloads() {
201
201
  event.stopPropagation();
202
202
  });
203
203
  button.addEventListener('mousedown', event => {
204
+ // Pointer activation downloads without taking focus from the selected chart item.
205
+ event.preventDefault();
204
206
  event.stopPropagation();
205
207
  });
206
208
  poster.addEventListener('focusout', event => {
@@ -242,12 +244,14 @@ function addPosterDownloads() {
242
244
  const margins = [...document.styleSheets].map(sheet => {
243
245
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
244
246
  }).join('\n');
247
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
248
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
245
249
  const restoreMargins = (source, clone) => {
246
250
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
247
251
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
248
252
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
249
253
  }
250
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
254
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
251
255
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
252
256
  };
253
257
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -303,7 +307,7 @@ function addPosterDownloads() {
303
307
  node.style.backgroundImage = background;
304
308
  };
305
309
  const blob = await domToBlob(poster, {
306
- scale: 2, style: { margin: '0' },
310
+ scale: 2, style: { margin: '0' }, filter: includeNode,
307
311
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
308
312
  onCloneNode: clone => {
309
313
  restoreMargins(poster, clone);
@@ -193,6 +193,8 @@ function addPosterDownloads() {
193
193
  event.stopPropagation();
194
194
  });
195
195
  button.addEventListener('mousedown', event => {
196
+ // Pointer activation downloads without taking focus from the selected chart item.
197
+ event.preventDefault();
196
198
  event.stopPropagation();
197
199
  });
198
200
  poster.addEventListener('focusout', event => {
@@ -234,12 +236,14 @@ function addPosterDownloads() {
234
236
  const margins = [...document.styleSheets].map(sheet => {
235
237
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
236
238
  }).join('\n');
239
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
240
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
237
241
  const restoreMargins = (source, clone) => {
238
242
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
239
243
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
240
244
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
241
245
  }
242
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
246
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
243
247
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
244
248
  };
245
249
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -295,7 +299,7 @@ function addPosterDownloads() {
295
299
  node.style.backgroundImage = background;
296
300
  };
297
301
  const blob = await domToBlob(poster, {
298
- scale: 2, style: { margin: '0' },
302
+ scale: 2, style: { margin: '0' }, filter: includeNode,
299
303
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
300
304
  onCloneNode: clone => {
301
305
  restoreMargins(poster, clone);
@@ -266,6 +266,8 @@ function addPosterDownloads() {
266
266
  event.stopPropagation();
267
267
  });
268
268
  button.addEventListener('mousedown', event => {
269
+ // Pointer activation downloads without taking focus from the selected chart item.
270
+ event.preventDefault();
269
271
  event.stopPropagation();
270
272
  });
271
273
  poster.addEventListener('focusout', event => {
@@ -307,12 +309,14 @@ function addPosterDownloads() {
307
309
  const margins = [...document.styleSheets].map(sheet => {
308
310
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
309
311
  }).join('\n');
312
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
313
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
310
314
  const restoreMargins = (source, clone) => {
311
315
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
312
316
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
313
317
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
314
318
  }
315
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
319
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
316
320
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
317
321
  };
318
322
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -368,7 +372,7 @@ function addPosterDownloads() {
368
372
  node.style.backgroundImage = background;
369
373
  };
370
374
  const blob = await domToBlob(poster, {
371
- scale: 2, style: { margin: '0' },
375
+ scale: 2, style: { margin: '0' }, filter: includeNode,
372
376
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
373
377
  onCloneNode: clone => {
374
378
  restoreMargins(poster, clone);
@@ -319,6 +319,8 @@ function addPosterDownloads() {
319
319
  event.stopPropagation();
320
320
  });
321
321
  button.addEventListener('mousedown', event => {
322
+ // Pointer activation downloads without taking focus from the selected chart item.
323
+ event.preventDefault();
322
324
  event.stopPropagation();
323
325
  });
324
326
  poster.addEventListener('focusout', event => {
@@ -360,12 +362,14 @@ function addPosterDownloads() {
360
362
  const margins = [...document.styleSheets].map(sheet => {
361
363
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
362
364
  }).join('\n');
365
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
366
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
363
367
  const restoreMargins = (source, clone) => {
364
368
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
365
369
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
366
370
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
367
371
  }
368
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
372
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
369
373
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
370
374
  };
371
375
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -421,7 +425,7 @@ function addPosterDownloads() {
421
425
  node.style.backgroundImage = background;
422
426
  };
423
427
  const blob = await domToBlob(poster, {
424
- scale: 2, style: { margin: '0' },
428
+ scale: 2, style: { margin: '0' }, filter: includeNode,
425
429
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
426
430
  onCloneNode: clone => {
427
431
  restoreMargins(poster, clone);
@@ -212,6 +212,8 @@ function addPosterDownloads() {
212
212
  event.stopPropagation();
213
213
  });
214
214
  button.addEventListener('mousedown', event => {
215
+ // Pointer activation downloads without taking focus from the selected chart item.
216
+ event.preventDefault();
215
217
  event.stopPropagation();
216
218
  });
217
219
  poster.addEventListener('focusout', event => {
@@ -253,12 +255,14 @@ function addPosterDownloads() {
253
255
  const margins = [...document.styleSheets].map(sheet => {
254
256
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
255
257
  }).join('\n');
258
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
259
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
256
260
  const restoreMargins = (source, clone) => {
257
261
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
258
262
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
259
263
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
260
264
  }
261
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
265
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
262
266
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
263
267
  };
264
268
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -314,7 +318,7 @@ function addPosterDownloads() {
314
318
  node.style.backgroundImage = background;
315
319
  };
316
320
  const blob = await domToBlob(poster, {
317
- scale: 2, style: { margin: '0' },
321
+ scale: 2, style: { margin: '0' }, filter: includeNode,
318
322
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
319
323
  onCloneNode: clone => {
320
324
  restoreMargins(poster, clone);
@@ -208,6 +208,8 @@ function addPosterDownloads() {
208
208
  event.stopPropagation();
209
209
  });
210
210
  button.addEventListener('mousedown', event => {
211
+ // Pointer activation downloads without taking focus from the selected chart item.
212
+ event.preventDefault();
211
213
  event.stopPropagation();
212
214
  });
213
215
  poster.addEventListener('focusout', event => {
@@ -249,12 +251,14 @@ function addPosterDownloads() {
249
251
  const margins = [...document.styleSheets].map(sheet => {
250
252
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
251
253
  }).join('\n');
254
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
255
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
252
256
  const restoreMargins = (source, clone) => {
253
257
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
254
258
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
255
259
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
256
260
  }
257
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
261
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
258
262
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
259
263
  };
260
264
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -310,7 +314,7 @@ function addPosterDownloads() {
310
314
  node.style.backgroundImage = background;
311
315
  };
312
316
  const blob = await domToBlob(poster, {
313
- scale: 2, style: { margin: '0' },
317
+ scale: 2, style: { margin: '0' }, filter: includeNode,
314
318
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
315
319
  onCloneNode: clone => {
316
320
  restoreMargins(poster, clone);
@@ -170,6 +170,8 @@ function addPosterDownloads() {
170
170
  event.stopPropagation();
171
171
  });
172
172
  button.addEventListener('mousedown', event => {
173
+ // Pointer activation downloads without taking focus from the selected chart item.
174
+ event.preventDefault();
173
175
  event.stopPropagation();
174
176
  });
175
177
  poster.addEventListener('focusout', event => {
@@ -211,12 +213,14 @@ function addPosterDownloads() {
211
213
  const margins = [...document.styleSheets].map(sheet => {
212
214
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
213
215
  }).join('\n');
216
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
217
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
214
218
  const restoreMargins = (source, clone) => {
215
219
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
216
220
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
217
221
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
218
222
  }
219
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
223
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
220
224
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
221
225
  };
222
226
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -272,7 +276,7 @@ function addPosterDownloads() {
272
276
  node.style.backgroundImage = background;
273
277
  };
274
278
  const blob = await domToBlob(poster, {
275
- scale: 2, style: { margin: '0' },
279
+ scale: 2, style: { margin: '0' }, filter: includeNode,
276
280
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
277
281
  onCloneNode: clone => {
278
282
  restoreMargins(poster, clone);
@@ -58,6 +58,8 @@ function addPosterDownloads() {
58
58
  event.stopPropagation();
59
59
  });
60
60
  button.addEventListener('mousedown', event => {
61
+ // Pointer activation downloads without taking focus from the selected chart item.
62
+ event.preventDefault();
61
63
  event.stopPropagation();
62
64
  });
63
65
  poster.addEventListener('focusout', event => {
@@ -99,12 +101,14 @@ function addPosterDownloads() {
99
101
  const margins = [...document.styleSheets].map(sheet => {
100
102
  try { return marginRules(sheet.cssRules); } catch (cause) { return ''; }
101
103
  }).join('\n');
104
+ // Omit display-none HTML subtrees, such as collapsed chart rows, from the image and its SVG payload.
105
+ const includeNode = node => !(node instanceof HTMLElement) || getComputedStyle(node).display !== 'none';
102
106
  const restoreMargins = (source, clone) => {
103
107
  if (clone.style && source !== poster && [...autoMargins].some(selector => source.matches(selector))) {
104
108
  [...clone.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.removeProperty(name));
105
109
  [...source.style].filter(name => name === 'margin' || name.startsWith('margin-')).forEach(name => clone.style.setProperty(name, source.style.getPropertyValue(name), source.style.getPropertyPriority(name)));
106
110
  }
107
- const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName));
111
+ const children = [...source.children].filter(node => !['STYLE', 'SCRIPT'].includes(node.tagName) && includeNode(node));
108
112
  [...clone.children].forEach((child, i) => { if (children[i]) restoreMargins(children[i], child); });
109
113
  };
110
114
  // Cross-origin font stylesheets are readable through fetch, but not through cssRules.
@@ -160,7 +164,7 @@ function addPosterDownloads() {
160
164
  node.style.backgroundImage = background;
161
165
  };
162
166
  const blob = await domToBlob(poster, {
163
- scale: 2, style: { margin: '0' },
167
+ scale: 2, style: { margin: '0' }, filter: includeNode,
164
168
  font: { cssText: fontRules.join('\n') }, onCloneEachNode: embedTexture,
165
169
  onCloneNode: clone => {
166
170
  restoreMargins(poster, clone);