@bicharts/chart-host 0.5.97 → 0.5.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -11,13 +11,15 @@ import {
11
11
  ANIM_PLAY_SPEED_MAX,
12
12
  ANIM_PLAY_SPEED_MIN,
13
13
  APPROXIMATE_POSITIONS_DEFAULT,
14
+ AUTO_RAMP_CLASSES,
15
+ AUTO_RAMP_DRAWN_OPACITY,
16
+ AUTO_RAMP_MIN_STEP_DELTA_E,
14
17
  AXIS_FILTER_CLASS,
15
18
  AXIS_PIN_BAND_PAD_PX,
16
19
  AXIS_PIN_MAX_BAND_FRACTION,
17
20
  AXIS_PIN_MIN_LABELS,
18
21
  AXIS_PIN_TRACK_REACH_PX,
19
22
  BACKING_MAJORITY,
20
- Bt,
21
23
  COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT,
22
24
  COLOR_SCALE_SELF_CLAMP_PCT_MAX,
23
25
  COLOR_SCALE_SELF_CLAMP_PCT_MIN,
@@ -28,20 +30,20 @@ import {
28
30
  DARK_TEXT,
29
31
  DIM_OPACITY_DEFAULT,
30
32
  DIM_OPACITY_VAR,
31
- De,
32
- Ee,
33
33
  FIT_CONTENT_SELECTOR,
34
34
  FLIP_MODE_DEFAULT,
35
35
  GEO_POINT_PRECISIONS,
36
36
  GLYPH_SAMPLE_N,
37
37
  HOST_CONTAINER_CLASS,
38
38
  HOST_CONTRACT_VERSION,
39
+ Kt,
39
40
  L3,
40
41
  LABEL_CONTRAST_CAP,
41
42
  LABEL_CONTRAST_DONE_ATTR,
42
43
  LEGEND_MARK_CLASS,
43
44
  LIFT_SELECTED_CLASS,
44
45
  LIGHT_TEXT,
46
+ Le,
45
47
  MARK_CLASS,
46
48
  MARK_SELECTED_CLASS,
47
49
  MAX_FRAME_GROW_FACTOR,
@@ -49,6 +51,7 @@ import {
49
51
  MIN_CONTRAST,
50
52
  MIN_HIT_BAND_PX,
51
53
  MIN_RAMP_FILLS,
54
+ Oe,
52
55
  PAGE_MATCH_TOLERANCE,
53
56
  PHANTOM_FRACTION,
54
57
  PILL_MIN_ALPHA,
@@ -60,10 +63,13 @@ import {
60
63
  SEASONAL_MARKERS_DEFAULT,
61
64
  SELECTION_ACTIVE_CLASS,
62
65
  VALUE_AXIS_BASELINE_DEFAULT,
66
+ VALUE_AXIS_MIN_FIT,
63
67
  WHITE_TEXT_BG_LUM,
64
68
  XFILTER_REFRESH_EVENT,
65
69
  Yt,
66
70
  applyLabelContrast,
71
+ autoRampCanvas,
72
+ autoRampMinStep,
67
73
  axisPinPlacement,
68
74
  backingHoldsGlyph,
69
75
  blankRenderFlag,
@@ -72,6 +78,7 @@ import {
72
78
  censusColourSpread,
73
79
  censusHitBands,
74
80
  censusMarks,
81
+ censusValuePlacement,
75
82
  chartOwnsTimeline,
76
83
  clearGeoCache,
77
84
  colourSpreadFlag,
@@ -111,6 +118,7 @@ import {
111
118
  registerGeoAsset,
112
119
  relativeLuminance,
113
120
  requiredD3Plugins,
121
+ resolveAutoColorScale,
114
122
  resolveOptions,
115
123
  scrollFitFor,
116
124
  sessionViewStateProvider,
@@ -118,8 +126,9 @@ import {
118
126
  svgInkReach,
119
127
  toRGBA,
120
128
  u,
121
- unpinScrolledAxis
122
- } from "./chunk-MX2AS5GG.mjs";
129
+ unpinScrolledAxis,
130
+ valuePlacementFlag
131
+ } from "./chunk-B2DWID7P.mjs";
123
132
  import "./chunk-A2GMXZP7.mjs";
124
133
  import "./chunk-GHODWOAL.mjs";
125
134
 
@@ -1239,15 +1248,15 @@ function displayText(col, raw, opts) {
1239
1248
  return String(raw);
1240
1249
  }
1241
1250
  function isSuppressed(col) {
1242
- return Ee(col).suppressed;
1251
+ return Oe(col).suppressed;
1243
1252
  }
1244
1253
  function resolveAgg(col, requested, auto) {
1245
1254
  const fallback = () => {
1246
- const d2 = Bt(col);
1255
+ const d2 = Yt(col);
1247
1256
  return d2 === "first" ? "count" : d2;
1248
1257
  };
1249
1258
  if (auto) return fallback();
1250
- return De(col).indexOf(requested) >= 0 ? requested : fallback();
1259
+ return Le(col).indexOf(requested) >= 0 ? requested : fallback();
1251
1260
  }
1252
1261
  function toNumber(v2) {
1253
1262
  if (v2 == null || v2 === "") return null;
@@ -1350,7 +1359,7 @@ function computeSelectionCard(payload, selectedRowIdxs, opts = {}) {
1350
1359
  }
1351
1360
  const value = reduce(selVals, colAgg, selRaw);
1352
1361
  let sharePct = null;
1353
- if (Yt(col, colAgg) && value != null) {
1362
+ if (Kt(col, colAgg) && value != null) {
1354
1363
  const allVals = [];
1355
1364
  const allRaw = [];
1356
1365
  for (let r2 = 0; r2 < rows.length; r2++) {
@@ -2099,6 +2108,9 @@ export {
2099
2108
  ANIM_PLAY_SPEED_MAX,
2100
2109
  ANIM_PLAY_SPEED_MIN,
2101
2110
  APPROXIMATE_POSITIONS_DEFAULT,
2111
+ AUTO_RAMP_CLASSES,
2112
+ AUTO_RAMP_DRAWN_OPACITY,
2113
+ AUTO_RAMP_MIN_STEP_DELTA_E,
2102
2114
  AXIS_FILTER_CLASS,
2103
2115
  AXIS_PIN_BAND_PAD_PX,
2104
2116
  AXIS_PIN_MAX_BAND_FRACTION,
@@ -2154,11 +2166,14 @@ export {
2154
2166
  SEASONAL_MARKERS_DEFAULT,
2155
2167
  SELECTION_ACTIVE_CLASS,
2156
2168
  VALUE_AXIS_BASELINE_DEFAULT,
2169
+ VALUE_AXIS_MIN_FIT,
2157
2170
  WHITE_TEXT_BG_LUM,
2158
2171
  XFILTER_REFRESH_EVENT,
2159
2172
  actionFor,
2160
2173
  applyLabelContrast,
2161
2174
  askApplyImprovements,
2175
+ autoRampCanvas,
2176
+ autoRampMinStep,
2162
2177
  axisPinPlacement,
2163
2178
  backingHoldsGlyph,
2164
2179
  bareBase64,
@@ -2173,6 +2188,7 @@ export {
2173
2188
  censusColourSpread,
2174
2189
  censusHitBands,
2175
2190
  censusMarks,
2191
+ censusValuePlacement,
2176
2192
  chartOwnsTimeline,
2177
2193
  chooserFitsViewport,
2178
2194
  clearGeoCache,
@@ -2248,6 +2264,7 @@ export {
2248
2264
  registerGeoAsset,
2249
2265
  relativeLuminance,
2250
2266
  requiredD3Plugins,
2267
+ resolveAutoColorScale,
2251
2268
  resolveOptions,
2252
2269
  scrollFitFor,
2253
2270
  sessionViewStateProvider,
@@ -2259,5 +2276,6 @@ export {
2259
2276
  svgNaturalSize,
2260
2277
  svgToDataUrl,
2261
2278
  toRGBA,
2262
- unpinScrolledAxis
2279
+ unpinScrolledAxis,
2280
+ valuePlacementFlag
2263
2281
  };
package/dist/react.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  createChartHost,
5
5
  geoFromCache,
6
6
  loadGeo
7
- } from "./chunk-MX2AS5GG.mjs";
7
+ } from "./chunk-B2DWID7P.mjs";
8
8
  import "./chunk-A2GMXZP7.mjs";
9
9
  import "./chunk-GHODWOAL.mjs";
10
10
 
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Classes the automatic ramp must keep apart. A binned legend rarely carries more than seven, and
3
+ * the chart that raised this drew six; ColorBrewer's sequential schemes stop at nine because past
4
+ * that no ramp of one hue separates its neighbours. A chart drawing fewer classes gets wider steps.
5
+ */
6
+ export declare const AUTO_RAMP_CLASSES = 7;
7
+ /**
8
+ * The fill-opacity the guarantee is made at. Dense dot charts paint at 0.5 so overlaps stay
9
+ * readable, and that halves every colour difference against a light canvas; a guarantee made at
10
+ * full opacity would be broken by exactly the charts that need it most. Opaque fills get more.
11
+ */
12
+ export declare const AUTO_RAMP_DRAWN_OPACITY = 0.5;
13
+ /**
14
+ * Minimum CIEDE2000 between neighbouring classes as painted: 2.3, the just-noticeable difference
15
+ * usually quoted for colour patches side by side. CIEDE2000 was fitted so that its own threshold
16
+ * sits nearer 1, so this errs towards more separation, which is the safe direction for a legend.
17
+ */
18
+ export declare const AUTO_RAMP_MIN_STEP_DELTA_E = 2.3;
19
+ export interface AutoColorScaleInput {
20
+ palette?: string[] | null;
21
+ backgroundColor?: string | null;
22
+ themeBg?: string | null;
23
+ themeFg?: string | null;
24
+ themeAccent?: string | null;
25
+ isHighContrast?: boolean | null;
26
+ }
27
+ export interface AutoColorScale {
28
+ low: string;
29
+ high: string;
30
+ }
31
+ /** The smallest neighbour-to-neighbour distance of the ramp, as painted. */
32
+ export declare function autoRampMinStep(low: string, high: string, canvas: string, classes?: number, opacity?: number): number;
33
+ /** The canvas the ramp is painted on: the visual's own background, else the theme's, else white. */
34
+ export declare function autoRampCanvas(p: AutoColorScaleInput): string;
35
+ /**
36
+ * The automatic Low and High colours for a continuous colour scale. Deterministic, never throws,
37
+ * and cheap enough to call on every render (the last answer is kept for the same inputs).
38
+ */
39
+ export declare function resolveAutoColorScale(p: AutoColorScaleInput): AutoColorScale;
@@ -1,4 +1,4 @@
1
- export declare const HOST_CONTRACT_VERSION = "1.7.0";
1
+ export declare const HOST_CONTRACT_VERSION = "1.8.0";
2
2
  export type GeoPointPrecision = "latlon" | "city" | "zip3" | "state" | "country";
3
3
  /** Every valid tier, ordered most precise → coarsest. Runtime form of GeoPointPrecision. */
4
4
  export declare const GEO_POINT_PRECISIONS: readonly GeoPointPrecision[];
@@ -111,6 +111,8 @@ export interface RenderOptions {
111
111
  seasonalMarkers?: SeasonalMarkers;
112
112
  colorScaleLow?: string;
113
113
  colorScaleHigh?: string;
114
+ colorScaleAutoLow?: string;
115
+ colorScaleAutoHigh?: string;
114
116
  colorScaleScope?: ColorScaleScope;
115
117
  colorScaleSelfClampPct?: number;
116
118
  geoLandColor?: string;
@@ -20,5 +20,11 @@ export declare function hexToLab(hex: string): Lab | null;
20
20
  * sequential ramp spends most of its length in.
21
21
  */
22
22
  export declare function deltaE2000(c1: Lab, c2: Lab): number;
23
+ /**
24
+ * CIE L*a*b* (D65) back to `#rrggbb`: the exact inverse of `rgbToLab`, with each channel clipped
25
+ * into the sRGB gamut. A Lab point outside the gamut comes back as the nearest channel-clipped
26
+ * colour, which is what a browser would paint anyway.
27
+ */
28
+ export declare function labToHex(lab: Lab): string;
23
29
  /** CIEDE2000 between two `#rrggbb` colours. NaN when either cannot be parsed. */
24
30
  export declare function deltaEHex(a: string, b: string): number;
@@ -3,6 +3,7 @@ import { type ResolveOptionsInput } from "./defaults";
3
3
  import { type MarkCensus } from "./blankRender";
4
4
  import { type HitBandCensus } from "./hitBands";
5
5
  import { type ColourSpreadCensus } from "./colourSpread";
6
+ import { type ValuePlacementCensus } from "./valuePlacement";
6
7
  import { type FitRenderedChartOptions, type FitRenderedChartResult } from "./fitDom";
7
8
  import { type LabelContrastOptions, type LabelContrastReport } from "./labelContrastDom";
8
9
  export type RenderFn = (container: HTMLElement, data: any, options: RenderOptions) => void;
@@ -108,6 +109,17 @@ export interface ChartHostConfig {
108
109
  * own skew is measured on the raw column while the ramp encodes an aggregate.
109
110
  */
110
111
  onColourSpreadCensus?: (census: ColourSpreadCensus) => void;
112
+ /**
113
+ * IS EACH DOT DRAWN AT ITS VALUE? Runs after every render, counts only.
114
+ *
115
+ * A chart drawing one dot per row along a value axis promises that a dot's position IS its
116
+ * value, and a force layout breaks that promise without a trace in the code: collision pushes
117
+ * dots along both axes, so on a dense column they drift off their values and pile against the
118
+ * band walls. This reads each single-row circle back to its row, finds the value axis as the
119
+ * column a straight line through the positions explains, and reports the share of dots more than
120
+ * a radius off it. It declines on anything that is not that shape.
121
+ */
122
+ onValuePlacementCensus?: (census: ValuePlacementCensus) => void;
111
123
  /** This chart declares time keyframes: frame one is allowed to be empty, so no blank verdict
112
124
  * is issued for it. */
113
125
  animated?: boolean;
@@ -23,9 +23,11 @@ export { decideLabelColor, toRGBA, compositeOver, relativeLuminance, contrastRat
23
23
  export { censusMarks, isBlankRender, blankRenderFlag, type MarkCensus, type BlankVerdictInput } from "./blankRender";
24
24
  export { censusHitBands, hitBandFlag, MIN_HIT_BAND_PX, type HitBandCensus } from "./hitBands";
25
25
  export { censusColourSpread, colourSpreadFlag, SAME_SHADE_DELTA_E, MIN_RAMP_FILLS, type ColourSpreadCensus } from "./colourSpread";
26
+ export { censusValuePlacement, valuePlacementFlag, VALUE_AXIS_MIN_FIT, type ValuePlacementCensus } from "./valuePlacement";
26
27
  export { SCROLL_SLACK_PX, MAX_FRAME_GROW_FACTOR, PHANTOM_FRACTION, FIT_CONTENT_SELECTOR, needsScroll, contentExtentOf, scrollFitFor, planFrameGrow, isPhantomBox, type MeasuredBox, type ContentExtent, type ScrollFit, type FrameGrowPlan, } from "./fit";
27
28
  export { fitRenderedChart, fitReadingFor, measureContainerBoxes, svgInkReach, ctmScaleOf, type FitReading, type InkReach, type FitRenderedChartOptions, type FitRenderedChartResult, } from "./fitDom";
28
29
  export { AXIS_PIN_MIN_LABELS, AXIS_PIN_BAND_PAD_PX, AXIS_PIN_MAX_BAND_FRACTION, AXIS_PIN_TRACK_REACH_PX, isHorizontalLabelRow, labelBand, planAxisPin, axisPinPlacement, type LabelRowBox, type AxisBand, type AxisPinCandidate, type AxisPinPlan, type AxisPinEdge, } from "./fit";
29
30
  export { pinScrolledAxis, unpinScrolledAxis, type AxisPinReport } from "./fitDom";
30
31
  export { MIN_DELTA_E, pickDistinctColorFromSeed, buildPalette, buildPaletteFromSeed, orderMostDistinct, LEGIBLE_LIGHTNESS, type PaletteResult, type SeedForSlot, type PaletteOptions, } from "./palette";
31
32
  export { deltaEHex } from "./deltaE";
33
+ export { resolveAutoColorScale, autoRampMinStep, autoRampCanvas, AUTO_RAMP_CLASSES, AUTO_RAMP_DRAWN_OPACITY, AUTO_RAMP_MIN_STEP_DELTA_E, type AutoColorScale, type AutoColorScaleInput } from "./autoRamp";
@@ -0,0 +1,34 @@
1
+ /** A straight line must explain at least this share of the positions to call it the value axis. */
2
+ export declare const VALUE_AXIS_MIN_FIT = 0.8;
3
+ export interface ValuePlacementCensus {
4
+ /** Dots measured: circles carrying exactly one row index. 0 = the census declined. */
5
+ marks: number;
6
+ /** The screen axis the values run along, and the column they encode. */
7
+ axis: "x" | "y" | "";
8
+ column: string;
9
+ /** How well the fitted line explains the positions (1 = every dot on its value). */
10
+ fit: number;
11
+ /** Share (0-100) of the dots more than one radius from their value. */
12
+ offShare: number;
13
+ /** Median distance, in radii, between a dot and its value. */
14
+ medianOffRadii: number;
15
+ }
16
+ /**
17
+ * Where do the dots sit against their values? Never throws; declines with `marks: 0`.
18
+ * `rows` are the rows the chart was handed, indexed exactly as data-row-idx indexes them.
19
+ */
20
+ export declare function censusValuePlacement(container: any, data: {
21
+ columns?: {
22
+ name: string;
23
+ }[];
24
+ rows?: any[][];
25
+ } | null | undefined): ValuePlacementCensus;
26
+ /**
27
+ * The always-on behaviour tag, or "" when the census declined.
28
+ *
29
+ * `place:d3:off0` no dot more than a radius from its value; `off1` some, under 5%; `off5` 5-20%;
30
+ * `off20` 20-50%; `off50` half or more. Finer at the bottom than the colour census's twenty-point
31
+ * buckets on purpose: a correct layout reports exactly zero, so the first few percent are the
32
+ * interesting ones.
33
+ */
34
+ export declare function valuePlacementFlag(c: ValuePlacementCensus): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bicharts/chart-host",
3
- "version": "0.5.97",
3
+ "version": "0.5.99",
4
4
  "description": "Run a BIC-generated D3 chart in any web host: compiles the generated render() function, applies the shared option defaults, resolves mark clicks (through tooltip overlays), owns the selection affordance, and translates row indices between cross-filtered charts. The same contract the BIC Power BI visual implements, minus Power BI. React bindings at @bicharts/chart-host/react.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",