@toclocoinc/lattice-grid 1.65.0 → 1.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +6 -4
  2. package/angular/LICENSE +111 -0
  3. package/angular/README.md +78 -0
  4. package/angular/fesm2022/toclocoinc-lattice-grid-angular.mjs +2843 -0
  5. package/angular/package.json +16 -0
  6. package/angular/types/toclocoinc-lattice-grid-angular.d.ts +1366 -0
  7. package/docs/API.html +741 -27
  8. package/docs/api-detail.html +137 -4
  9. package/lattice-grid.d.ts +9 -6
  10. package/lattice-grid.esm.min.js +26 -10
  11. package/lattice-grid.min.cjs +26 -10
  12. package/lattice-grid.min.css +1 -1
  13. package/lattice-grid.min.js +26 -10
  14. package/modules/ai.d.ts +1 -1
  15. package/modules/ai.esm.min.js +3 -3
  16. package/modules/ai.min.cjs +3 -3
  17. package/modules/ai.min.js +3 -3
  18. package/modules/angular.d.ts +1 -1
  19. package/modules/angular.esm.min.js +7 -7
  20. package/modules/angular.min.cjs +7 -7
  21. package/modules/angular.min.js +7 -7
  22. package/modules/chart-alluvial.d.ts +1 -1
  23. package/modules/chart-alluvial.esm.min.js +1 -1
  24. package/modules/chart-alluvial.min.cjs +1 -1
  25. package/modules/chart-alluvial.min.js +1 -1
  26. package/modules/chart-arc.d.ts +1 -1
  27. package/modules/chart-arc.esm.min.js +1 -1
  28. package/modules/chart-arc.min.cjs +1 -1
  29. package/modules/chart-arc.min.js +1 -1
  30. package/modules/chart-bubblemap.d.ts +1 -1
  31. package/modules/chart-bubblemap.esm.min.js +1 -1
  32. package/modules/chart-bubblemap.min.cjs +1 -1
  33. package/modules/chart-bubblemap.min.js +1 -1
  34. package/modules/chart-bump.d.ts +1 -1
  35. package/modules/chart-bump.esm.min.js +1 -1
  36. package/modules/chart-bump.min.cjs +1 -1
  37. package/modules/chart-bump.min.js +1 -1
  38. package/modules/chart-calendar.d.ts +1 -1
  39. package/modules/chart-calendar.esm.min.js +1 -1
  40. package/modules/chart-calendar.min.cjs +1 -1
  41. package/modules/chart-calendar.min.js +1 -1
  42. package/modules/chart-decomposition.d.ts +1 -1
  43. package/modules/chart-decomposition.esm.min.js +1 -1
  44. package/modules/chart-decomposition.min.cjs +1 -1
  45. package/modules/chart-decomposition.min.js +1 -1
  46. package/modules/chart-diverging.d.ts +1 -1
  47. package/modules/chart-diverging.esm.min.js +1 -1
  48. package/modules/chart-diverging.min.cjs +1 -1
  49. package/modules/chart-diverging.min.js +1 -1
  50. package/modules/chart-dumbbell.d.ts +1 -1
  51. package/modules/chart-dumbbell.esm.min.js +1 -1
  52. package/modules/chart-dumbbell.min.cjs +1 -1
  53. package/modules/chart-dumbbell.min.js +1 -1
  54. package/modules/chart-fan.d.ts +1 -1
  55. package/modules/chart-fan.esm.min.js +1 -1
  56. package/modules/chart-fan.min.cjs +1 -1
  57. package/modules/chart-fan.min.js +1 -1
  58. package/modules/chart-hexbin.d.ts +1 -1
  59. package/modules/chart-hexbin.esm.min.js +1 -1
  60. package/modules/chart-hexbin.min.cjs +1 -1
  61. package/modules/chart-hexbin.min.js +1 -1
  62. package/modules/chart-hexmap.d.ts +1 -1
  63. package/modules/chart-hexmap.esm.min.js +1 -1
  64. package/modules/chart-hexmap.min.cjs +1 -1
  65. package/modules/chart-hexmap.min.js +1 -1
  66. package/modules/chart-icicle.d.ts +1 -1
  67. package/modules/chart-icicle.esm.min.js +1 -1
  68. package/modules/chart-icicle.min.cjs +1 -1
  69. package/modules/chart-icicle.min.js +1 -1
  70. package/modules/chart-markermap.d.ts +1 -1
  71. package/modules/chart-markermap.esm.min.js +1 -1
  72. package/modules/chart-markermap.min.cjs +1 -1
  73. package/modules/chart-markermap.min.js +1 -1
  74. package/modules/chart-parallel.d.ts +1 -1
  75. package/modules/chart-parallel.esm.min.js +1 -1
  76. package/modules/chart-parallel.min.cjs +1 -1
  77. package/modules/chart-parallel.min.js +1 -1
  78. package/modules/chart-ridgeline.d.ts +1 -1
  79. package/modules/chart-ridgeline.esm.min.js +1 -1
  80. package/modules/chart-ridgeline.min.cjs +1 -1
  81. package/modules/chart-ridgeline.min.js +1 -1
  82. package/modules/chart-roc.d.ts +1 -1
  83. package/modules/chart-roc.esm.min.js +1 -1
  84. package/modules/chart-roc.min.cjs +1 -1
  85. package/modules/chart-roc.min.js +1 -1
  86. package/modules/chart-slope.d.ts +1 -1
  87. package/modules/chart-slope.esm.min.js +1 -1
  88. package/modules/chart-slope.min.cjs +1 -1
  89. package/modules/chart-slope.min.js +1 -1
  90. package/modules/chart-splom.d.ts +1 -1
  91. package/modules/chart-splom.esm.min.js +1 -1
  92. package/modules/chart-splom.min.cjs +1 -1
  93. package/modules/chart-splom.min.js +1 -1
  94. package/modules/chart-waffle.d.ts +1 -1
  95. package/modules/chart-waffle.esm.min.js +1 -1
  96. package/modules/chart-waffle.min.cjs +1 -1
  97. package/modules/chart-waffle.min.js +1 -1
  98. package/modules/charts.d.ts +1 -1
  99. package/modules/charts.esm.min.js +261 -48
  100. package/modules/charts.min.cjs +261 -48
  101. package/modules/charts.min.js +261 -48
  102. package/modules/data-router.d.ts +8 -3
  103. package/modules/data-router.esm.min.js +28 -6
  104. package/modules/data-router.min.cjs +28 -6
  105. package/modules/data-router.min.js +28 -6
  106. package/modules/devtools.d.ts +1 -1
  107. package/modules/devtools.esm.min.js +1 -1
  108. package/modules/devtools.min.cjs +1 -1
  109. package/modules/devtools.min.js +1 -1
  110. package/modules/dhtmlx-compat.d.ts +1 -1
  111. package/modules/dhtmlx-compat.esm.min.js +3 -3
  112. package/modules/dhtmlx-compat.min.cjs +3 -3
  113. package/modules/dhtmlx-compat.min.js +3 -3
  114. package/modules/gantt.d.ts +8 -3
  115. package/modules/gantt.esm.min.js +27 -4
  116. package/modules/gantt.min.cjs +27 -4
  117. package/modules/gantt.min.js +27 -4
  118. package/modules/geo-europe-nuts.d.ts +1 -1
  119. package/modules/geo-europe-nuts.esm.min.js +1 -1
  120. package/modules/geo-uk.d.ts +1 -1
  121. package/modules/geo-uk.esm.min.js +1 -1
  122. package/modules/geo-us-states.d.ts +1 -1
  123. package/modules/geo-us-states.esm.min.js +1 -1
  124. package/modules/geo-world-110m.d.ts +1 -1
  125. package/modules/geo-world-110m.esm.min.js +1 -1
  126. package/modules/geo-world-50m.d.ts +1 -1
  127. package/modules/geo-world-50m.esm.min.js +1 -1
  128. package/modules/htmx.d.ts +1 -1
  129. package/modules/htmx.esm.min.js +26 -10
  130. package/modules/htmx.min.cjs +26 -10
  131. package/modules/htmx.min.js +26 -10
  132. package/modules/kanban.d.ts +10 -3
  133. package/modules/kanban.esm.min.js +24 -4
  134. package/modules/kanban.min.cjs +24 -4
  135. package/modules/kanban.min.js +24 -4
  136. package/modules/kpi.d.ts +10 -3
  137. package/modules/kpi.esm.min.js +27 -4
  138. package/modules/kpi.min.cjs +27 -4
  139. package/modules/kpi.min.js +27 -4
  140. package/modules/layout.d.ts +1 -1
  141. package/modules/layout.esm.min.js +3 -3
  142. package/modules/layout.min.cjs +3 -3
  143. package/modules/layout.min.js +3 -3
  144. package/modules/mock-socket.d.ts +1 -1
  145. package/modules/mock-socket.esm.min.js +1 -1
  146. package/modules/mock-socket.min.cjs +1 -1
  147. package/modules/mock-socket.min.js +1 -1
  148. package/modules/react.d.ts +1 -1
  149. package/modules/react.esm.min.js +3 -3
  150. package/modules/react.min.cjs +3 -3
  151. package/modules/react.min.js +3 -3
  152. package/modules/svelte.d.ts +251 -2
  153. package/modules/svelte.esm.min.js +960 -6
  154. package/modules/svelte.min.cjs +942 -5
  155. package/modules/svelte.min.js +942 -5
  156. package/modules/tabs.d.ts +1 -1
  157. package/modules/tabs.esm.min.js +3 -3
  158. package/modules/tabs.min.cjs +3 -3
  159. package/modules/tabs.min.js +3 -3
  160. package/modules/vue.d.ts +398 -9
  161. package/modules/vue.esm.min.js +1163 -31
  162. package/modules/vue.min.cjs +1147 -30
  163. package/modules/vue.min.js +1147 -30
  164. package/modules/webcomponent.d.ts +233 -1
  165. package/modules/webcomponent.esm.min.js +1274 -41
  166. package/modules/webcomponent.min.cjs +1256 -41
  167. package/modules/webcomponent.min.js +1256 -41
  168. package/package.json +27 -2
  169. package/svelte/Chart.svelte +34 -0
  170. package/svelte/Gantt.svelte +34 -0
  171. package/svelte/Grid.svelte +30 -0
  172. package/svelte/GridProvider.svelte +13 -0
  173. package/svelte/KPI.svelte +34 -0
  174. package/svelte/Kanban.svelte +34 -0
  175. package/svelte/Layout.svelte +34 -0
  176. package/svelte/Router.svelte +16 -0
  177. package/svelte/Tabs.svelte +53 -0
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.65.0, charts module
2
+ * Lattice Grid 1.67.0, charts module
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -245,9 +245,10 @@ bottom:top+height,
245
245
  gutter:{left,bottom,right,top},
