@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
  */
@@ -243,9 +243,10 @@ bottom:top+height,
243
243
  gutter:{left,bottom,right,top},
244
244
  };
245
245
  }
246
- function shouldRotate(labels,slot,fontSize){
246
+ function shouldRotate(labels,slot,fontSize,every){
247
247
  if(!labels.length||slot<=0)return false;
248
- return widestLabel(labels,fontSize)>slot-4;
248
+ const step=Number.isFinite(every)&&every>0?Number(every):1;
249
+ return widestLabel(labels,fontSize)>slot*step-4;
249
250
  }
250
251
  class Pool{
251
252
  #parent;
@@ -567,7 +568,7 @@ return`
567
568
  max-width:40%;overflow:auto;padding:4px 8px}
568
569
  .${NS}__legend[data-position="left"]{order:-1}
569
570
  .${NS}__legend-more{align-self:center;color:var(--lattice-foreground-muted,#5b6670)}
570
- .${NS}__tooltip{position:absolute;z-index:5;pointer-events:none;max-width:260px;
571
+ .${NS}__tooltip{position:fixed;z-index:5;pointer-events:none;max-width:260px;
571
572
  padding:5px 8px;border-radius:4px;font-size:var(--lattice-font-size-sm,11px);
572
573
  background:var(--lattice-surface,#f7f8f9);color:var(--lattice-foreground,#1c2126);
573
574
  border:1px solid var(--lattice-border-color,#dfe3e6);
@@ -639,6 +640,7 @@ Object.defineProperty(__exports,"normaliseAxes",{enumerable:true,get:function(){
639
640
  Object.defineProperty(__exports,"tickValues",{enumerable:true,get:function(){return tickValues;}});
640
641
  Object.defineProperty(__exports,"tickLabeller",{enumerable:true,get:function(){return tickLabeller;}});
641
642
  Object.defineProperty(__exports,"drawAxisTitle",{enumerable:true,get:function(){return drawAxisTitle;}});
643
+ Object.defineProperty(__exports,"labelEvery",{enumerable:true,get:function(){return labelEvery;}});
642
644
  Object.defineProperty(__exports,"drawMeasureAxis",{enumerable:true,get:function(){return drawMeasureAxis;}});
643
645
  Object.defineProperty(__exports,"drawCategoryAxis",{enumerable:true,get:function(){return drawCategoryAxis;}});
644
646
  Object.defineProperty(__exports,"leftLabelRoom",{enumerable:true,get:function(){return leftLabelRoom;}});
@@ -659,6 +661,7 @@ const setText=__m1["setText"];
659
661
  const svg=__m1["svg"];
660
662
  const __m2=__req("packages/modules/charts/typography.js");
661
663
  const applySize=__m2["applySize"];
664
+ const CHAR_RATIO=__m2["CHAR_RATIO"];
662
665
  const truncateTo=__m2["truncateTo"];
663
666
  const __m3=__req("packages/modules/charts/styles.js");
664
667
  const NS=__m3["NS"];
@@ -696,6 +699,13 @@ return fallback.tick;
696
699
  }
697
700
  function drawAxisTitle(opts){
698
701
  if(!opts.text)return;
702
+ const band=opts.side==='left'||opts.side==='right'
703
+ ?opts.plot.height
704
+ :opts.plot.width;
705
+ const shown=Number.isFinite(band)
706
+ ?truncateTo(String(opts.text),Math.max(0,band),opts.size)
707
+ :String(opts.text);
708
+ if(!shown||shown==='…')return;
699
709
  const node=svg(opts.group.ownerDocument,'text',{class:`${NS}__axis-title`});
700
710
  applySize(node,opts.size);
701
711
  if(opts.side==='left'){
@@ -719,28 +729,55 @@ y:round(opts.plot.bottom+opts.plot.gutter.bottom-2),
719
729
  'text-anchor':'middle',
720
730
  });
721
731
  }
722
- setText(node,opts.text);
732
+ setText(node,shown);
733
+ if(shown!==String(opts.text))node.setAttribute('aria-label',String(opts.text));
723
734
  opts.group.appendChild(node);
724
735
  }
736
+ function labelEvery(opts){
737
+ const{values,scale,size,horizontal,label}=opts;
738
+ if(values.length<2)return 1;
739
+ let pitch=Infinity;
740
+ for(let i=1;i<values.length;i++){
741
+ const gap=Math.abs(scale.of(values[i])-scale.of(values[i-1]));
742
+ if(Number.isFinite(gap)&&gap<pitch)pitch=gap;
743
+ }
744
+ if(!Number.isFinite(pitch))return 1;
745
+ if(pitch<=0)return values.length;
746
+ let needed=size*LINE_HEIGHT+2;
747
+ if(horizontal){
748
+ let widest=0;
749
+ for(const value of values){
750
+ const width=String(label(value)||'').length*size*CHAR_RATIO;
751
+ if(width>widest)widest=width;
752
+ }
753
+ needed=widest+GAP;
754
+ }
755
+ return Math.max(1,Math.ceil(needed/pitch));
756
+ }
725
757
  function drawMeasureAxis(opts){
726
758
  const{gridGroup,axisGroup,plot,scale,format}=opts;
727
759
  const config=opts.config||{};
728
760
  const values=tickValues(scale,config);
729
761
  const label=tickLabeller(config,format,opts.grid);
730
762
  const size=opts.size||11;
763
+ const every=labelEvery({
764
+ values,scale,size,horizontal:!!opts.horizontal,label,
765
+ });
731
766
  const lines=config.grid===false?null:gridGroup;
732
767
  const grid=lines?new Pool(lines):null;
733
768
  const labels=new Pool(axisGroup);
734
- for(const value of values){
769
+ for(let i=0;i<values.length;i++){
770
+ const value=values[i];
735
771
  const at=round(scale.of(value));
736
772
  const zero=value===0;
773
+ const thinned=i%every!==0;
737
774
  if(opts.horizontal){
738
775
  if(grid)attrs(grid.next('line',`${NS}__gridline`),{
739
776
  x1:at,x2:at,y1:round(plot.top),y2:round(plot.bottom),
740
777
  'stroke-opacity':zero?1:0.6,
741
778
  'stroke-width':zero?1.5:1,
742
779
  });
743
- if(config.labels===false)continue;
780
+ if(config.labels===false||thinned)continue;
744
781
  const text=labels.next('text',`${NS}__tick`);
745
782
  applySize(text,size);
746
783
  attrs(text,{
@@ -754,7 +791,7 @@ x1:round(plot.left),x2:round(plot.right),y1:at,y2:at,
754
791
  'stroke-opacity':zero?1:0.6,
755
792
  'stroke-width':zero?1.5:1,
756
793
  });
757
- if(config.labels===false)continue;
794
+ if(config.labels===false||thinned)continue;
758
795
  const text=labels.next('text',`${NS}__tick`);
759
796
  applySize(text,size);
760
797
  attrs(text,{
@@ -2581,12 +2618,12 @@ Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){r
2581
2618
  Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
2582
2619
  Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
2583
2620
  Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
2584
- const STAMPED_VERSION="1.65.0";
2621
+ const STAMPED_VERSION="1.67.0";
2585
2622
  async function resolveVersion(){
2586
2623
  if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
2587
2624
  return STAMPED_VERSION;
2588
2625
  }
2589
- const VERSION="1.65.0";
2626
+ const VERSION="1.67.0";
2590
2627
  const warned=new Set();
2591
2628
  const WARNED_LIMIT=2000;
2592
2629
  function rememberWarned(key){
@@ -2957,6 +2994,8 @@ Object.defineProperty(__exports,"drawBoundErrorBars",{enumerable:true,get:functi
2957
2994
  Object.defineProperty(__exports,"drawForest",{enumerable:true,get:function(){return drawForest;}});
2958
2995
  Object.defineProperty(__exports,"drawReferenceLines",{enumerable:true,get:function(){return drawReferenceLines;}});
2959
2996
  Object.defineProperty(__exports,"drawCartesian",{enumerable:true,get:function(){return drawCartesian;}});
2997
+ Object.defineProperty(__exports,"HIT_TOLERANCE",{enumerable:true,get:function(){return HIT_TOLERANCE;}});
2998
+ Object.defineProperty(__exports,"nearestDrawnPoint",{enumerable:true,get:function(){return nearestDrawnPoint;}});
2960
2999
  Object.defineProperty(__exports,"nearestCategory",{enumerable:true,get:function(){return nearestCategory;}});
2961
3000
  Object.defineProperty(__exports,"categoryKeyAt",{enumerable:true,get:function(){return categoryKeyAt;}});
2962
3001
  const __m0=__req("packages/modules/charts/axis.js");
@@ -3777,7 +3816,7 @@ plot,
3777
3816
  scale:xScale,
3778
3817
  labels:bound.labels,
3779
3818
  fontSize:type_.small,
3780
- rotated:shouldRotate(bound.labels,xScale.step,type_.small),
3819
+ rotated:shouldRotate(bound.labels,xScale.step,type_.small,axisConfig.x.every),
3781
3820
  config:axisConfig.x,
3782
3821
  });
3783
3822
  }else{
@@ -3828,11 +3867,16 @@ group:ctx.groups.axis,plot,text:leftSeries[0].label,side:'left',size:type_.axisT
3828
3867
  const target=Number.isFinite(ctx.downsampleTo)
3829
3868
  ?Number(ctx.downsampleTo)
3830
3869
  :Math.max(2,Math.round(plot.width));
3870
+ let reduced=false;
3831
3871
  if(shape.marks==='path'||type==='scatter'||type==='bubble'){
3832
3872
  for(const series of visible){
3873
+ series.kept=null;
3833
3874
  if(series.points.length>target*1.5){
3834
3875
  const indexed=series.points.map((point,i)=>({x:i,y:point.y,point}));
3835
- series.points=downsample(indexed,target).map((entry)=>entry.point);
3876
+ const picked=downsample(indexed,target);
3877
+ series.points=picked.map((entry)=>entry.point);
3878
+ series.kept=picked.map((entry)=>entry.x);
3879
+ reduced=true;
3836
3880
  }
3837
3881
  }
3838
3882
  }
@@ -4022,8 +4066,42 @@ plot,
4022
4066
  errorBars,
4023
4067
  annotations:describedAll,
4024
4068
  trendlines,
4069
+ reduced,
4025
4070
  };
4026
4071
  }
4072
+ const HIT_TOLERANCE=32;
4073
+ function nearestDrawnPoint(opts){
4074
+ const{series,xScale,at}=opts;
4075
+ const tolerance=Number.isFinite(opts.tolerance)?Number(opts.tolerance):HIT_TOLERANCE;
4076
+ const entries=[];
4077
+ let index=-1;
4078
+ let best=Infinity;
4079
+ for(const one of series){
4080
+ let near=null;
4081
+ let nearAt=-1;
4082
+ let nearest=Infinity;
4083
+ const points=one.points||[];
4084
+ for(let i=0;i<points.length;i++){
4085
+ const point=points[i];
4086
+ if(!point||!isNumber(point.y))continue;
4087
+ const px=xOf(xScale,point);
4088
+ if(Number.isNaN(px))continue;
4089
+ const distance=Math.abs(px-at);
4090
+ if(distance>=nearest)continue;
4091
+ nearest=distance;
4092
+ near=point;
4093
+ nearAt=Array.isArray(one.kept)?one.kept[i]:i;
4094
+ }
4095
+ if(!near||nearest>tolerance)continue;
4096
+ entries.push({series:one,point:near});
4097
+ if(nearest<best){
4098
+ best=nearest;
4099
+ index=nearAt;
4100
+ }
4101
+ }
4102
+ if(index<0)return null;
4103
+ return{index,entries};
4104
+ }
4027
4105
  function nearestCategory(opts){
4028
4106
  const{bound,xScale,at}=opts;
4029
4107
  if(!bound.categories.length)return-1;
@@ -4815,6 +4893,8 @@ __def("packages/modules/charts/distribution.js",function(__exports,__req){
4815
4893
  Object.defineProperty(__exports,"FENCE",{enumerable:true,get:function(){return FENCE;}});
4816
4894
  Object.defineProperty(__exports,"quantile",{enumerable:true,get:function(){return quantile;}});
4817
4895
  Object.defineProperty(__exports,"summarise",{enumerable:true,get:function(){return summarise;}});
4896
+ Object.defineProperty(__exports,"binEdge",{enumerable:true,get:function(){return binEdge;}});
4897
+ Object.defineProperty(__exports,"outsideDomain",{enumerable:true,get:function(){return outsideDomain;}});
4818
4898
  Object.defineProperty(__exports,"histogram",{enumerable:true,get:function(){return histogram;}});
4819
4899
  Object.defineProperty(__exports,"readingsOf",{enumerable:true,get:function(){return readingsOf;}});
4820
4900
  Object.defineProperty(__exports,"valuesByCategory",{enumerable:true,get:function(){return valuesByCategory;}});
@@ -4837,6 +4917,7 @@ const drawAxisLines=__m1["drawAxisLines"];
4837
4917
  const drawCategoryAxis=__m1["drawCategoryAxis"];
4838
4918
  const drawContinuousAxis=__m1["drawContinuousAxis"];
4839
4919
  const drawMeasureAxis=__m1["drawMeasureAxis"];
4920
+ const tickLabeller=__m1["tickLabeller"];
4840
4921
  const __m2=__req("packages/modules/charts/format.js");
4841
4922
  const formatters=__m2["formatters"];
4842
4923
  const __m3=__req("packages/modules/charts/scale.js");
@@ -4857,6 +4938,7 @@ const __m7=__req("packages/modules/charts/labels.js");
4857
4938
  const drawAnchoredLabels=__m7["drawAnchoredLabels"];
4858
4939
  const labelText=__m7["labelText"];
4859
4940
  const FENCE=1.5;
4941
+ const DASH='\u2013';
4860
4942
  function quantile(sorted,p){
4861
4943
  const n=sorted.length;
4862
4944
  if(!n)return NaN;
@@ -4896,18 +4978,42 @@ outliers:sorted.filter((v)=>v<lowFence||v>highFence),
4896
4978
  count:sorted.length,
4897
4979
  };
4898
4980
  }
4899
- function histogram(values,buckets=12){
4981
+ function binEdge(first,step,i){
4982
+ const v=first+i*step;
4983
+ return Math.abs(v)<step/1e6?0:Number(v.toPrecision(12));
4984
+ }
4985
+ function outsideDomain(values,domain){
4986
+ const declared=domain||{};
4987
+ const hasMin=isNumber(declared.min);
4988
+ const hasMax=isNumber(declared.max);
4989
+ if(!hasMin&&!hasMax)return 0;
4990
+ let out=0;
4991
+ for(let i=0;i<values.length;i++){
4992
+ const v=values[i];
4993
+ if(!isNumber(v))continue;
4994
+ if((hasMin&&v<declared.min)||(hasMax&&v>declared.max))out++;
4995
+ }
4996
+ return out;
4997
+ }
4998
+ function histogram(values,buckets=12,domain){
4999
+ const declared=domain||{};
5000
+ const hasMin=isNumber(declared.min);
5001
+ const hasMax=isNumber(declared.max);
4900
5002
  let min=Infinity;
4901
5003
  let max=-Infinity;
4902
5004
  let count=0;
4903
5005
  for(let i=0;i<values.length;i++){
4904
5006
  const v=values[i];
4905
5007
  if(!isNumber(v))continue;
5008
+ if(hasMin&&v<declared.min)continue;
5009
+ if(hasMax&&v>declared.max)continue;
4906
5010
  if(v<min)min=v;
4907
5011
  if(v>max)max=v;
4908
5012
  count++;
4909
5013
  }
4910
5014
  if(!count)return[];
5015
+ if(hasMin)min=Number(declared.min);
5016
+ if(hasMax)max=Number(declared.max);
4911
5017
  if(min===max){
4912
5018
  const pad=Math.abs(min)>0?Math.abs(min)/10:0.5;
4913
5019
  min-=pad;
@@ -4917,13 +5023,15 @@ const step=niceStep((max-min)/Math.max(1,buckets));
4917
5023
  const first=Math.floor(min/step)*step;
4918
5024
  const last=Math.ceil(max/step)*step;
4919
5025
  const out=[];
4920
- for(let edge=first;edge<last-step/1e6;edge+=step){
4921
- out.push({from:Number(edge.toPrecision(12)),to:Number((edge+step).toPrecision(12)),count:0});
5026
+ const bins=Math.max(1,Math.round((last-first)/step));
5027
+ for(let i=0;i<bins;i++){
5028
+ out.push({from:binEdge(first,step,i),to:binEdge(first,step,i+1),count:0});
4922
5029
  }
4923
- if(!out.length)out.push({from:first,to:first+step,count:0});
4924
5030
  for(let i=0;i<values.length;i++){
4925
5031
  const v=values[i];
4926
5032
  if(!isNumber(v))continue;
5033
+ if(hasMin&&v<declared.min)continue;
5034
+ if(hasMax&&v>declared.max)continue;
4927
5035
  let index=Math.floor((v-first)/step);
4928
5036
  if(index>=out.length)index=out.length-1;
4929
5037
  if(index<0)index=0;
@@ -4988,16 +5096,35 @@ out.push({at,density:sum/(n*bandwidth*Math.sqrt(Math.PI*2))});
4988
5096
  }
4989
5097
  return out;
4990
5098
  }
5099
+ function binFormatter(ctx,bound,step){
5100
+ const numbers=formatters(ctx.grid,{kind:'linear',step});
5101
+ const column=bound.measure&&bound.measure.col&&ctx.grid.columns
5102
+ ?ctx.grid.columns.get(bound.measure.col)
5103
+ :null;
5104
+ const formatted=!!(column&&column.format&&typeof column.formatValue==='function');
5105
+ const fallback=formatted
5106
+ ?{
5107
+ tick:(v)=>String(column.formatValue(v,null)),
5108
+ }
5109
+ :numbers;
5110
+ return tickLabeller((ctx.axis&&ctx.axis.x)||{},fallback,ctx.grid);
5111
+ }
4991
5112
  function drawHistogram(ctx){
4992
5113
  const scheme=ctx.scheme||resolveScheme();
4993
5114
  const{plot,bound}=ctx;
4994
5115
  const values=allReadings(bound);
4995
- const buckets=histogram(values,ctx.buckets||12);
5116
+ const declared=(ctx.axis&&ctx.axis.y)||{};
5117
+ const buckets=histogram(values,ctx.buckets||12,declared);
5118
+ const outside=outsideDomain(values,declared);
4996
5119
  const counts=buckets.map((b)=>b.count);
4997
5120
  const yDomain=measureDomain(counts,{zero:true});
4998
5121
  const yScale=linearScale(yDomain,[plot.bottom,plot.top]);
4999
- const labels=buckets.map((b)=>String(b.from));
5000
- const xScale=bandScale(labels,[plot.left,plot.right],0.08);
5122
+ const step=buckets.length?buckets[0].to-buckets[0].from:1;
5123
+ const edge=binFormatter(ctx,bound,step);
5124
+ const labels=buckets.map((b)=>edge(b.from));
5125
+ const ranges=buckets.map((b)=>`${edge(b.from)} ${DASH} ${edge(b.to)}`);
5126
+ const keys=buckets.map((unused,i)=>i);
5127
+ const xScale=bandScale(keys,[plot.left,plot.right],0.08);
5001
5128
  drawMeasureAxis({
5002
5129
  gridGroup:ctx.groups.grid,
5003
5130
  axisGroup:ctx.groups.axis,
@@ -5019,7 +5146,7 @@ const base=yScale.of(yDomain.min<=0?0:yDomain.min);
5019
5146
  buckets.forEach((bucket,i)=>{
5020
5147
  const top=yScale.of(bucket.count);
5021
5148
  attrs(pool.next('rect',`${NS}__bar ${NS}__mark`),{
5022
- x:round(xScale.of(labels[i])),
5149
+ x:round(xScale.of(i)),
5023
5150
  y:round(Math.min(top,base)),
5024
5151
  width:round(xScale.bandwidth),
5025
5152
  height:round(Math.max(bucket.count>0?1:0,Math.abs(base-top))),
@@ -5060,7 +5187,7 @@ const top=Math.min(yScale.of(bucket.count),base);
5060
5187
  const above=top-size/2-2;
5061
5188
  const inside=above<plot.top;
5062
5189
  return{
5063
- x:round(xScale.of(labels[i])+xScale.bandwidth/2),
5190
+ x:round(xScale.of(i)+xScale.bandwidth/2),
5064
5191
  y:round(inside?top+size/2+2:above),
5065
5192
  text:bucket.count?labelText(bucket.count,ctx.labels,ctx.grid):'',
5066
5193
  inside,
@@ -5073,12 +5200,15 @@ return{
5073
5200
  xScale,
5074
5201
  yScale,
5075
5202
  buckets,
5203
+ labels:ranges,
5204
+ categories:buckets.map((b)=>b.from),
5205
+ outside,
5076
5206
  series:[{
5077
5207
  key:'',
5078
5208
  label:bound.measure.title,
5079
5209
  index:0,
5080
5210
  points:buckets.map((b,i)=>({
5081
- x:labels[i],xKey:labels[i],label:`${b.from} – ${b.to}`,y:b.count,rows:b.count,
5211
+ x:i,xKey:String(i),label:ranges[i],from:b.from,to:b.to,y:b.count,rows:b.count,
5082
5212
  })),
5083
5213
  }],
5084
5214
  };
@@ -8502,7 +8632,8 @@ plot,
8502
8632
  scale:xScale,
8503
8633
  labels:bound.labels,
8504
8634
  fontSize:(ctx.typography&&ctx.typography.small)||ctx.fontSize,
8505
- rotated:shouldRotate(bound.labels,xScale.step,ctx.fontSize),
8635
+ rotated:shouldRotate(bound.labels,xScale.step,ctx.fontSize,
8636
+ ((ctx.axis&&ctx.axis.x)||{}).every),
8506
8637
  config:(ctx.axis&&ctx.axis.x)||{},
8507
8638
  });
8508
8639
  return{xScale,yScale,series:visible};
@@ -9205,6 +9336,7 @@ const axisWindowSpan=__m0["axisWindowSpan"];
9205
9336
  const drawCartesian=__m0["drawCartesian"];
9206
9337
  const drawForest=__m0["drawForest"];
9207
9338
  const nearestCategory=__m0["nearestCategory"];
9339
+ const nearestDrawnPoint=__m0["nearestDrawnPoint"];
9208
9340
  const staleWindow=__m0["staleWindow"];
9209
9341
  const WINDOW_LEAD=__m0["WINDOW_LEAD"];
9210
9342
  const windowedBound=__m0["windowedBound"];
@@ -9488,6 +9620,7 @@ class Chart{
9488
9620
  #groups=null;
9489
9621
  #legend=null;
9490
9622
  #tooltip=null;
9623
+ #tooltipEscapeChecked=false;
9491
9624
  #table=null;
9492
9625
  #empty=null;
9493
9626
  #off=[];
@@ -9688,11 +9821,39 @@ return{x:(event.clientX||0)-box.left,y:(event.clientY||0)-box.top};
9688
9821
  }
9689
9822
  #categoryAt(at){
9690
9823
  return nearestCategory({
9691
- bound:this.#bound,
9824
+ bound:{categories:this.#shown().categories},
9825
+ xScale:this.#drawn.xScale,
9826
+ at:this.#drawn.horizontal?at.y:at.x,
9827
+ });
9828
+ }
9829
+ #shown(){
9830
+ const drawn=this.#drawn;
9831
+ if(drawn&&Array.isArray(drawn.labels)&&Array.isArray(drawn.categories)){
9832
+ return{labels:drawn.labels,categories:drawn.categories};
9833
+ }
9834
+ return{
9835
+ labels:(this.#bound&&this.#bound.labels)||[],
9836
+ categories:(this.#bound&&this.#bound.categories)||[],
9837
+ };
9838
+ }
9839
+ #marksAt(at){
9840
+ if(!this.#drawn||!Array.isArray(this.#drawn.series))return null;
9841
+ if(this.#drawn.reduced){
9842
+ return nearestDrawnPoint({
9843
+ series:this.#drawn.series,
9692
9844
  xScale:this.#drawn.xScale,
9693
9845
  at:this.#drawn.horizontal?at.y:at.x,
9694
9846
  });
9695
9847
  }
9848
+ const index=this.#categoryAt(at);
9849
+ if(index<0)return null;
9850
+ return{
9851
+ index,
9852
+ entries:this.#drawn.series
9853
+ .map((series)=>({series,point:series.points[index]}))
9854
+ .filter((entry)=>entry.point&&entry.point.y!==null),
9855
+ };
9856
+ }
9696
9857
  #hitAt(at){
9697
9858
  return resolveHit({
9698
9859
  drawn:this.#drawn,
@@ -9710,7 +9871,7 @@ const rows=[];
9710
9871
  let heading='';
9711
9872
  const hit=this.#hitAt(at);
9712
9873
  if(hit){
9713
- this.#showTooltip(hit.heading,hit.rows,at);
9874
+ this.#showTooltip(hit.heading,hit.rows,event);
9714
9875
  this.emit('hover',{...hit.datum,native:event});
9715
9876
  return;
9716
9877
  }
@@ -9732,19 +9893,17 @@ value:`${measureText(arc.total,this.#grid.messages)} (${this.#grid.messages.numb
9732
9893
  colour:this.#scheme.series(arc.index),
9733
9894
  });
9734
9895
  }else{
9735
- const index=this.#categoryAt(at);
9736
- if(index<0){
9896
+ const marks=this.#marksAt(at);
9897
+ if(!marks){
9737
9898
  this.#hideTooltip();
9738
9899
  return;
9739
9900
  }
9740
- heading=this.#bound.labels[index]||'';
9741
- for(const series of this.#drawn.series){
9742
- const point=series.points[index];
9743
- if(!point||point.y===null)continue;
9901
+ heading=this.#shown().labels[marks.index]||'';
9902
+ for(const entry of marks.entries){
9744
9903
  rows.push({
9745
- label:series.label,
9746
- value:measureText(point.y,this.#grid.messages),
9747
- colour:this.#scheme.series(series.index),
9904
+ label:entry.series.label,
9905
+ value:measureText(entry.point.y,this.#grid.messages),
9906
+ colour:this.#scheme.series(entry.series.index),
9748
9907
  });
9749
9908
  }
9750
9909
  }
@@ -9752,11 +9911,11 @@ if(!rows.length){
9752
9911
  this.#hideTooltip();
9753
9912
  return;
9754
9913
  }
9755
- this.#showTooltip(heading,rows,at);
9914
+ this.#showTooltip(heading,rows,event);
9756
9915
  const datum=this.#datumAt(at);
9757
9916
  if(datum)this.emit('hover',{...datum,native:event});
9758
9917
  }
9759
- #showTooltip(heading,rows,at){
9918
+ #showTooltip(heading,rows,event){
9760
9919
  const doc=this.#doc;
9761
9920
  clear(this.#tooltip);
9762
9921
  if(heading){
@@ -9778,7 +9937,52 @@ append(line,[swatch,label,value]);
9778
9937
  this.#tooltip.appendChild(line);
9779
9938
  }
9780
9939
  this.#tooltip.removeAttribute('hidden');
9781
- this.#tooltip.setAttribute('style',`left:${Math.round(at.x+12)}px;top:${Math.round(at.y+12)}px`);
9940
+ this.#positionTooltip(event);
9941
+ }
9942
+ #positionTooltip(event){
9943
+ if(!this.#tooltipEscapeChecked){
9944
+ this.#tooltipEscapeChecked=true;
9945
+ if(this.#hasContainingBlockAncestor()){
9946
+ const body=this.#doc&&this.#doc.body;
9947
+ if(body&&typeof body.appendChild==='function')body.appendChild(this.#tooltip);
9948
+ }
9949
+ }
9950
+ const view=viewOf(this.#doc);
9951
+ const margin=12;
9952
+ const pointerX=(event&&event.clientX)||0;
9953
+ const pointerY=(event&&event.clientY)||0;
9954
+ const rect=typeof this.#tooltip.getBoundingClientRect==='function'
9955
+ ?this.#tooltip.getBoundingClientRect()
9956
+ :{width:0,height:0};
9957
+ const vw=view.innerWidth||0;
9958
+ const vh=view.innerHeight||0;
9959
+ let left=pointerX+margin;
9960
+ if(vw&&left+rect.width>vw-margin)left=pointerX-margin-rect.width;
9961
+ left=Math.max(margin,left);
9962
+ let top=pointerY+margin;
9963
+ if(vh&&top+rect.height>vh-margin)top=pointerY-margin-rect.height;
9964
+ top=Math.max(margin,top);
9965
+ this.#tooltip.style.left=`${Math.round(left)}px`;
9966
+ this.#tooltip.style.top=`${Math.round(top)}px`;
9967
+ }
9968
+ #hasContainingBlockAncestor(){
9969
+ const view=viewOf(this.#doc);
9970
+ if(typeof view.getComputedStyle!=='function')return false;
9971
+ let node=this.#root&&this.#root.parentNode;
9972
+ while(node){
9973
+ if(node.nodeType===11&&node.host){node=node.host;continue;}
9974
+ if(node.nodeType!==1)break;
9975
+ const style=view.getComputedStyle(node);
9976
+ if(style&&(
9977
+ (style.transform&&style.transform!=='none')
9978
+ ||(style.perspective&&style.perspective!=='none')
9979
+ ||(style.filter&&style.filter!=='none')
9980
+ ||(style.backdropFilter&&style.backdropFilter!=='none')
9981
+ ||(style.contain&&/layout|paint|strict|content/.test(style.contain))
9982
+ ))return true;
9983
+ node=node.parentNode;
9984
+ }
9985
+ return false;
9782
9986
  }
9783
9987
  #hideTooltip(){
9784
9988
  if(this.#tooltip)this.#tooltip.setAttribute('hidden','');
@@ -9803,16 +10007,19 @@ path:Array.isArray(arc.path)?[...arc.path]:[arc.label],
9803
10007
  rowKeys:arc.node.rowKey?[arc.node.rowKey]:[],
9804
10008
  };
9805
10009
  }
9806
- const index=this.#categoryAt(at);
9807
- if(index<0)return null;
9808
- const points=this.#drawn.series
9809
- .map((series)=>({series,point:series.points[index]}))
9810
- .filter((entry)=>entry.point&&entry.point.y!==null);
10010
+ const marks=this.#marksAt(at);
10011
+ if(!marks)return null;
10012
+ const points=marks.entries;
10013
+ const shown=this.#shown();
10014
+ const span=points.length===1&&points[0].point.from!==undefined
10015
+ ?{from:points[0].point.from,to:points[0].point.to}
10016
+ :null;
9811
10017
  return{
9812
- label:this.#bound.labels[index]||'',
9813
- category:this.#bound.categories[index],
10018
+ label:shown.labels[marks.index]||'',
10019
+ category:shown.categories[marks.index],
9814
10020
  column:this.#bound.dimension.col,
9815
10021
  value:points.length===1?points[0].point.y:null,
10022
+ ...(span||{}),
9816
10023
  series:points.map((entry)=>({
9817
10024
  key:entry.series.key,
9818
10025
  label:entry.series.label,
@@ -10421,6 +10628,7 @@ out.warn(message);
10421
10628
  }
10422
10629
  }
10423
10630
  if(this.#drawn)this.#drawn.plot=this.#drawn.plot||plotOf(this.#drawn,width,height);
10631
+ if(this.#bound)this.#bound.outside=(this.#drawn&&this.#drawn.outside)||0;
10424
10632
  if(this.#spec.selection)this.#emphasise();
10425
10633
  this.#watermark();
10426
10634
  this.#describe(type,bound,hierarchical);
@@ -10670,17 +10878,22 @@ const heading=el(doc,'th');
10670
10878
  setText(heading,measure);
10671
10879
  head.appendChild(heading);
10672
10880
  }else{
10673
- for(const series of bound.series||[]){
10881
+ const shown=this.#shown();
10882
+ const table_=this.#drawn&&Array.isArray(this.#drawn.labels)
10883
+ &&Array.isArray(this.#drawn.series)&&Array.isArray(this.#drawn.categories)
10884
+ ?this.#drawn.series
10885
+ :(bound.series||[]);
10886
+ for(const series of table_){
10674
10887
  const th=el(doc,'th');
10675
10888
  setText(th,series.label);
10676
10889
  head.appendChild(th);
10677
10890
  }
10678
- for(let i=0;i<(bound.labels||[]).length;i++){
10891
+ for(let i=0;i<(shown.labels||[]).length;i++){
10679
10892
  const tr=el(doc,'tr');
10680
10893
  const th=el(doc,'th');
10681
- setText(th,bound.labels[i]);
10894
+ setText(th,shown.labels[i]);
10682
10895
  tr.appendChild(th);
10683
- for(const series of bound.series||[]){
10896
+ for(const series of table_){
10684
10897
  const td=el(doc,'td');
10685
10898
  const point=series.points[i];
10686
10899
  setText(td,point&&point.y!==null?measureText(point.y,messages):'');