246
246
  };
247
247
  }
248
- function shouldRotate(labels,slot,fontSize){
248
+ function shouldRotate(labels,slot,fontSize,every){
249
249
  if(!labels.length||slot<=0)return false;
250
- return widestLabel(labels,fontSize)>slot-4;
250
+ const step=Number.isFinite(every)&&every>0?Number(every):1;
251
+ return widestLabel(labels,fontSize)>slot*step-4;
251
252
  }
252
253
  class Pool{
253
254
  #parent;
@@ -569,7 +570,7 @@ return`
569
570
  max-width:40%;overflow:auto;padding:4px 8px}
570
571
  .${NS}__legend[data-position="left"]{order:-1}
571
572
  .${NS}__legend-more{align-self:center;color:var(--lattice-foreground-muted,#5b6670)}
572
- .${NS}__tooltip{position:absolute;z-index:5;pointer-events:none;max-width:260px;
573
+ .${NS}__tooltip{position:fixed;z-index:5;pointer-events:none;max-width:260px;
573
574
  padding:5px 8px;border-radius:4px;font-size:var(--lattice-font-size-sm,11px);
574
575
  background:var(--lattice-surface,#f7f8f9);color:var(--lattice-foreground,#1c2126);
575
576
  border:1px solid var(--lattice-border-color,#dfe3e6);
@@ -641,6 +642,7 @@ Object.defineProperty(__exports,"normaliseAxes",{enumerable:true,get:function(){
641
642
  Object.defineProperty(__exports,"tickValues",{enumerable:true,get:function(){return tickValues;}});
642
643
  Object.defineProperty(__exports,"tickLabeller",{enumerable:true,get:function(){return tickLabeller;}});
643
644
  Object.defineProperty(__exports,"drawAxisTitle",{enumerable:true,get:function(){return drawAxisTitle;}});
645
+ Object.defineProperty(__exports,"labelEvery",{enumerable:true,get:function(){return labelEvery;}});
644
646
  Object.defineProperty(__exports,"drawMeasureAxis",{enumerable:true,get:function(){return drawMeasureAxis;}});
645
647
  Object.defineProperty(__exports,"drawCategoryAxis",{enumerable:true,get:function(){return drawCategoryAxis;}});
646
648
  Object.defineProperty(__exports,"leftLabelRoom",{enumerable:true,get:function(){return leftLabelRoom;}});
@@ -661,6 +663,7 @@ const setText=__m1["setText"];
661
663
  const svg=__m1["svg"];
662
664
  const __m2=__req("packages/modules/charts/typography.js");
663
665
  const applySize=__m2["applySize"];
666
+ const CHAR_RATIO=__m2["CHAR_RATIO"];
664
667
  const truncateTo=__m2["truncateTo"];
665
668
  const __m3=__req("packages/modules/charts/styles.js");
666
669
  const NS=__m3["NS"];
@@ -698,6 +701,13 @@ return fallback.tick;
698
701
  }
699
702
  function drawAxisTitle(opts){
700
703
  if(!opts.text)return;
704
+ const band=opts.side==='left'||opts.side==='right'
705
+ ?opts.plot.height
706
+ :opts.plot.width;
707
+ const shown=Number.isFinite(band)
708
+ ?truncateTo(String(opts.text),Math.max(0,band),opts.size)
709
+ :String(opts.text);
710
+ if(!shown||shown==='…')return;
701
711
  const node=svg(opts.group.ownerDocument,'text',{class:`${NS}__axis-title`});
702
712
  applySize(node,opts.size);
703
713
  if(opts.side==='left'){
@@ -721,28 +731,55 @@ y:round(opts.plot.bottom+opts.plot.gutter.bottom-2),
721
731
  'text-anchor':'middle',
722
732
  });
723
733
  }
724
- setText(node,opts.text);
734
+ setText(node,shown);
735
+ if(shown!==String(opts.text))node.setAttribute('aria-label',String(opts.text));
725
736
  opts.group.appendChild(node);
726
737
  }
738
+ function labelEvery(opts){
739
+ const{values,scale,size,horizontal,label}=opts;
740
+ if(values.length<2)return 1;
741
+ let pitch=Infinity;
742
+ for(let i=1;i<values.length;i++){
743
+ const gap=Math.abs(scale.of(values[i])-scale.of(values[i-1]));
744
+ if(Number.isFinite(gap)&&gap<pitch)pitch=gap;
745
+ }
746
+ if(!Number.isFinite(pitch))return 1;
747
+ if(pitch<=0)return values.length;
748
+ let needed=size*LINE_HEIGHT+2;
749
+ if(horizontal){
750
+ let widest=0;
751
+ for(const value of values){
752
+ const width=String(label(value)||'').length*size*CHAR_RATIO;
753
+ if(width>widest)widest=width;
754
+ }
755
+ needed=widest+GAP;
756
+ }
757
+ return Math.max(1,Math.ceil(needed/pitch));
758
+ }
727
759
  function drawMeasureAxis(opts){
728
760
  const{gridGroup,axisGroup,plot,scale,format}=opts;
729
761
  const config=opts.config||{};
730
762
  const values=tickValues(scale,config);
731
763
  const label=tickLabeller(config,format,opts.grid);
732
764
  const size=opts.size||11;
765
+ const every=labelEvery({
766
+ values,scale,size,horizontal:!!opts.horizontal,label,
767
+ });
733
768
  const lines=config.grid===false?null:gridGroup;
734
769
  const grid=lines?new Pool(lines):null;
735
770
  const labels=new Pool(axisGroup);
736
- for(const value of values){
771
+ for(let i=0;i<values.length;i++){
772
+ const value=values[i];
737
773
  const at=round(scale.of(value));
738
774
  const zero=value===0;
775
+ const thinned=i%every!==0;
739
776
  if(opts.horizontal){
740
777
  if(grid)attrs(grid.next('line',`${NS}__gridline`),{
741
778
  x1:at,x2:at,y1:round(plot.top),y2:round(plot.bottom),
742
779
  'stroke-opacity':zero?1:0.6,
743
780
  'stroke-width':zero?1.5:1,
744
781
  });
745
- if(config.labels===false)continue;
782
+ if(config.labels===false||thinned)continue;
746
783
  const text=labels.next('text',`${NS}__tick`);
747
784
  applySize(text,size);
748
785
  attrs(text,{
@@ -756,7 +793,7 @@ x1:round(plot.left),x2:round(plot.right),y1:at,y2:at,
756
793
  'stroke-opacity':zero?1:0.6,
757
794
  'stroke-width':zero?1.5:1,
758
795
  });
759
- if(config.labels===false)continue;
796
+ if(config.labels===false||thinned)continue;
760
797
  const text=labels.next('text',`${NS}__tick`);
761
798
  applySize(text,size);
762
799
  attrs(text,{
@@ -2583,12 +2620,12 @@ Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){r
2583
2620
  Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
2584
2621
  Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
2585
2622
  Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
2586
- const STAMPED_VERSION="1.65.0";
2623
+ const STAMPED_VERSION="1.67.0";
2587
2624
  async function resolveVersion(){
2588
2625
  if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
2589
2626
  return STAMPED_VERSION;
2590
2627
  }
2591
- const VERSION="1.65.0";
2628
+ const VERSION="1.67.0";
2592
2629
  const warned=new Set();
2593
2630
  const WARNED_LIMIT=2000;
2594
2631
  function rememberWarned(key){
@@ -2959,6 +2996,8 @@ Object.defineProperty(__exports,"drawBoundErrorBars",{enumerable:true,get:functi
2959
2996
  Object.defineProperty(__exports,"drawForest",{enumerable:true,get:function(){return drawForest;}});
2960
2997
  Object.defineProperty(__exports,"drawReferenceLines",{enumerable:true,get:function(){return drawReferenceLines;}});
2961
2998
  Object.defineProperty(__exports,"drawCartesian",{enumerable:true,get:function(){return drawCartesian;}});
2999
+ Object.defineProperty(__exports,"HIT_TOLERANCE",{enumerable:true,get:function(){return HIT_TOLERANCE;}});
3000
+ Object.defineProperty(__exports,"nearestDrawnPoint",{enumerable:true,get:function(){return nearestDrawnPoint;}});
2962
3001
  Object.defineProperty(__exports,"nearestCategory",{enumerable:true,get:function(){return nearestCategory;}});
2963
3002
  Object.defineProperty(__exports,"categoryKeyAt",{enumerable:true,get:function(){return categoryKeyAt;}});
2964
3003
  const __m0=__req("packages/modules/charts/axis.js");
@@ -3779,7 +3818,7 @@ plot,
3779
3818
  scale:xScale,
3780
3819
  labels:bound.labels,
3781
3820
  fontSize:type_.small,
3782
- rotated:shouldRotate(bound.labels,xScale.step,type_.small),
3821
+ rotated:shouldRotate(bound.labels,xScale.step,type_.small,axisConfig.x.every),
3783
3822
  config:axisConfig.x,
3784
3823
  });
3785
3824
  }else{
@@ -3830,11 +3869,16 @@ group:ctx.groups.axis,plot,text:leftSeries[0].label,side:'left',size:type_.axisT
3830
3869
  const target=Number.isFinite(ctx.downsampleTo)
3831
3870
  ?Number(ctx.downsampleTo)
3832
3871
  :Math.max(2,Math.round(plot.width));
3872
+ let reduced=false;
3833
3873
  if(shape.marks==='path'||type==='scatter'||type==='bubble'){
3834
3874
  for(const series of visible){
3875
+ series.kept=null;
3835
3876
  if(series.points.length>target*1.5){
3836
3877
  const indexed=series.points.map((point,i)=>({x:i,y:point.y,point}));
3837
- series.points=downsample(indexed,target).map((entry)=>entry.point);
3878
+ const picked=downsample(indexed,target);
3879
+ series.points=picked.map((entry)=>entry.point);
3880
+ series.kept=picked.map((entry)=>entry.x);
3881
+ reduced=true;
3838
3882
  }
3839
3883
  }
3840
3884
  }
@@ -4024,8 +4068,42 @@ plot,
4024
4068
  errorBars,
4025
4069
  annotations:describedAll,
4026
4070
  trendlines,
4071
+ reduced,
4027
4072
  };
4028
4073
  }
4074
+ const HIT_TOLERANCE=32;
4075
+ function nearestDrawnPoint(opts){
4076
+ const{series,xScale,at}=opts;
4077
+ const tolerance=Number.isFinite(opts.tolerance)?Number(opts.tolerance):HIT_TOLERANCE;
4078
+ const entries=[];
4079
+ let index=-1;
4080
+ let best=Infinity;
4081
+ for(const one of series){
4082
+ let near=null;
4083
+ let nearAt=-1;
4084
+ let nearest=Infinity;
4085
+ const points=one.points||[];
4086
+ for(let i=0;i<points.length;i++){
4087
+ const point=points[i];
4088
+ if(!point||!isNumber(point.y))continue;
4089
+ const px=xOf(xScale,point);
4090
+ if(Number.isNaN(px))continue;
4091
+ const distance=Math.abs(px-at);
4092
+ if(distance>=nearest)continue;
4093
+ nearest=distance;
4094
+ near=point;
4095
+ nearAt=Array.isArray(one.kept)?one.kept[i]:i;
4096
+ }
4097
+ if(!near||nearest>tolerance)continue;
4098
+ entries.push({series:one,point:near});
4099
+ if(nearest<best){
4100
+ best=nearest;
4101
+ index=nearAt;
4102
+ }
4103
+ }
4104
+ if(index<0)return null;
4105
+ return{index,entries};
4106
+ }
4029
4107
  function nearestCategory(opts){
4030
4108
  const{bound,xScale,at}=opts;
4031
4109
  if(!bound.categories.length)return-1;
@@ -4817,6 +4895,8 @@ __def("packages/modules/charts/distribution.js",function(__exports,__req){
4817
4895
  Object.defineProperty(__exports,"FENCE",{enumerable:true,get:function(){return FENCE;}});
4818
4896
  Object.defineProperty(__exports,"quantile",{enumerable:true,get:function(){return quantile;}});
4819
4897
  Object.defineProperty(__exports,"summarise",{enumerable:true,get:function(){return summarise;}});
4898
+ Object.defineProperty(__exports,"binEdge",{enumerable:true,get:function(){return binEdge;}});
4899
+ Object.defineProperty(__exports,"outsideDomain",{enumerable:true,get:function(){return outsideDomain;}});
4820
4900
  Object.defineProperty(__exports,"histogram",{enumerable:true,get:function(){return histogram;}});
4821
4901
  Object.defineProperty(__exports,"readingsOf",{enumerable:true,get:function(){return readingsOf;}});
4822
4902
  Object.defineProperty(__exports,"valuesByCategory",{enumerable:true,get:function(){return valuesByCategory;}});
@@ -4839,6 +4919,7 @@ const drawAxisLines=__m1["drawAxisLines"];
4839
4919
  const drawCategoryAxis=__m1["drawCategoryAxis"];
4840
4920
  const drawContinuousAxis=__m1["drawContinuousAxis"];
4841
4921
  const drawMeasureAxis=__m1["drawMeasureAxis"];
4922
+ const tickLabeller=__m1["tickLabeller"];
4842
4923
  const __m2=__req("packages/modules/charts/format.js");
4843
4924
  const formatters=__m2["formatters"];
4844
4925
  const __m3=__req("packages/modules/charts/scale.js");
@@ -4859,6 +4940,7 @@ const __m7=__req("packages/modules/charts/labels.js");
4859
4940
  const drawAnchoredLabels=__m7["drawAnchoredLabels"];
4860
4941
  const labelText=__m7["labelText"];
4861
4942
  const FENCE=1.5;
4943
+ const DASH='\u2013';
4862
4944
  function quantile(sorted,p){
4863
4945
  const n=sorted.length;
4864
4946
  if(!n)return NaN;
@@ -4898,18 +4980,42 @@ outliers:sorted.filter((v)=>v<lowFence||v>highFence),
4898
4980
  count:sorted.length,
4899
4981
  };
4900
4982
  }
4901
- function histogram(values,buckets=12){
4983
+ function binEdge(first,step,i){
4984
+ const v=first+i*step;
4985
+ return Math.abs(v)<step/1e6?0:Number(v.toPrecision(12));
4986
+ }
4987
+ function outsideDomain(values,domain){
4988
+ const declared=domain||{};
4989
+ const hasMin=isNumber(declared.min);
4990
+ const hasMax=isNumber(declared.max);
4991
+ if(!hasMin&&!hasMax)return 0;
4992
+ let out=0;
4993
+ for(let i=0;i<values.length;i++){
4994
+ const v=values[i];
4995
+ if(!isNumber(v))continue;
4996
+ if((hasMin&&v<declared.min)||(hasMax&&v>declared.max))out++;
4997
+ }
4998
+ return out;
4999
+ }
5000
+ function histogram(values,buckets=12,domain){
5001
+ const declared=domain||{};
5002
+ const hasMin=isNumber(declared.min);
5003
+ const hasMax=isNumber(declared.max);
4902
5004
  let min=Infinity;
4903
5005
  let max=-Infinity;
4904
5006
  let count=0;
4905
5007
  for(let i=0;i<values.length;i++){
4906
5008
  const v=values[i];
4907
5009
  if(!isNumber(v))continue;
5010
+ if(hasMin&&v<declared.min)continue;
5011
+ if(hasMax&&v>declared.max)continue;
4908
5012
  if(v<min)min=v;
4909
5013
  if(v>max)max=v;
4910
5014
  count++;
4911
5015
  }
4912
5016
  if(!count)return[];
5017
+ if(hasMin)min=Number(declared.min);
5018
+ if(hasMax)max=Number(declared.max);
4913
5019
  if(min===max){
4914
5020
  const pad=Math.abs(min)>0?Math.abs(min)/10:0.5;
4915
5021
  min-=pad;
@@ -4919,13 +5025,15 @@ const step=niceStep((max-min)/Math.max(1,buckets));
4919
5025
  const first=Math.floor(min/step)*step;
4920
5026
  const last=Math.ceil(max/step)*step;
4921
5027
  const out=[];
4922
- for(let edge=first;edge<last-step/1e6;edge+=step){
4923
- out.push({from:Number(edge.toPrecision(12)),to:Number((edge+step).toPrecision(12)),count:0});
5028
+ const bins=Math.max(1,Math.round((last-first)/step));
5029
+ for(let i=0;i<bins;i++){
5030
+ out.push({from:binEdge(first,step,i),to:binEdge(first,step,i+1),count:0});
4924
5031
  }
4925
- if(!out.length)out.push({from:first,to:first+step,count:0});
4926
5032
  for(let i=0;i<values.length;i++){
4927
5033
  const v=values[i];
4928
5034
  if(!isNumber(v))continue;
5035
+ if(hasMin&&v<declared.min)continue;
5036
+ if(hasMax&&v>declared.max)continue;
4929
5037
  let index=Math.floor((v-first)/step);
4930
5038
  if(index>=out.length)index=out.length-1;
4931
5039
  if(index<0)index=0;
@@ -4990,16 +5098,35 @@ out.push({at,density:sum/(n*bandwidth*Math.sqrt(Math.PI*2))});
4990
5098
  }
4991
5099
  return out;
4992
5100
  }
5101
+ function binFormatter(ctx,bound,step){
5102
+ const numbers=formatters(ctx.grid,{kind:'linear',step});
5103
+ const column=bound.measure&&bound.measure.col&&ctx.grid.columns
5104
+ ?ctx.grid.columns.get(bound.measure.col)
5105
+ :null;
5106
+ const formatted=!!(column&&column.format&&typeof column.formatValue==='function');
5107
+ const fallback=formatted
5108
+ ?{
5109
+ tick:(v)=>String(column.formatValue(v,null)),
5110
+ }
5111
+ :numbers;
5112
+ return tickLabeller((ctx.axis&&ctx.axis.x)||{},fallback,ctx.grid);
5113
+ }
4993
5114
  function drawHistogram(ctx){
4994
5115
  const scheme=ctx.scheme||resolveScheme();
4995
5116
  const{plot,bound}=ctx;
4996
5117
  const values=allReadings(bound);
4997
- const buckets=histogram(values,ctx.buckets||12);
5118
+ const declared=(ctx.axis&&ctx.axis.y)||{};
5119
+ const buckets=histogram(values,ctx.buckets||12,declared);
5120
+ const outside=outsideDomain(values,declared);
4998
5121
  const counts=buckets.map((b)=>b.count);
4999
5122
  const yDomain=measureDomain(counts,{zero:true});
5000
5123
  const yScale=linearScale(yDomain,[plot.bottom,plot.top]);
5001
- const labels=buckets.map((b)=>String(b.from));
5002
- const xScale=bandScale(labels,[plot.left,plot.right],0.08);
5124
+ const step=buckets.length?buckets[0].to-buckets[0].from:1;
5125
+ const edge=binFormatter(ctx,bound,step);
5126
+ const labels=buckets.map((b)=>edge(b.from));
5127
+ const ranges=buckets.map((b)=>`${edge(b.from)} ${DASH} ${edge(b.to)}`);
5128
+ const keys=buckets.map((unused,i)=>i);
5129
+ const xScale=bandScale(keys,[plot.left,plot.right],0.08);
5003
5130
  drawMeasureAxis({
5004
5131
  gridGroup:ctx.groups.grid,
5005
5132
  axisGroup:ctx.groups.axis,
@@ -5021,7 +5148,7 @@ const base=yScale.of(yDomain.min<=0?0:yDomain.min);
5021
5148
  buckets.forEach((bucket,i)=>{
5022
5149
  const top=yScale.of(bucket.count);
5023
5150
  attrs(pool.next('rect',`${NS}__bar ${NS}__mark`),{
5024
- x:round(xScale.of(labels[i])),
5151
+ x:round(xScale.of(i)),
5025
5152
  y:round(Math.min(top,base)),
5026
5153
  width:round(xScale.bandwidth),
5027
5154
  height:round(Math.max(bucket.count>0?1:0,Math.abs(base-top))),
@@ -5062,7 +5189,7 @@ const top=Math.min(yScale.of(bucket.count),base);
5062
5189
  const above=top-size/2-2;
5063
5190
  const inside=above<plot.top;
5064
5191
  return{
5065
- x:round(xScale.of(labels[i])+xScale.bandwidth/2),
5192
+ x:round(xScale.of(i)+xScale.bandwidth/2),
5066
5193
  y:round(inside?top+size/2+2:above),
5067
5194
  text:bucket.count?labelText(bucket.count,ctx.labels,ctx.grid):'',
5068
5195
  inside,
@@ -5075,12 +5202,15 @@ return{
5075
5202
  xScale,
5076
5203
  yScale,
5077
5204
  buckets,
5205
+ labels:ranges,
5206
+ categories:buckets.map((b)=>b.from),
5207
+ outside,
5078
5208
  series:[{
5079
5209
  key:'',
5080
5210
  label:bound.measure.title,
5081
5211
  index:0,
5082
5212
  points:buckets.map((b,i)=>({
5083
- x:labels[i],xKey:labels[i],label:`${b.from} – ${b.to}`,y:b.count,rows:b.count,
5213
+ x:i,xKey:String(i),label:ranges[i],from:b.from,to:b.to,y:b.count,rows:b.count,
5084
5214
  })),
5085
5215
  }],
5086
5216
  };
@@ -8504,7 +8634,8 @@ plot,
8504
8634
  scale:xScale,
8505
8635
  labels:bound.labels,
8506
8636
  fontSize:(ctx.typography&&ctx.typography.small)||ctx.fontSize,
8507
- rotated:shouldRotate(bound.labels,xScale.step,ctx.fontSize),
8637
+ rotated:shouldRotate(bound.labels,xScale.step,ctx.fontSize,
8638
+ ((ctx.axis&&ctx.axis.x)||{}).every),
8508
8639
  config:(ctx.axis&&ctx.axis.x)||{},
8509
8640
  });
8510
8641
  return{xScale,yScale,series:visible};
@@ -9207,6 +9338,7 @@ const axisWindowSpan=__m0["axisWindowSpan"];
9207
9338
  const drawCartesian=__m0["drawCartesian"];
9208
9339
  const drawForest=__m0["drawForest"];
9209
9340
  const nearestCategory=__m0["nearestCategory"];
9341
+ const nearestDrawnPoint=__m0["nearestDrawnPoint"];
9210
9342
  const staleWindow=__m0["staleWindow"];
9211
9343
  const WINDOW_LEAD=__m0["WINDOW_LEAD"];
9212
9344
  const windowedBound=__m0["windowedBound"];
@@ -9490,6 +9622,7 @@ class Chart{
9490
9622
  #groups=null;
9491
9623
  #legend=null;
9492
9624
  #tooltip=null;
9625
+ #tooltipEscapeChecked=false;
9493
9626
  #table=null;
9494
9627
  #empty=null;
9495
9628
  #off=[];
@@ -9690,11 +9823,39 @@ return{x:(event.clientX||0)-box.left,y:(event.clientY||0)-box.top};
9690
9823
  }
9691
9824
  #categoryAt(at){
9692
9825
  return nearestCategory({
9693
- bound:this.#bound,
9826
+ bound:{categories:this.#shown().categories},
9827
+ xScale:this.#drawn.xScale,
9828
+ at:this.#drawn.horizontal?at.y:at.x,
9829
+ });
9830
+ }
9831
+ #shown(){
9832
+ const drawn=this.#drawn;
9833
+ if(drawn&&Array.isArray(drawn.labels)&&Array.isArray(drawn.categories)){
9834
+ return{labels:drawn.labels,categories:drawn.categories};
9835
+ }
9836
+ return{
9837
+ labels:(this.#bound&&this.#bound.labels)||[],
9838
+ categories:(this.#bound&&this.#bound.categories)||[],
9839
+ };
9840
+ }
9841
+ #marksAt(at){
9842
+ if(!this.#drawn||!Array.isArray(this.#drawn.series))return null;
9843
+ if(this.#drawn.reduced){
9844
+ return nearestDrawnPoint({
9845
+ series:this.#drawn.series,
9694
9846
  xScale:this.#drawn.xScale,
9695
9847
  at:this.#drawn.horizontal?at.y:at.x,
9696
9848
  });
9697
9849
  }
9850
+ const index=this.#categoryAt(at);
9851
+ if(index<0)return null;
9852
+ return{
9853
+ index,
9854
+ entries:this.#drawn.series
9855
+ .map((series)=>({series,point:series.points[index]}))
9856
+ .filter((entry)=>entry.point&&entry.point.y!==null),
9857
+ };
9858
+ }
9698
9859
  #hitAt(at){
9699
9860
  return resolveHit({
9700
9861
  drawn:this.#drawn,
@@ -9712,7 +9873,7 @@ const rows=[];
9712
9873
  let heading='';
9713
9874
  const hit=this.#hitAt(at);
9714
9875
  if(hit){
9715
- this.#showTooltip(hit.heading,hit.rows,at);
9876
+ this.#showTooltip(hit.heading,hit.rows,event);
9716
9877
  this.emit('hover',{...hit.datum,native:event});
9717
9878
  return;
9718
9879
  }
@@ -9734,19 +9895,17 @@ value:`${measureText(arc.total,this.#grid.messages)} (${this.#grid.messages.numb
9734
9895
  colour:this.#scheme.series(arc.index),
9735
9896
  });
9736
9897
  }else{
9737
- const index=this.#categoryAt(at);
9738
- if(index<0){
9898
+ const marks=this.#marksAt(at);
9899
+ if(!marks){
9739
9900
  this.#hideTooltip();
9740
9901
  return;
9741
9902
  }
9742
- heading=this.#bound.labels[index]||'';
9743
- for(const series of this.#drawn.series){
9744
- const point=series.points[index];
9745
- if(!point||point.y===null)continue;
9903
+ heading=this.#shown().labels[marks.index]||'';
9904
+ for(const entry of marks.entries){
9746
9905
  rows.push({
9747
- label:series.label,
9748
- value:measureText(point.y,this.#grid.messages),
9749
- colour:this.#scheme.series(series.index),
9906
+ label:entry.series.label,
9907
+ value:measureText(entry.point.y,this.#grid.messages),
9908
+ colour:this.#scheme.series(entry.series.index),
9750
9909
  });
9751
9910
  }
9752
9911
  }
@@ -9754,11 +9913,11 @@ if(!rows.length){
9754
9913
  this.#hideTooltip();
9755
9914
  return;
9756
9915
  }
9757
- this.#showTooltip(heading,rows,at);
9916
+ this.#showTooltip(heading,rows,event);
9758
9917
  const datum=this.#datumAt(at);
9759
9918
  if(datum)this.emit('hover',{...datum,native:event});
9760
9919
  }
9761
- #showTooltip(heading,rows,at){
9920
+ #showTooltip(heading,rows,event){
9762
9921
  const doc=this.#doc;
9763
9922
  clear(this.#tooltip);
9764
9923
  if(heading){
@@ -9780,7 +9939,52 @@ append(line,[swatch,label,value]);
9780
9939
  this.#tooltip.appendChild(line);
9781
9940
  }
9782
9941
  this.#tooltip.removeAttribute('hidden');
9783
- this.#tooltip.setAttribute('style',`left:${Math.round(at.x+12)}px;top:${Math.round(at.y+12)}px`);
9942
+ this.#positionTooltip(event);
9943
+ }
9944
+ #positionTooltip(event){
9945
+ if(!this.#tooltipEscapeChecked){
9946
+ this.#tooltipEscapeChecked=true;
9947
+ if(this.#hasContainingBlockAncestor()){
9948
+ const body=this.#doc&&this.#doc.body;
9949
+ if(body&&typeof body.appendChild==='function')body.appendChild(this.#tooltip);
9950
+ }
9951
+ }
9952
+ const view=viewOf(this.#doc);
9953
+ const margin=12;
9954
+ const pointerX=(event&&event.clientX)||0;
9955
+ const pointerY=(event&&event.clientY)||0;
9956
+ const rect=typeof this.#tooltip.getBoundingClientRect==='function'
9957
+ ?this.#tooltip.getBoundingClientRect()
9958
+ :{width:0,height:0};
9959
+ const vw=view.innerWidth||0;
9960
+ const vh=view.innerHeight||0;
9961
+ let left=pointerX+margin;
9962
+ if(vw&&left+rect.width>vw-margin)left=pointerX-margin-rect.width;
9963
+ left=Math.max(margin,left);
9964
+ let top=pointerY+margin;
9965
+ if(vh&&top+rect.height>vh-margin)top=pointerY-margin-rect.height;
9966
+ top=Math.max(margin,top);
9967
+ this.#tooltip.style.left=`${Math.round(left)}px`;
9968
+ this.#tooltip.style.top=`${Math.round(top)}px`;
9969
+ }
9970
+ #hasContainingBlockAncestor(){
9971
+ const view=viewOf(this.#doc);
9972
+ if(typeof view.getComputedStyle!=='function')return false;
9973
+ let node=this.#root&&this.#root.parentNode;
9974
+ while(node){
9975
+ if(node.nodeType===11&&node.host){node=node.host;continue;}
9976
+ if(node.nodeType!==1)break;
9977
+ const style=view.getComputedStyle(node);
9978
+ if(style&&(
9979
+ (style.transform&&style.transform!=='none')
9980
+ ||(style.perspective&&style.perspective!=='none')
9981
+ ||(style.filter&&style.filter!=='none')
9982
+ ||(style.backdropFilter&&style.backdropFilter!=='none')
9983
+ ||(style.contain&&/layout|paint|strict|content/.test(style.contain))
9984
+ ))return true;
9985
+ node=node.parentNode;
9986
+ }
9987
+ return false;
9784
9988
  }
9785
9989
  #hideTooltip(){
9786
9990
  if(this.#tooltip)this.#tooltip.setAttribute('hidden','');
@@ -9805,16 +10009,19 @@ path:Array.isArray(arc.path)?[...arc.path]:[arc.label],
9805
10009
  rowKeys:arc.node.rowKey?[arc.node.rowKey]:[],
9806
10010
  };
9807
10011
  }
9808
- const index=this.#categoryAt(at);
9809
- if(index<0)return null;
9810
- const points=this.#drawn.series
9811
- .map((series)=>({series,point:series.points[index]}))
9812
- .filter((entry)=>entry.point&&entry.point.y!==null);
10012
+ const marks=this.#marksAt(at);
10013
+ if(!marks)return null;
10014
+ const points=marks.entries;
10015
+ const shown=this.#shown();
10016
+ const span=points.length===1&&points[0].point.from!==undefined
10017
+ ?{from:points[0].point.from,to:points[0].point.to}
10018
+ :null;
9813
10019
  return{
9814
- label:this.#bound.labels[index]||'',
9815
- category:this.#bound.categories[index],
10020
+ label:shown.labels[marks.index]||'',
10021
+ category:shown.categories[marks.index],
9816
10022
  column:this.#bound.dimension.col,
9817
10023
  value:points.length===1?points[0].point.y:null,
10024
+ ...(span||{}),
9818
10025
  series:points.map((entry)=>({
9819
10026
  key:entry.series.key,
9820
10027
  label:entry.series.label,
@@ -10423,6 +10630,7 @@ out.warn(message);
10423
10630
  }
10424
10631
  }
10425
10632
  if(this.#drawn)this.#drawn.plot=this.#drawn.plot||plotOf(this.#drawn,width,height);
10633
+ if(this.#bound)this.#bound.outside=(this.#drawn&&this.#drawn.outside)||0;
10426
10634
  if(this.#spec.selection)this.#emphasise();
10427
10635
  this.#watermark();
10428
10636
  this.#describe(type,bound,hierarchical);
@@ -10672,17 +10880,22 @@ const heading=el(doc,'th');
10672
10880
  setText(heading,measure);
10673
10881
  head.appendChild(heading);
10674
10882
  }else{
10675
- for(const series of bound.series||[]){
10883
+ const shown=this.#shown();
10884
+ const table_=this.#drawn&&Array.isArray(this.#drawn.labels)
10885
+ &&Array.isArray(this.#drawn.series)&&Array.isArray(this.#drawn.categories)
10886
+ ?this.#drawn.series
10887
+ :(bound.series||[]);
10888
+ for(const series of table_){
10676
10889
  const th=el(doc,'th');
10677
10890
  setText(th,series.label);
10678
10891
  head.appendChild(th);
10679
10892
  }
10680
- for(let i=0;i<(bound.labels||[]).length;i++){
10893
+ for(let i=0;i<(shown.labels||[]).length;i++){
10681
10894
  const tr=el(doc,'tr');
10682
10895
  const th=el(doc,'th');
10683
- setText(th,bound.labels[i]);
10896
+ setText(th,shown.labels[i]);
10684
10897
  tr.appendChild(th);
10685
- for(const series of bound.series||[]){
10898
+ for(const series of table_){
10686
10899
  const td=el(doc,'td');
10687
10900
  const point=series.points[i];
10688
10901
  setText(td,point&&point.y!==null?measureText(point.y,messages):'');