@voila.dev/chart 4.0.0 → 4.0.108

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 (73) hide show
  1. package/dist/canvas/paint-scene.d.ts.map +1 -1
  2. package/dist/canvas/paint-scene.js +31 -1
  3. package/dist/canvas/paint-scene.js.map +2 -2
  4. package/dist/core/marks/area.d.ts.map +1 -1
  5. package/dist/core/marks/area.js +3 -2
  6. package/dist/core/marks/area.js.map +2 -2
  7. package/dist/core/marks/bar.d.ts +5 -0
  8. package/dist/core/marks/bar.d.ts.map +1 -1
  9. package/dist/core/marks/bar.js +19 -9
  10. package/dist/core/marks/bar.js.map +2 -2
  11. package/dist/core/marks/cell.d.ts.map +1 -1
  12. package/dist/core/marks/cell.js +2 -1
  13. package/dist/core/marks/cell.js.map +2 -2
  14. package/dist/core/marks/dot.d.ts.map +1 -1
  15. package/dist/core/marks/dot.js +2 -1
  16. package/dist/core/marks/dot.js.map +2 -2
  17. package/dist/core/marks/funnel.d.ts.map +1 -1
  18. package/dist/core/marks/funnel.js +3 -2
  19. package/dist/core/marks/funnel.js.map +2 -2
  20. package/dist/core/marks/line.d.ts.map +1 -1
  21. package/dist/core/marks/line.js +2 -1
  22. package/dist/core/marks/line.js.map +2 -2
  23. package/dist/core/marks/polar.d.ts.map +1 -1
  24. package/dist/core/marks/polar.js +5 -4
  25. package/dist/core/marks/polar.js.map +2 -2
  26. package/dist/core/marks/rect.d.ts.map +1 -1
  27. package/dist/core/marks/rect.js +2 -1
  28. package/dist/core/marks/rect.js.map +2 -2
  29. package/dist/core/marks/shared.d.ts +8 -2
  30. package/dist/core/marks/shared.d.ts.map +1 -1
  31. package/dist/core/marks/shared.js +4 -0
  32. package/dist/core/marks/shared.js.map +2 -2
  33. package/dist/core/marks/stats/dodge.d.ts.map +1 -1
  34. package/dist/core/marks/stats/dodge.js +2 -1
  35. package/dist/core/marks/stats/dodge.js.map +2 -2
  36. package/dist/core/marks/stats/histogram.d.ts.map +1 -1
  37. package/dist/core/marks/stats/histogram.js +2 -1
  38. package/dist/core/marks/stats/histogram.js.map +2 -2
  39. package/dist/core/marks/stats/waffle.d.ts.map +1 -1
  40. package/dist/core/marks/stats/waffle.js +3 -2
  41. package/dist/core/marks/stats/waffle.js.map +2 -2
  42. package/dist/core/types.d.ts +2 -0
  43. package/dist/core/types.d.ts.map +1 -1
  44. package/dist/react/chart-placeholders.d.ts +13 -0
  45. package/dist/react/chart-placeholders.d.ts.map +1 -0
  46. package/dist/react/chart-placeholders.js +77 -0
  47. package/dist/react/chart-placeholders.js.map +7 -0
  48. package/dist/react/index.d.ts +1 -0
  49. package/dist/react/index.d.ts.map +1 -1
  50. package/dist/react/index.js +3 -0
  51. package/dist/react/index.js.map +2 -2
  52. package/dist/react/svg-scene.d.ts +1 -1
  53. package/dist/react/svg-scene.d.ts.map +1 -1
  54. package/dist/react/svg-scene.js +53 -10
  55. package/dist/react/svg-scene.js.map +2 -2
  56. package/package.json +1 -1
  57. package/src/canvas/paint-scene.ts +45 -1
  58. package/src/core/marks/area.ts +2 -1
  59. package/src/core/marks/bar.ts +25 -8
  60. package/src/core/marks/cell.ts +2 -1
  61. package/src/core/marks/dot.ts +2 -1
  62. package/src/core/marks/funnel.ts +2 -1
  63. package/src/core/marks/line.ts +2 -1
  64. package/src/core/marks/polar.ts +4 -3
  65. package/src/core/marks/rect.ts +2 -1
  66. package/src/core/marks/shared.ts +15 -2
  67. package/src/core/marks/stats/dodge.ts +2 -1
  68. package/src/core/marks/stats/histogram.ts +2 -1
  69. package/src/core/marks/stats/waffle.ts +2 -1
  70. package/src/core/types.ts +2 -0
  71. package/src/react/chart-placeholders.tsx +93 -0
  72. package/src/react/index.ts +1 -0
  73. package/src/react/svg-scene.tsx +72 -11
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/line.ts"],
4
- "sourcesContent": ["import { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tgroupBySeries,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport { type ChartXY, linePath } from \"#/core/paths.ts\";\nimport type {\n\tChartAccessor,\n\tChartCurve,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface LineOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\treadonly stroke?: string;\n\treadonly strokeWidth?: number;\n\treadonly strokeDasharray?: string;\n\treadonly curve?: ChartCurve;\n\t/** A dot on every point, not only on the focused one. */\n\treadonly dots?: boolean;\n}\n\nconst DEFAULT_STROKE_WIDTH = 2;\nconst DOT_RADIUS = 3;\n\n/** With no accessor, a line of plain numbers plots each against its index. */\nfunction positionAccessor<TDatum>(\n\taccessor: ChartAccessor<TDatum, ChartValue> | undefined,\n\tfallback: \"index\" | \"identity\",\n): ChartAccessor<TDatum, ChartValue> {\n\tif (accessor !== undefined) {\n\t\treturn accessor;\n\t}\n\treturn fallback === \"index\"\n\t\t? (_datum, index) => index\n\t\t: (datum) => datum as unknown as ChartValue;\n}\n\nfunction lineMark<TDatum>(\n\tkind: \"lineY\" | \"lineX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: LineOptions<TDatum>,\n): ChartMark {\n\t// lineY: the value runs up the y axis; lineX: along x, positions down y.\n\tconst vertical = kind === \"lineY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(data, positionAccessor(positionKey, \"index\"));\n\tconst values = readChannel(data, positionAccessor(valueKey, \"identity\"));\n\tconst colors = colorChannel(data, options);\n\tconst positionChannel = {\n\t\tvalues: positions.filter(isPlaceable),\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: values.filter(isPlaceable),\n\t\tlabel: channelLabel(valueKey) ?? options.label,\n\t};\n\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: vertical ? \"x\" : \"y\",\n\t\tchannels: {\n\t\t\tx: vertical ? positionChannel : valueChannel,\n\t\t\ty: vertical ? valueChannel : positionChannel,\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, kind, context);\n\t\t\tconst positionScale = vertical ? context.scales.x : context.scales.y;\n\t\t\tconst valueScale = vertical ? context.scales.y : context.scales.x;\n\t\t\tif (positionScale === undefined || valueScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.stroke },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst lines: SceneNode[] = [];\n\t\t\tconst dots: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\n\t\t\tfor (const { series, indices } of groupBySeries(\n\t\t\t\tdata.length,\n\t\t\t\tseriesOf,\n\t\t\t).values()) {\n\t\t\t\t// A gap in the data is a gap in the line, not a dive to zero.\n\t\t\t\tconst runs: ChartXY[][] = [[]];\n\t\t\t\tfor (const index of indices) {\n\t\t\t\t\tconst position = positions[index];\n\t\t\t\t\tconst value = valueOn(valueScale, values[index]);\n\t\t\t\t\tif (!isPlaceable(position) || value === undefined) {\n\t\t\t\t\t\truns.push([]);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst along = positionScale.center(position);\n\t\t\t\t\tconst across = valueScale.center(value);\n\t\t\t\t\tconst xy = vertical\n\t\t\t\t\t\t? { x: along, y: across }\n\t\t\t\t\t\t: { x: across, y: along };\n\t\t\t\t\truns[runs.length - 1].push(xy);\n\t\t\t\t\tif (options.tip !== false) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\t\tx: xy.x,\n\t\t\t\t\t\t\ty: xy.y,\n\t\t\t\t\t\t\txValue: vertical ? position : value,\n\t\t\t\t\t\t\tyValue: vertical ? value : position,\n\t\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\t\ttitle: vertical\n\t\t\t\t\t\t\t\t? context.formatX(position)\n\t\t\t\t\t\t\t\t: context.formatY(position),\n\t\t\t\t\t\t\tvalue: vertical ? context.formatY(value) : context.formatX(value),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (options.dots) {\n\t\t\t\t\t\tdots.push({\n\t\t\t\t\t\t\tkind: \"circle\",\n\t\t\t\t\t\t\tkey: `${id}:dot:${index}`,\n\t\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t\t\tcx: xy.x,\n\t\t\t\t\t\t\tcy: xy.y,\n\t\t\t\t\t\t\tr: DOT_RADIUS,\n\t\t\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\t\t\tstroke: context.theme.background,\n\t\t\t\t\t\t\t\tstrokeWidth: 1.5,\n\t\t\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst d = runs\n\t\t\t\t\t.map((run) => linePath(run, options.curve))\n\t\t\t\t\t.filter((part) => part !== \"\")\n\t\t\t\t\t.join(\"\");\n\t\t\t\tlines.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:line:${series.key}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td,\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tstroke: series.color,\n\t\t\t\t\t\tstrokeWidth: options.strokeWidth ?? DEFAULT_STROKE_WIDTH,\n\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\n\t\t\t\t\t\tstrokeLinecap: \"round\",\n\t\t\t\t\t\tstrokeLinejoin: \"round\",\n\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst legend =\n\t\t\t\toptions.color === undefined && options.label !== undefined\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: id,\n\t\t\t\t\t\t\t\tlabel: options.label,\n\t\t\t\t\t\t\t\tcolor:\n\t\t\t\t\t\t\t\t\toptions.stroke ?? context.paletteColor(context.markIndex),\n\t\t\t\t\t\t\t\tshape: options.strokeDasharray\n\t\t\t\t\t\t\t\t\t? (\"dashed\" as const)\n\t\t\t\t\t\t\t\t\t: (\"line\" as const),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: [];\n\t\t\treturn { nodes: [...lines, ...dots], points, legend };\n\t\t},\n\t};\n}\n\n/** A line whose value runs up the y axis, over x positions: a time series. */\nexport function lineY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: LineOptions<TDatum> = {},\n): ChartMark {\n\treturn lineMark(\"lineY\", data, options);\n}\n\n/** A line whose value runs along x, over y positions. */\nexport function lineX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: LineOptions<TDatum> = {},\n): ChartMark {\n\treturn lineMark(\"lineX\", data, options);\n}\n"],
5
- "mappings": "AAAA,SAAS,cAAc,aAAa,mBAAmB;AACvD;AAAA,EAEC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAuB,gBAAgB;AAqBvC,MAAM,uBAAuB;AAC7B,MAAM,aAAa;AAGnB,SAAS,iBACR,UACA,UACoC;AACpC,MAAI,aAAa,QAAW;AAC3B,WAAO;AAAA,EACR;AACA,SAAO,aAAa,UACjB,CAAC,QAAQ,UAAU,QACnB,CAAC,UAAU;AACf;AAEA,SAAS,SACR,MACA,MACA,SACY;AAEZ,QAAM,WAAW,SAAS;AAC1B,QAAM,cAAc,WAAW,QAAQ,IAAI,QAAQ;AACnD,QAAM,WAAW,WAAW,QAAQ,IAAI,QAAQ;AAChD,QAAM,YAAY,YAAY,MAAM,iBAAiB,aAAa,OAAO,CAAC;AAC1E,QAAM,SAAS,YAAY,MAAM,iBAAiB,UAAU,UAAU,CAAC;AACvE,QAAM,SAAS,aAAa,MAAM,OAAO;AACzC,QAAM,kBAAkB;AAAA,IACvB,QAAQ,UAAU,OAAO,WAAW;AAAA,IACpC,OAAO,aAAa,WAAW;AAAA,EAChC;AACA,QAAM,eAAe;AAAA,IACpB,QAAQ,OAAO,OAAO,WAAW;AAAA,IACjC,OAAO,aAAa,QAAQ,KAAK,QAAQ;AAAA,EAC1C;AAEA,SAAO;AAAA,IACN,IAAI,QAAQ;AAAA,IACZ,YAAY;AAAA,IACZ,YAAY,WAAW,MAAM;AAAA,IAC7B,UAAU;AAAA,MACT,GAAG,WAAW,kBAAkB;AAAA,MAChC,GAAG,WAAW,eAAe;AAAA,MAC7B,OAAO,OAAO;AAAA,IACf;AAAA,IACA,OAAO,SAAS;AACf,YAAM,KAAK,OAAO,QAAQ,IAAI,MAAM,OAAO;AAC3C,YAAM,gBAAgB,WAAW,QAAQ,OAAO,IAAI,QAAQ,OAAO;AACnE,YAAM,aAAa,WAAW,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAChE,UAAI,kBAAkB,UAAa,eAAe,QAAW;AAC5D,eAAO,EAAE,OAAO,CAAC,EAAE;AAAA,MACpB;AACA,YAAM,WAAW;AAAA,QAChB,OAAO;AAAA,QACP,EAAE,GAAG,SAAS,YAAY,QAAQ,OAAO;AAAA,QACzC;AAAA,QACA;AAAA,MACD;AACA,YAAM,QAAqB,CAAC;AAC5B,YAAM,OAAoB,CAAC;AAC3B,YAAM,SAAuB,CAAC;AAE9B,iBAAW,EAAE,QAAQ,QAAQ,KAAK;AAAA,QACjC,KAAK;AAAA,QACL;AAAA,MACD,EAAE,OAAO,GAAG;AAEX,cAAM,OAAoB,CAAC,CAAC,CAAC;AAC7B,mBAAW,SAAS,SAAS;AAC5B,gBAAM,WAAW,UAAU,KAAK;AAChC,gBAAM,QAAQ,QAAQ,YAAY,OAAO,KAAK,CAAC;AAC/C,cAAI,CAAC,YAAY,QAAQ,KAAK,UAAU,QAAW;AAClD,iBAAK,KAAK,CAAC,CAAC;AACZ;AAAA,UACD;AACA,gBAAM,QAAQ,cAAc,OAAO,QAAQ;AAC3C,gBAAM,SAAS,WAAW,OAAO,KAAK;AACtC,gBAAM,KAAK,WACR,EAAE,GAAG,OAAO,GAAG,OAAO,IACtB,EAAE,GAAG,QAAQ,GAAG,MAAM;AACzB,eAAK,KAAK,SAAS,CAAC,EAAE,KAAK,EAAE;AAC7B,cAAI,QAAQ,QAAQ,OAAO;AAC1B,mBAAO,KAAK;AAAA,cACX,KAAK,GAAG,EAAE,IAAI,KAAK;AAAA,cACnB,QAAQ;AAAA,cACR;AAAA,cACA,OAAO,KAAK,KAAK;AAAA,cACjB,GAAG,GAAG;AAAA,cACN,GAAG,GAAG;AAAA,cACN,QAAQ,WAAW,WAAW;AAAA,cAC9B,QAAQ,WAAW,QAAQ;AAAA,cAC3B,QAAQ,OAAO;AAAA,cACf,aAAa,OAAO;AAAA,cACpB,OAAO,OAAO;AAAA,cACd,OAAO,WACJ,QAAQ,QAAQ,QAAQ,IACxB,QAAQ,QAAQ,QAAQ;AAAA,cAC3B,OAAO,WAAW,QAAQ,QAAQ,KAAK,IAAI,QAAQ,QAAQ,KAAK;AAAA,YACjE,CAAC;AAAA,UACF;AACA,cAAI,QAAQ,MAAM;AACjB,iBAAK,KAAK;AAAA,cACT,MAAM;AAAA,cACN,KAAK,GAAG,EAAE,QAAQ,KAAK;AAAA,cACvB,QAAQ,OAAO;AAAA,cACf,MAAM;AAAA,cACN,IAAI,GAAG;AAAA,cACP,IAAI,GAAG;AAAA,cACP,GAAG;AAAA,cACH,OAAO,MAAM;AAAA,gBACZ,MAAM,OAAO;AAAA,gBACb,QAAQ,QAAQ,MAAM;AAAA,gBACtB,aAAa;AAAA,gBACb,SAAS,QAAQ;AAAA,cAClB,CAAC;AAAA,YACF,CAAC;AAAA,UACF;AAAA,QACD;AACA,cAAM,IAAI,KACR,IAAI,CAAC,QAAQ,SAAS,KAAK,QAAQ,KAAK,CAAC,EACzC,OAAO,CAAC,SAAS,SAAS,EAAE,EAC5B,KAAK,EAAE;AACT,cAAM,KAAK;AAAA,UACV,MAAM;AAAA,UACN,KAAK,GAAG,EAAE,SAAS,OAAO,GAAG;AAAA,UAC7B,QAAQ,OAAO;AAAA,UACf,MAAM;AAAA,UACN;AAAA,UACA,OAAO,MAAM;AAAA,YACZ,QAAQ,OAAO;AAAA,YACf,aAAa,QAAQ,eAAe;AAAA,YACpC,iBAAiB,QAAQ;AAAA,YACzB,eAAe;AAAA,YACf,gBAAgB;AAAA,YAChB,MAAM;AAAA,YACN,SAAS,QAAQ;AAAA,UAClB,CAAC;AAAA,QACF,CAAC;AAAA,MACF;AAEA,YAAM,SACL,QAAQ,UAAU,UAAa,QAAQ,UAAU,SAC9C;AAAA,QACA;AAAA,UACC,KAAK;AAAA,UACL,OAAO,QAAQ;AAAA,UACf,OACC,QAAQ,UAAU,QAAQ,aAAa,QAAQ,SAAS;AAAA,UACzD,OAAO,QAAQ,kBACX,WACA;AAAA,QACL;AAAA,MACD,IACC,CAAC;AACL,aAAO,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,GAAG,QAAQ,OAAO;AAAA,IACrD;AAAA,EACD;AACD;AAGO,SAAS,MACf,MACA,UAA+B,CAAC,GACpB;AACZ,SAAO,SAAS,SAAS,MAAM,OAAO;AACvC;AAGO,SAAS,MACf,MACA,UAA+B,CAAC,GACpB;AACZ,SAAO,SAAS,SAAS,MAAM,OAAO;AACvC;",
4
+ "sourcesContent": ["import { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tgroupBySeries,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\ttips,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport { type ChartXY, linePath } from \"#/core/paths.ts\";\nimport type {\n\tChartAccessor,\n\tChartCurve,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface LineOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\treadonly stroke?: string;\n\treadonly strokeWidth?: number;\n\treadonly strokeDasharray?: string;\n\treadonly curve?: ChartCurve;\n\t/** A dot on every point, not only on the focused one. */\n\treadonly dots?: boolean;\n}\n\nconst DEFAULT_STROKE_WIDTH = 2;\nconst DOT_RADIUS = 3;\n\n/** With no accessor, a line of plain numbers plots each against its index. */\nfunction positionAccessor<TDatum>(\n\taccessor: ChartAccessor<TDatum, ChartValue> | undefined,\n\tfallback: \"index\" | \"identity\",\n): ChartAccessor<TDatum, ChartValue> {\n\tif (accessor !== undefined) {\n\t\treturn accessor;\n\t}\n\treturn fallback === \"index\"\n\t\t? (_datum, index) => index\n\t\t: (datum) => datum as unknown as ChartValue;\n}\n\nfunction lineMark<TDatum>(\n\tkind: \"lineY\" | \"lineX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: LineOptions<TDatum>,\n): ChartMark {\n\t// lineY: the value runs up the y axis; lineX: along x, positions down y.\n\tconst vertical = kind === \"lineY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(data, positionAccessor(positionKey, \"index\"));\n\tconst values = readChannel(data, positionAccessor(valueKey, \"identity\"));\n\tconst colors = colorChannel(data, options);\n\tconst positionChannel = {\n\t\tvalues: positions.filter(isPlaceable),\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: values.filter(isPlaceable),\n\t\tlabel: channelLabel(valueKey) ?? options.label,\n\t};\n\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: vertical ? \"x\" : \"y\",\n\t\tchannels: {\n\t\t\tx: vertical ? positionChannel : valueChannel,\n\t\t\ty: vertical ? valueChannel : positionChannel,\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, kind, context);\n\t\t\tconst positionScale = vertical ? context.scales.x : context.scales.y;\n\t\t\tconst valueScale = vertical ? context.scales.y : context.scales.x;\n\t\t\tif (positionScale === undefined || valueScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.stroke },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst lines: SceneNode[] = [];\n\t\t\tconst dots: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\n\t\t\tfor (const { series, indices } of groupBySeries(\n\t\t\t\tdata.length,\n\t\t\t\tseriesOf,\n\t\t\t).values()) {\n\t\t\t\t// A gap in the data is a gap in the line, not a dive to zero.\n\t\t\t\tconst runs: ChartXY[][] = [[]];\n\t\t\t\tfor (const index of indices) {\n\t\t\t\t\tconst position = positions[index];\n\t\t\t\t\tconst value = valueOn(valueScale, values[index]);\n\t\t\t\t\tif (!isPlaceable(position) || value === undefined) {\n\t\t\t\t\t\truns.push([]);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst along = positionScale.center(position);\n\t\t\t\t\tconst across = valueScale.center(value);\n\t\t\t\t\tconst xy = vertical\n\t\t\t\t\t\t? { x: along, y: across }\n\t\t\t\t\t\t: { x: across, y: along };\n\t\t\t\t\truns[runs.length - 1].push(xy);\n\t\t\t\t\tif (tips(options.tip, data[index], index)) {\n\t\t\t\t\t\tpoints.push({\n\t\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\t\tindex,\n\t\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\t\tx: xy.x,\n\t\t\t\t\t\t\ty: xy.y,\n\t\t\t\t\t\t\txValue: vertical ? position : value,\n\t\t\t\t\t\t\tyValue: vertical ? value : position,\n\t\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\t\ttitle: vertical\n\t\t\t\t\t\t\t\t? context.formatX(position)\n\t\t\t\t\t\t\t\t: context.formatY(position),\n\t\t\t\t\t\t\tvalue: vertical ? context.formatY(value) : context.formatX(value),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tif (options.dots) {\n\t\t\t\t\t\tdots.push({\n\t\t\t\t\t\t\tkind: \"circle\",\n\t\t\t\t\t\t\tkey: `${id}:dot:${index}`,\n\t\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t\t\tcx: xy.x,\n\t\t\t\t\t\t\tcy: xy.y,\n\t\t\t\t\t\t\tr: DOT_RADIUS,\n\t\t\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\t\t\tstroke: context.theme.background,\n\t\t\t\t\t\t\t\tstrokeWidth: 1.5,\n\t\t\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst d = runs\n\t\t\t\t\t.map((run) => linePath(run, options.curve))\n\t\t\t\t\t.filter((part) => part !== \"\")\n\t\t\t\t\t.join(\"\");\n\t\t\t\tlines.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:line:${series.key}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td,\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tstroke: series.color,\n\t\t\t\t\t\tstrokeWidth: options.strokeWidth ?? DEFAULT_STROKE_WIDTH,\n\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\n\t\t\t\t\t\tstrokeLinecap: \"round\",\n\t\t\t\t\t\tstrokeLinejoin: \"round\",\n\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst legend =\n\t\t\t\toptions.color === undefined && options.label !== undefined\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: id,\n\t\t\t\t\t\t\t\tlabel: options.label,\n\t\t\t\t\t\t\t\tcolor:\n\t\t\t\t\t\t\t\t\toptions.stroke ?? context.paletteColor(context.markIndex),\n\t\t\t\t\t\t\t\tshape: options.strokeDasharray\n\t\t\t\t\t\t\t\t\t? (\"dashed\" as const)\n\t\t\t\t\t\t\t\t\t: (\"line\" as const),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: [];\n\t\t\treturn { nodes: [...lines, ...dots], points, legend };\n\t\t},\n\t};\n}\n\n/** A line whose value runs up the y axis, over x positions: a time series. */\nexport function lineY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: LineOptions<TDatum> = {},\n): ChartMark {\n\treturn lineMark(\"lineY\", data, options);\n}\n\n/** A line whose value runs along x, over y positions. */\nexport function lineX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: LineOptions<TDatum> = {},\n): ChartMark {\n\treturn lineMark(\"lineX\", data, options);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"polar.d.ts","sourceRoot":"","sources":["../../../src/core/marks/polar.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"polar.d.ts","sourceRoot":"","sources":["../../../src/core/marks/polar.ts"],"names":[],"mappings":"AAOA,OAAO,EACN,KAAK,gBAAgB,EAKrB,MAAM,wBAAwB,CAAC;AAShC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAIT,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAiCzB,UAAU,UAAU;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,QAAQ,SAAI,EACZ,UAAU,SAAI,EACd,QAAQ,SAAY,GAClB,aAAa,CAAC,UAAU,CAAC,CAsB3B;AAED,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACnE,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAID,6EAA6E;AAC7E,wBAAgB,GAAG,CAAC,MAAM,EACzB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,GACzB,SAAS,CA6FX;AAED,0DAA0D;AAC1D,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,GACzB,SAAS,CAEX;AAED,MAAM,WAAW,gBAAgB,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACzE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,mFAAmF;IACnF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,MAAM,EAC/B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B,SAAS,CA+FX;AAED,MAAM,WAAW,YAAY,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACrE,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACjD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAgFD,6FAA6F;AAC7F,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,GAC3B,SAAS,CAoIX"}
@@ -8,7 +8,8 @@ import { formatPercentage } from "../format.js";
8
8
  import {
9
9
  markId,
10
10
  paint,
11
- seriesResolver
11
+ seriesResolver,
12
+ tips
12
13
  } from "./shared.js";
13
14
  import {
14
15
  arcPath,
@@ -117,7 +118,7 @@ function arc(data, options) {
117
118
  opacity: options.opacity
118
119
  })
119
120
  });
120
- if (options.tip === false) {
121
+ if (!tips(options.tip, data[index], index)) {
121
122
  continue;
122
123
  }
123
124
  const middle = (angle.startAngle + angle.endAngle) / 2;
@@ -213,7 +214,7 @@ function radialBar(data, options) {
213
214
  d: arcPath(shape),
214
215
  paint: paint({ fill: series.color, opacity: options.opacity })
215
216
  });
216
- if (options.tip === false) {
217
+ if (!tips(options.tip, data[index], index)) {
217
218
  continue;
218
219
  }
219
220
  const anchor = polarToCartesian(
@@ -375,7 +376,7 @@ function radar(data, options) {
375
376
  };
376
377
  polygon.vertices[spoke] = vertex;
377
378
  polygons.set(series.key, polygon);
378
- if (options.tip !== false) {
379
+ if (tips(options.tip, data[index], index)) {
379
380
  points.push({
380
381
  key: `${id}:${index}`,
381
382
  markId: id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/polar.ts"],
4
- "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { formatPercentage } from \"#/core/format.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n} from \"#/core/marks/shared.ts\";\nimport {\n\tarcPath,\n\ttype ChartXY,\n\tpolarToCartesian,\n\tpolygonPath,\n} from \"#/core/paths.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport { niceDomain } from \"#/core/ticks.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartMarkContext,\n\tChartPoint,\n\tChartRect,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\n/**\n * Round marks. They own the whole plot rather than sitting on x and y\n * scales; their slices are coloured by category, which is what the legend\n * lists. Angles are degrees clockwise from twelve o'clock.\n */\n\nconst FULL_TURN = 360;\nconst EDGE = 4;\n\ninterface Frame {\n\treadonly cx: number;\n\treadonly cy: number;\n\treadonly radius: number;\n}\n\n/**\n * The circle a round mark is drawn in: centred, as large as the plot allows\n * once `insetX` (left and right) and `insetY` (top and bottom) are kept clear\n * for labels drawn outside it.\n */\nfunction frameOf(plot: ChartRect, insetX = 0, insetY = insetX): Frame {\n\treturn {\n\t\tcx: plot.x + plot.width / 2,\n\t\tcy: plot.y + plot.height / 2,\n\t\tradius: Math.max(\n\t\t\t0,\n\t\t\tMath.min(plot.width / 2 - insetX, plot.height / 2 - insetY) - EDGE,\n\t\t),\n\t};\n}\n\ninterface SliceAngle {\n\treadonly startAngle: number;\n\treadonly endAngle: number;\n\treadonly fraction: number;\n}\n\n/**\n * Splits a turn between values, proportionally. Negative values count as\n * zero: a pie of signed numbers has no honest reading.\n */\nexport function sliceAngles(\n\tvalues: ReadonlyArray<number>,\n\tpadAngle = 0,\n\tstartAngle = 0,\n\tendAngle = FULL_TURN,\n): ReadonlyArray<SliceAngle> {\n\tconst positives = values.map((value) =>\n\t\tNumber.isFinite(value) && value > 0 ? value : 0,\n\t);\n\tconst total = positives.reduce((sum, value) => sum + value, 0);\n\tconst pads = positives.filter((value) => value > 0).length > 1 ? padAngle : 0;\n\tconst available = Math.max(\n\t\t0,\n\t\tendAngle - startAngle - pads * positives.length,\n\t);\n\tlet cursor = startAngle;\n\treturn positives.map((value) => {\n\t\tconst fraction = total === 0 ? 0 : value / total;\n\t\tconst sweep = available * fraction;\n\t\tconst slice = {\n\t\t\tstartAngle: cursor + pads / 2,\n\t\t\tendAngle: cursor + pads / 2 + sweep,\n\t\t\tfraction,\n\t\t};\n\t\tcursor += sweep + pads;\n\t\treturn slice;\n\t});\n}\n\nexport interface ArcOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** The slice's name: what the legend, tooltip and table call it. */\n\treadonly category: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** Share of the radius left empty in the middle: 0 is a pie, 0.6 a donut. */\n\treadonly innerRadius?: number;\n\t/** Degrees of blank between two slices. */\n\treadonly padAngle?: number;\n\treadonly startAngle?: number;\n\treadonly endAngle?: number;\n\treadonly fill?: string;\n\treadonly stroke?: string;\n}\n\nconst DEFAULT_PAD_ANGLE = 1;\n\n/** A pie, or a donut with `innerRadius`: each datum a slice of the whole. */\nexport function arc<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ArcOptions<TDatum>,\n): ChartMark {\n\tconst categories = readChannel(data, options.category);\n\tconst values = readChannel(data, options.value).map(numericValue);\n\tconst colorAccessor = options.color ?? options.category;\n\tconst colors = readChannel(data, colorAccessor);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"frame\",\n\t\ttitles: {\n\t\t\tcategory: channelLabel(options.category),\n\t\t\tvalue: channelLabel(options.value) ?? options.label,\n\t\t},\n\t\tchannels: {\n\t\t\tcolor: {\n\t\t\t\tvalues: colors.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(colorAccessor),\n\t\t\t},\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"arc\", context);\n\t\t\tconst { cx, cy, radius } = frameOf(context.plot);\n\t\t\tconst inner = radius * (options.innerRadius ?? 0);\n\t\t\tconst angles = sliceAngles(\n\t\t\t\tvalues.map((value) => value ?? 0),\n\t\t\t\toptions.padAngle ?? DEFAULT_PAD_ANGLE,\n\t\t\t\toptions.startAngle,\n\t\t\t\toptions.endAngle,\n\t\t\t);\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors,\n\t\t\t\t{ ...options, color: colorAccessor, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, angle] of angles.entries()) {\n\t\t\t\tconst category = categories[index];\n\t\t\t\tconst value = values[index];\n\t\t\t\tif (\n\t\t\t\t\t!isPlaceable(category) ||\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\tangle.fraction === 0\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst shape = {\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tinnerRadius: inner,\n\t\t\t\t\touterRadius: radius,\n\t\t\t\t\tstartAngle: angle.startAngle,\n\t\t\t\t\tendAngle: angle.endAngle,\n\t\t\t\t};\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: arcPath(shape),\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\tstroke: options.stroke ?? context.theme.background,\n\t\t\t\t\t\tstrokeWidth: options.stroke ? 1 : 0,\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tif (options.tip === false) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst middle = (angle.startAngle + angle.endAngle) / 2;\n\t\t\t\tconst anchor = polarToCartesian(cx, cy, (inner + radius) / 2, middle);\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex,\n\t\t\t\t\tdatum: data[index],\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\txValue: category,\n\t\t\t\t\tyValue: value,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tseriesLabel: options.label,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: series.label ?? context.formatX(category),\n\t\t\t\t\tvalue: `${context.formatY(value)} (${formatPercentage(angle.fraction, context.locale)})`,\n\t\t\t\t\thit: { kind: \"arc\", ...shape },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n\n/** A ring of slices: `arc` with the middle left empty. */\nexport function donut<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ArcOptions<TDatum>,\n): ChartMark {\n\treturn arc(data, { innerRadius: 0.6, ...options });\n}\n\nexport interface RadialBarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly category: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** The value a full turn stands for. Defaults to the largest value, rounded up. */\n\treadonly max?: number;\n\t/** Share of the radius left empty in the middle. */\n\treadonly innerRadius?: number;\n\t/** Share of each ring's thickness left empty between two rings. */\n\treadonly gap?: number;\n\t/** Draw each ring's empty remainder, so the bars read against a full turn. */\n\treadonly track?: boolean;\n\treadonly fill?: string;\n}\n\n/** Concentric rings, each filled as far round as its value: progress against a common maximum. */\nexport function radialBar<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RadialBarOptions<TDatum>,\n): ChartMark {\n\tconst categories = readChannel(data, options.category);\n\tconst values = readChannel(data, options.value).map(numericValue);\n\tconst colorAccessor = options.color ?? options.category;\n\tconst colors = readChannel(data, colorAccessor);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"frame\",\n\t\ttitles: {\n\t\t\tcategory: channelLabel(options.category),\n\t\t\tvalue: channelLabel(options.value) ?? options.label,\n\t\t},\n\t\tchannels: {\n\t\t\tcolor: {\n\t\t\t\tvalues: colors.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(colorAccessor),\n\t\t\t},\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"radialBar\", context);\n\t\t\tconst { cx, cy, radius } = frameOf(context.plot);\n\t\t\tconst peak = Math.max(0, ...values.map((value) => value ?? 0));\n\t\t\tconst max = options.max ?? niceDomain(0, peak)[1];\n\t\t\tconst inner = radius * (options.innerRadius ?? 0.3);\n\t\t\tconst count = Math.max(1, data.length);\n\t\t\tconst ring = (radius - inner) / count;\n\t\t\tconst thickness = ring * (1 - (options.gap ?? 0.25));\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors,\n\t\t\t\t{ ...options, color: colorAccessor, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, category] of categories.entries()) {\n\t\t\t\tconst value = values[index];\n\t\t\t\tif (!isPlaceable(category) || value === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst outerRadius = radius - index * ring;\n\t\t\t\tconst shape = {\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tinnerRadius: outerRadius - thickness,\n\t\t\t\t\touterRadius,\n\t\t\t\t\tstartAngle: 0,\n\t\t\t\t\tendAngle: max <= 0 ? 0 : (Math.min(value, max) / max) * FULL_TURN,\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tif (options.track !== false) {\n\t\t\t\t\tnodes.push({\n\t\t\t\t\t\tkind: \"path\",\n\t\t\t\t\t\tkey: `${id}:track:${categoryKey(category)}`,\n\t\t\t\t\t\trole: \"track\",\n\t\t\t\t\t\td: arcPath({ ...shape, endAngle: FULL_TURN }),\n\t\t\t\t\t\tpaint: { fill: context.theme.grid, opacity: 0.5 },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: arcPath(shape),\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (options.tip === false) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst anchor = polarToCartesian(\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\touterRadius - thickness / 2,\n\t\t\t\t\tMath.max(shape.endAngle, 1),\n\t\t\t\t);\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex,\n\t\t\t\t\tdatum: data[index],\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\txValue: category,\n\t\t\t\t\tyValue: value,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: series.label ?? context.formatX(category),\n\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\thit: { kind: \"arc\", ...shape, endAngle: FULL_TURN },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n\nexport interface RadarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** The spoke a value sits on: \"Vitesse\", \"Endurance\"\u2026 */\n\treadonly axis: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** The value the outer ring stands for. Defaults to the largest value, rounded up. */\n\treadonly max?: number;\n\t/** Grid rings between the centre and the outer ring. */\n\treadonly rings?: number;\n\treadonly fillOpacity?: number;\n\treadonly fill?: string;\n\t/** `false` leaves the grid and spoke labels to another radar on the same chart. */\n\treadonly grid?: boolean;\n}\n\nconst LABEL_GAP = 8;\n\nfunction anchorFor(angle: number): {\n\treadonly textAnchor: \"start\" | \"middle\" | \"end\";\n\treadonly baseline: \"top\" | \"middle\" | \"bottom\";\n} {\n\tconst normalized = ((angle % FULL_TURN) + FULL_TURN) % FULL_TURN;\n\tconst side = Math.sin((normalized * Math.PI) / 180);\n\tconst vertical = -Math.cos((normalized * Math.PI) / 180);\n\treturn {\n\t\ttextAnchor: Math.abs(side) < 0.2 ? \"middle\" : side > 0 ? \"start\" : \"end\",\n\t\tbaseline:\n\t\t\tMath.abs(vertical) < 0.2 ? \"middle\" : vertical > 0 ? \"top\" : \"bottom\",\n\t};\n}\n\nfunction radarGrid(\n\tid: string,\n\tcontext: ChartMarkContext,\n\tframe: Frame,\n\taxes: ReadonlyArray<ChartValue>,\n\trings: number,\n): SceneNode[] {\n\tconst { cx, cy, radius } = frame;\n\tconst { theme } = context;\n\tconst nodes: SceneNode[] = [];\n\tfor (let level = 1; level <= rings; level += 1) {\n\t\tconst ringRadius = (radius * level) / rings;\n\t\tnodes.push({\n\t\t\tkind: \"path\",\n\t\t\tkey: `${id}:ring:${level}`,\n\t\t\trole: \"grid\",\n\t\t\td: polygonPath(\n\t\t\t\taxes.map((_axis, index) =>\n\t\t\t\t\tpolarToCartesian(\n\t\t\t\t\t\tcx,\n\t\t\t\t\t\tcy,\n\t\t\t\t\t\tringRadius,\n\t\t\t\t\t\t(FULL_TURN * index) / axes.length,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t\tpaint: { stroke: theme.grid, strokeWidth: 1, fill: \"none\" },\n\t\t});\n\t}\n\tfor (const [index, axis] of axes.entries()) {\n\t\tconst angle = (FULL_TURN * index) / axes.length;\n\t\tconst end = polarToCartesian(cx, cy, radius, angle);\n\t\tconst label = polarToCartesian(cx, cy, radius + LABEL_GAP, angle);\n\t\tnodes.push(\n\t\t\t{\n\t\t\t\tkind: \"line\",\n\t\t\t\tkey: `${id}:spoke:${categoryKey(axis)}`,\n\t\t\t\trole: \"grid\",\n\t\t\t\tx1: cx,\n\t\t\t\ty1: cy,\n\t\t\t\tx2: end.x,\n\t\t\t\ty2: end.y,\n\t\t\t\tpaint: { stroke: theme.grid, strokeWidth: 1 },\n\t\t\t},\n\t\t\t{\n\t\t\t\tkind: \"text\",\n\t\t\t\tkey: `${id}:axis:${categoryKey(axis)}`,\n\t\t\t\trole: \"axis\",\n\t\t\t\tx: label.x,\n\t\t\t\ty: label.y,\n\t\t\t\ttext: context.formatX(axis),\n\t\t\t\tpaint: {\n\t\t\t\t\tfill: theme.muted,\n\t\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\t\t...anchorFor(angle),\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\treturn nodes;\n}\n\n/** Values on spokes joined into a polygon, one per series: profiles compared at a glance. */\nexport function radar<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RadarOptions<TDatum>,\n): ChartMark {\n\tconst axisValues = readChannel(data, options.axis);\n\tconst values = readChannel(data, options.value).map(numericValue);\n\tconst colors = readChannel(data, options.color);\n\tconst axes = [\n\t\t...new Map(\n\t\t\taxisValues.filter(isPlaceable).map((axis) => [categoryKey(axis), axis]),\n\t\t).values(),\n\t];\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"frame\",\n\t\ttitles: {\n\t\t\tcategory: channelLabel(options.axis),\n\t\t\tvalue: channelLabel(options.value) ?? options.label,\n\t\t},\n\t\tchannels:\n\t\t\toptions.color === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tcolor: {\n\t\t\t\t\t\t\tvalues: colors.filter(isPlaceable),\n\t\t\t\t\t\t\tlabel: channelLabel(options.color),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"radar\", context);\n\t\t\tconst widest = Math.max(\n\t\t\t\t0,\n\t\t\t\t...axes.map((axis) =>\n\t\t\t\t\tcontext.measureText(context.formatX(axis), context.theme.fontSize),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst frame = frameOf(\n\t\t\t\tcontext.plot,\n\t\t\t\twidest + LABEL_GAP,\n\t\t\t\tcontext.theme.fontSize + LABEL_GAP,\n\t\t\t);\n\t\t\tconst peak = Math.max(0, ...values.map((value) => value ?? 0));\n\t\t\tconst max = options.max ?? niceDomain(0, peak)[1];\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst nodes: SceneNode[] =\n\t\t\t\toptions.grid === false\n\t\t\t\t\t? []\n\t\t\t\t\t: radarGrid(id, context, frame, axes, options.rings ?? 4);\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tconst polygons = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ color: string; vertices: Array<ChartXY | undefined> }\n\t\t\t>();\n\t\t\tfor (const [index, axis] of axisValues.entries()) {\n\t\t\t\tconst value = values[index];\n\t\t\t\tconst spoke = isPlaceable(axis)\n\t\t\t\t\t? axes.findIndex(\n\t\t\t\t\t\t\t(candidate) => categoryKey(candidate) === categoryKey(axis),\n\t\t\t\t\t\t)\n\t\t\t\t\t: -1;\n\t\t\t\tif (spoke === -1 || value === undefined || !isPlaceable(axis)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst angle = (FULL_TURN * spoke) / axes.length;\n\t\t\t\tconst vertex = polarToCartesian(\n\t\t\t\t\tframe.cx,\n\t\t\t\t\tframe.cy,\n\t\t\t\t\tmax <= 0 ? 0 : (Math.min(value, max) / max) * frame.radius,\n\t\t\t\t\tangle,\n\t\t\t\t);\n\t\t\t\tconst polygon = polygons.get(series.key) ?? {\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\tvertices: axes.map(() => undefined),\n\t\t\t\t};\n\t\t\t\tpolygon.vertices[spoke] = vertex;\n\t\t\t\tpolygons.set(series.key, polygon);\n\t\t\t\tif (options.tip !== false) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\tx: vertex.x,\n\t\t\t\t\t\ty: vertex.y,\n\t\t\t\t\t\txValue: axis,\n\t\t\t\t\t\tyValue: value,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: context.formatX(axis),\n\t\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const [key, polygon] of polygons) {\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:shape:${key}`,\n\t\t\t\t\tseries: key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: polygonPath(\n\t\t\t\t\t\tpolygon.vertices.map(\n\t\t\t\t\t\t\t(vertex) => vertex ?? { x: frame.cx, y: frame.cy },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: polygon.color,\n\t\t\t\t\t\tfillOpacity: options.fillOpacity ?? 0.2,\n\t\t\t\t\t\tstroke: polygon.color,\n\t\t\t\t\t\tstrokeWidth: 2,\n\t\t\t\t\t\tstrokeLinejoin: \"round\",\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst legend =\n\t\t\t\toptions.color === undefined && options.label !== undefined\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: id,\n\t\t\t\t\t\t\t\tlabel: options.label,\n\t\t\t\t\t\t\t\tcolor: options.fill ?? context.paletteColor(context.markIndex),\n\t\t\t\t\t\t\t\tshape: \"square\" as const,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: [];\n\t\t\treturn { nodes, points, legend };\n\t\t},\n\t};\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { formatPercentage } from \"#/core/format.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\ttips,\n} from \"#/core/marks/shared.ts\";\nimport {\n\tarcPath,\n\ttype ChartXY,\n\tpolarToCartesian,\n\tpolygonPath,\n} from \"#/core/paths.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport { niceDomain } from \"#/core/ticks.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartMarkContext,\n\tChartPoint,\n\tChartRect,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\n/**\n * Round marks. They own the whole plot rather than sitting on x and y\n * scales; their slices are coloured by category, which is what the legend\n * lists. Angles are degrees clockwise from twelve o'clock.\n */\n\nconst FULL_TURN = 360;\nconst EDGE = 4;\n\ninterface Frame {\n\treadonly cx: number;\n\treadonly cy: number;\n\treadonly radius: number;\n}\n\n/**\n * The circle a round mark is drawn in: centred, as large as the plot allows\n * once `insetX` (left and right) and `insetY` (top and bottom) are kept clear\n * for labels drawn outside it.\n */\nfunction frameOf(plot: ChartRect, insetX = 0, insetY = insetX): Frame {\n\treturn {\n\t\tcx: plot.x + plot.width / 2,\n\t\tcy: plot.y + plot.height / 2,\n\t\tradius: Math.max(\n\t\t\t0,\n\t\t\tMath.min(plot.width / 2 - insetX, plot.height / 2 - insetY) - EDGE,\n\t\t),\n\t};\n}\n\ninterface SliceAngle {\n\treadonly startAngle: number;\n\treadonly endAngle: number;\n\treadonly fraction: number;\n}\n\n/**\n * Splits a turn between values, proportionally. Negative values count as\n * zero: a pie of signed numbers has no honest reading.\n */\nexport function sliceAngles(\n\tvalues: ReadonlyArray<number>,\n\tpadAngle = 0,\n\tstartAngle = 0,\n\tendAngle = FULL_TURN,\n): ReadonlyArray<SliceAngle> {\n\tconst positives = values.map((value) =>\n\t\tNumber.isFinite(value) && value > 0 ? value : 0,\n\t);\n\tconst total = positives.reduce((sum, value) => sum + value, 0);\n\tconst pads = positives.filter((value) => value > 0).length > 1 ? padAngle : 0;\n\tconst available = Math.max(\n\t\t0,\n\t\tendAngle - startAngle - pads * positives.length,\n\t);\n\tlet cursor = startAngle;\n\treturn positives.map((value) => {\n\t\tconst fraction = total === 0 ? 0 : value / total;\n\t\tconst sweep = available * fraction;\n\t\tconst slice = {\n\t\t\tstartAngle: cursor + pads / 2,\n\t\t\tendAngle: cursor + pads / 2 + sweep,\n\t\t\tfraction,\n\t\t};\n\t\tcursor += sweep + pads;\n\t\treturn slice;\n\t});\n}\n\nexport interface ArcOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** The slice's name: what the legend, tooltip and table call it. */\n\treadonly category: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** Share of the radius left empty in the middle: 0 is a pie, 0.6 a donut. */\n\treadonly innerRadius?: number;\n\t/** Degrees of blank between two slices. */\n\treadonly padAngle?: number;\n\treadonly startAngle?: number;\n\treadonly endAngle?: number;\n\treadonly fill?: string;\n\treadonly stroke?: string;\n}\n\nconst DEFAULT_PAD_ANGLE = 1;\n\n/** A pie, or a donut with `innerRadius`: each datum a slice of the whole. */\nexport function arc<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ArcOptions<TDatum>,\n): ChartMark {\n\tconst categories = readChannel(data, options.category);\n\tconst values = readChannel(data, options.value).map(numericValue);\n\tconst colorAccessor = options.color ?? options.category;\n\tconst colors = readChannel(data, colorAccessor);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"frame\",\n\t\ttitles: {\n\t\t\tcategory: channelLabel(options.category),\n\t\t\tvalue: channelLabel(options.value) ?? options.label,\n\t\t},\n\t\tchannels: {\n\t\t\tcolor: {\n\t\t\t\tvalues: colors.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(colorAccessor),\n\t\t\t},\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"arc\", context);\n\t\t\tconst { cx, cy, radius } = frameOf(context.plot);\n\t\t\tconst inner = radius * (options.innerRadius ?? 0);\n\t\t\tconst angles = sliceAngles(\n\t\t\t\tvalues.map((value) => value ?? 0),\n\t\t\t\toptions.padAngle ?? DEFAULT_PAD_ANGLE,\n\t\t\t\toptions.startAngle,\n\t\t\t\toptions.endAngle,\n\t\t\t);\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors,\n\t\t\t\t{ ...options, color: colorAccessor, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, angle] of angles.entries()) {\n\t\t\t\tconst category = categories[index];\n\t\t\t\tconst value = values[index];\n\t\t\t\tif (\n\t\t\t\t\t!isPlaceable(category) ||\n\t\t\t\t\tvalue === undefined ||\n\t\t\t\t\tangle.fraction === 0\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst shape = {\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tinnerRadius: inner,\n\t\t\t\t\touterRadius: radius,\n\t\t\t\t\tstartAngle: angle.startAngle,\n\t\t\t\t\tendAngle: angle.endAngle,\n\t\t\t\t};\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: arcPath(shape),\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\tstroke: options.stroke ?? context.theme.background,\n\t\t\t\t\t\tstrokeWidth: options.stroke ? 1 : 0,\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tif (!tips(options.tip, data[index], index)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst middle = (angle.startAngle + angle.endAngle) / 2;\n\t\t\t\tconst anchor = polarToCartesian(cx, cy, (inner + radius) / 2, middle);\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex,\n\t\t\t\t\tdatum: data[index],\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\txValue: category,\n\t\t\t\t\tyValue: value,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tseriesLabel: options.label,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: series.label ?? context.formatX(category),\n\t\t\t\t\tvalue: `${context.formatY(value)} (${formatPercentage(angle.fraction, context.locale)})`,\n\t\t\t\t\thit: { kind: \"arc\", ...shape },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n\n/** A ring of slices: `arc` with the middle left empty. */\nexport function donut<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ArcOptions<TDatum>,\n): ChartMark {\n\treturn arc(data, { innerRadius: 0.6, ...options });\n}\n\nexport interface RadialBarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly category: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** The value a full turn stands for. Defaults to the largest value, rounded up. */\n\treadonly max?: number;\n\t/** Share of the radius left empty in the middle. */\n\treadonly innerRadius?: number;\n\t/** Share of each ring's thickness left empty between two rings. */\n\treadonly gap?: number;\n\t/** Draw each ring's empty remainder, so the bars read against a full turn. */\n\treadonly track?: boolean;\n\treadonly fill?: string;\n}\n\n/** Concentric rings, each filled as far round as its value: progress against a common maximum. */\nexport function radialBar<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RadialBarOptions<TDatum>,\n): ChartMark {\n\tconst categories = readChannel(data, options.category);\n\tconst values = readChannel(data, options.value).map(numericValue);\n\tconst colorAccessor = options.color ?? options.category;\n\tconst colors = readChannel(data, colorAccessor);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"frame\",\n\t\ttitles: {\n\t\t\tcategory: channelLabel(options.category),\n\t\t\tvalue: channelLabel(options.value) ?? options.label,\n\t\t},\n\t\tchannels: {\n\t\t\tcolor: {\n\t\t\t\tvalues: colors.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(colorAccessor),\n\t\t\t},\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"radialBar\", context);\n\t\t\tconst { cx, cy, radius } = frameOf(context.plot);\n\t\t\tconst peak = Math.max(0, ...values.map((value) => value ?? 0));\n\t\t\tconst max = options.max ?? niceDomain(0, peak)[1];\n\t\t\tconst inner = radius * (options.innerRadius ?? 0.3);\n\t\t\tconst count = Math.max(1, data.length);\n\t\t\tconst ring = (radius - inner) / count;\n\t\t\tconst thickness = ring * (1 - (options.gap ?? 0.25));\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors,\n\t\t\t\t{ ...options, color: colorAccessor, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, category] of categories.entries()) {\n\t\t\t\tconst value = values[index];\n\t\t\t\tif (!isPlaceable(category) || value === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst outerRadius = radius - index * ring;\n\t\t\t\tconst shape = {\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tinnerRadius: outerRadius - thickness,\n\t\t\t\t\touterRadius,\n\t\t\t\t\tstartAngle: 0,\n\t\t\t\t\tendAngle: max <= 0 ? 0 : (Math.min(value, max) / max) * FULL_TURN,\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tif (options.track !== false) {\n\t\t\t\t\tnodes.push({\n\t\t\t\t\t\tkind: \"path\",\n\t\t\t\t\t\tkey: `${id}:track:${categoryKey(category)}`,\n\t\t\t\t\t\trole: \"track\",\n\t\t\t\t\t\td: arcPath({ ...shape, endAngle: FULL_TURN }),\n\t\t\t\t\t\tpaint: { fill: context.theme.grid, opacity: 0.5 },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: arcPath(shape),\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (!tips(options.tip, data[index], index)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst anchor = polarToCartesian(\n\t\t\t\t\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\touterRadius - thickness / 2,\n\t\t\t\t\tMath.max(shape.endAngle, 1),\n\t\t\t\t);\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${categoryKey(category)}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex,\n\t\t\t\t\tdatum: data[index],\n\t\t\t\t\tx: anchor.x,\n\t\t\t\t\ty: anchor.y,\n\t\t\t\t\txValue: category,\n\t\t\t\t\tyValue: value,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: series.label ?? context.formatX(category),\n\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\thit: { kind: \"arc\", ...shape, endAngle: FULL_TURN },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n\nexport interface RadarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** The spoke a value sits on: \"Vitesse\", \"Endurance\"\u2026 */\n\treadonly axis: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** The value the outer ring stands for. Defaults to the largest value, rounded up. */\n\treadonly max?: number;\n\t/** Grid rings between the centre and the outer ring. */\n\treadonly rings?: number;\n\treadonly fillOpacity?: number;\n\treadonly fill?: string;\n\t/** `false` leaves the grid and spoke labels to another radar on the same chart. */\n\treadonly grid?: boolean;\n}\n\nconst LABEL_GAP = 8;\n\nfunction anchorFor(angle: number): {\n\treadonly textAnchor: \"start\" | \"middle\" | \"end\";\n\treadonly baseline: \"top\" | \"middle\" | \"bottom\";\n} {\n\tconst normalized = ((angle % FULL_TURN) + FULL_TURN) % FULL_TURN;\n\tconst side = Math.sin((normalized * Math.PI) / 180);\n\tconst vertical = -Math.cos((normalized * Math.PI) / 180);\n\treturn {\n\t\ttextAnchor: Math.abs(side) < 0.2 ? \"middle\" : side > 0 ? \"start\" : \"end\",\n\t\tbaseline:\n\t\t\tMath.abs(vertical) < 0.2 ? \"middle\" : vertical > 0 ? \"top\" : \"bottom\",\n\t};\n}\n\nfunction radarGrid(\n\tid: string,\n\tcontext: ChartMarkContext,\n\tframe: Frame,\n\taxes: ReadonlyArray<ChartValue>,\n\trings: number,\n): SceneNode[] {\n\tconst { cx, cy, radius } = frame;\n\tconst { theme } = context;\n\tconst nodes: SceneNode[] = [];\n\tfor (let level = 1; level <= rings; level += 1) {\n\t\tconst ringRadius = (radius * level) / rings;\n\t\tnodes.push({\n\t\t\tkind: \"path\",\n\t\t\tkey: `${id}:ring:${level}`,\n\t\t\trole: \"grid\",\n\t\t\td: polygonPath(\n\t\t\t\taxes.map((_axis, index) =>\n\t\t\t\t\tpolarToCartesian(\n\t\t\t\t\t\tcx,\n\t\t\t\t\t\tcy,\n\t\t\t\t\t\tringRadius,\n\t\t\t\t\t\t(FULL_TURN * index) / axes.length,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t\tpaint: { stroke: theme.grid, strokeWidth: 1, fill: \"none\" },\n\t\t});\n\t}\n\tfor (const [index, axis] of axes.entries()) {\n\t\tconst angle = (FULL_TURN * index) / axes.length;\n\t\tconst end = polarToCartesian(cx, cy, radius, angle);\n\t\tconst label = polarToCartesian(cx, cy, radius + LABEL_GAP, angle);\n\t\tnodes.push(\n\t\t\t{\n\t\t\t\tkind: \"line\",\n\t\t\t\tkey: `${id}:spoke:${categoryKey(axis)}`,\n\t\t\t\trole: \"grid\",\n\t\t\t\tx1: cx,\n\t\t\t\ty1: cy,\n\t\t\t\tx2: end.x,\n\t\t\t\ty2: end.y,\n\t\t\t\tpaint: { stroke: theme.grid, strokeWidth: 1 },\n\t\t\t},\n\t\t\t{\n\t\t\t\tkind: \"text\",\n\t\t\t\tkey: `${id}:axis:${categoryKey(axis)}`,\n\t\t\t\trole: \"axis\",\n\t\t\t\tx: label.x,\n\t\t\t\ty: label.y,\n\t\t\t\ttext: context.formatX(axis),\n\t\t\t\tpaint: {\n\t\t\t\t\tfill: theme.muted,\n\t\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\t\t...anchorFor(angle),\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t}\n\treturn nodes;\n}\n\n/** Values on spokes joined into a polygon, one per series: profiles compared at a glance. */\nexport function radar<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RadarOptions<TDatum>,\n): ChartMark {\n\tconst axisValues = readChannel(data, options.axis);\n\tconst values = readChannel(data, options.value).map(numericValue);\n\tconst colors = readChannel(data, options.color);\n\tconst axes = [\n\t\t...new Map(\n\t\t\taxisValues.filter(isPlaceable).map((axis) => [categoryKey(axis), axis]),\n\t\t).values(),\n\t];\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"frame\",\n\t\ttitles: {\n\t\t\tcategory: channelLabel(options.axis),\n\t\t\tvalue: channelLabel(options.value) ?? options.label,\n\t\t},\n\t\tchannels:\n\t\t\toptions.color === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tcolor: {\n\t\t\t\t\t\t\tvalues: colors.filter(isPlaceable),\n\t\t\t\t\t\t\tlabel: channelLabel(options.color),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"radar\", context);\n\t\t\tconst widest = Math.max(\n\t\t\t\t0,\n\t\t\t\t...axes.map((axis) =>\n\t\t\t\t\tcontext.measureText(context.formatX(axis), context.theme.fontSize),\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst frame = frameOf(\n\t\t\t\tcontext.plot,\n\t\t\t\twidest + LABEL_GAP,\n\t\t\t\tcontext.theme.fontSize + LABEL_GAP,\n\t\t\t);\n\t\t\tconst peak = Math.max(0, ...values.map((value) => value ?? 0));\n\t\t\tconst max = options.max ?? niceDomain(0, peak)[1];\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst nodes: SceneNode[] =\n\t\t\t\toptions.grid === false\n\t\t\t\t\t? []\n\t\t\t\t\t: radarGrid(id, context, frame, axes, options.rings ?? 4);\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tconst polygons = new Map<\n\t\t\t\tstring,\n\t\t\t\t{ color: string; vertices: Array<ChartXY | undefined> }\n\t\t\t>();\n\t\t\tfor (const [index, axis] of axisValues.entries()) {\n\t\t\t\tconst value = values[index];\n\t\t\t\tconst spoke = isPlaceable(axis)\n\t\t\t\t\t? axes.findIndex(\n\t\t\t\t\t\t\t(candidate) => categoryKey(candidate) === categoryKey(axis),\n\t\t\t\t\t\t)\n\t\t\t\t\t: -1;\n\t\t\t\tif (spoke === -1 || value === undefined || !isPlaceable(axis)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst angle = (FULL_TURN * spoke) / axes.length;\n\t\t\t\tconst vertex = polarToCartesian(\n\t\t\t\t\tframe.cx,\n\t\t\t\t\tframe.cy,\n\t\t\t\t\tmax <= 0 ? 0 : (Math.min(value, max) / max) * frame.radius,\n\t\t\t\t\tangle,\n\t\t\t\t);\n\t\t\t\tconst polygon = polygons.get(series.key) ?? {\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\tvertices: axes.map(() => undefined),\n\t\t\t\t};\n\t\t\t\tpolygon.vertices[spoke] = vertex;\n\t\t\t\tpolygons.set(series.key, polygon);\n\t\t\t\tif (tips(options.tip, data[index], index)) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\tx: vertex.x,\n\t\t\t\t\t\ty: vertex.y,\n\t\t\t\t\t\txValue: axis,\n\t\t\t\t\t\tyValue: value,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: context.formatX(axis),\n\t\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const [key, polygon] of polygons) {\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:shape:${key}`,\n\t\t\t\t\tseries: key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: polygonPath(\n\t\t\t\t\t\tpolygon.vertices.map(\n\t\t\t\t\t\t\t(vertex) => vertex ?? { x: frame.cx, y: frame.cy },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: polygon.color,\n\t\t\t\t\t\tfillOpacity: options.fillOpacity ?? 0.2,\n\t\t\t\t\t\tstroke: polygon.color,\n\t\t\t\t\t\tstrokeWidth: 2,\n\t\t\t\t\t\tstrokeLinejoin: \"round\",\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst legend =\n\t\t\t\toptions.color === undefined && options.label !== undefined\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tkey: id,\n\t\t\t\t\t\t\t\tlabel: options.label,\n\t\t\t\t\t\t\t\tcolor: options.fill ?? context.paletteColor(context.markIndex),\n\t\t\t\t\t\t\t\tshape: \"square\" as const,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t]\n\t\t\t\t\t: [];\n\t\t\treturn { nodes, points, legend };\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/core/marks/rect.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,8CAA8C;IAC9C,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,SAAS,CA6GX"}
1
+ {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/core/marks/rect.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,8CAA8C;IAC9C,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,SAAS,CA6GX"}
@@ -9,6 +9,7 @@ import {
9
9
  markId,
10
10
  paint,
11
11
  seriesResolver,
12
+ tips,
12
13
  valueOn
13
14
  } from "./shared.js";
14
15
  import { stackSegments } from "./stack.js";
@@ -90,7 +91,7 @@ function rectY(data, options) {
90
91
  opacity: options.opacity
91
92
  })
92
93
  });
93
- if (options.tip !== false) {
94
+ if (tips(options.tip, data[index], index)) {
94
95
  points.push({
95
96
  key: `${id}:${index}`,
96
97
  markId: id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/rect.ts"],
4
- "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface RectOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** Start and end of the rectangle along a continuous x: a bin, a period. */\n\treadonly x1: ChartAccessor<TDatum, ChartValue>;\n\treadonly x2: ChartAccessor<TDatum, ChartValue>;\n\t/** Its height. Stacks by colour like bars. */\n\treadonly y: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\t/** Pixels kept clear on each side, so neighbours read as separate. */\n\treadonly inset?: number;\n\treadonly stack?: boolean;\n\treadonly radius?: number;\n}\n\n/**\n * A rectangle between two x values, as tall as its value: the bars of a\n * histogram, periods on a timeline. Unlike `barY` the x axis stays\n * continuous, so the bins keep their true widths.\n */\nexport function rectY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RectOptions<TDatum>,\n): ChartMark {\n\tconst starts = readChannel(data, options.x1);\n\tconst ends = readChannel(data, options.x2);\n\tconst values = readChannel(data, options.y).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst stacked = options.stack ?? options.color !== undefined;\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tstarts.map((start) =>\n\t\t\t\t\tisPlaceable(start) ? categoryKey(start) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\tconst edges = values.map((value, index) =>\n\t\tvalue === undefined\n\t\t\t? undefined\n\t\t\t: (segments[index] ?? { low: 0, high: value, outer: true }),\n\t);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"x\",\n\t\tchannels: {\n\t\t\tx: {\n\t\t\t\tvalues: [...starts, ...ends].filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.x1),\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: edges.flatMap((edge) => (edge ? [edge.low, edge.high] : [])),\n\t\t\t\tincludeZero: true,\n\t\t\t\tlabel: channelLabel(options.y) ?? options.label,\n\t\t\t},\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"rectY\", context);\n\t\t\tconst { x: xScale, y: yScale } = context.scales;\n\t\t\tif (xScale === undefined || yScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst inset = options.inset ?? 0.5;\n\t\t\tconst radius = options.radius ?? 0;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, edge] of edges.entries()) {\n\t\t\t\tconst start = valueOn(xScale, starts[index]);\n\t\t\t\tconst end = valueOn(xScale, ends[index]);\n\t\t\t\tconst value = values[index];\n\t\t\t\tif (\n\t\t\t\t\tedge === undefined ||\n\t\t\t\t\tstart === undefined ||\n\t\t\t\t\tend === undefined ||\n\t\t\t\t\tvalue === undefined\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst left = Math.min(xScale.map(start), xScale.map(end)) + inset;\n\t\t\t\tconst right = Math.max(xScale.map(start), xScale.map(end)) - inset;\n\t\t\t\tconst top = Math.min(yScale.map(edge.low), yScale.map(edge.high));\n\t\t\t\tconst rect = {\n\t\t\t\t\tx: left,\n\t\t\t\t\ty: top,\n\t\t\t\t\twidth: Math.max(0, right - left),\n\t\t\t\t\theight: Math.abs(yScale.map(edge.high) - yScale.map(edge.low)),\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t...rect,\n\t\t\t\t\tcorners:\n\t\t\t\t\t\tradius > 0 && edge.outer ? [radius, radius, 0, 0] : undefined,\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\tfillOpacity: options.fillOpacity,\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tif (options.tip !== false) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\tx: rect.x + rect.width / 2,\n\t\t\t\t\t\ty: top,\n\t\t\t\t\t\txValue: start,\n\t\t\t\t\t\tyValue: value,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: `${context.formatX(start)} \u2013 ${context.formatX(end)}`,\n\t\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\t\thit: { kind: \"rect\", rect },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\ttips,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface RectOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** Start and end of the rectangle along a continuous x: a bin, a period. */\n\treadonly x1: ChartAccessor<TDatum, ChartValue>;\n\treadonly x2: ChartAccessor<TDatum, ChartValue>;\n\t/** Its height. Stacks by colour like bars. */\n\treadonly y: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\t/** Pixels kept clear on each side, so neighbours read as separate. */\n\treadonly inset?: number;\n\treadonly stack?: boolean;\n\treadonly radius?: number;\n}\n\n/**\n * A rectangle between two x values, as tall as its value: the bars of a\n * histogram, periods on a timeline. Unlike `barY` the x axis stays\n * continuous, so the bins keep their true widths.\n */\nexport function rectY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: RectOptions<TDatum>,\n): ChartMark {\n\tconst starts = readChannel(data, options.x1);\n\tconst ends = readChannel(data, options.x2);\n\tconst values = readChannel(data, options.y).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst stacked = options.stack ?? options.color !== undefined;\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tstarts.map((start) =>\n\t\t\t\t\tisPlaceable(start) ? categoryKey(start) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\tconst edges = values.map((value, index) =>\n\t\tvalue === undefined\n\t\t\t? undefined\n\t\t\t: (segments[index] ?? { low: 0, high: value, outer: true }),\n\t);\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"x\",\n\t\tchannels: {\n\t\t\tx: {\n\t\t\t\tvalues: [...starts, ...ends].filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.x1),\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: edges.flatMap((edge) => (edge ? [edge.low, edge.high] : [])),\n\t\t\t\tincludeZero: true,\n\t\t\t\tlabel: channelLabel(options.y) ?? options.label,\n\t\t\t},\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"rectY\", context);\n\t\t\tconst { x: xScale, y: yScale } = context.scales;\n\t\t\tif (xScale === undefined || yScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst inset = options.inset ?? 0.5;\n\t\t\tconst radius = options.radius ?? 0;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, edge] of edges.entries()) {\n\t\t\t\tconst start = valueOn(xScale, starts[index]);\n\t\t\t\tconst end = valueOn(xScale, ends[index]);\n\t\t\t\tconst value = values[index];\n\t\t\t\tif (\n\t\t\t\t\tedge === undefined ||\n\t\t\t\t\tstart === undefined ||\n\t\t\t\t\tend === undefined ||\n\t\t\t\t\tvalue === undefined\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst left = Math.min(xScale.map(start), xScale.map(end)) + inset;\n\t\t\t\tconst right = Math.max(xScale.map(start), xScale.map(end)) - inset;\n\t\t\t\tconst top = Math.min(yScale.map(edge.low), yScale.map(edge.high));\n\t\t\t\tconst rect = {\n\t\t\t\t\tx: left,\n\t\t\t\t\ty: top,\n\t\t\t\t\twidth: Math.max(0, right - left),\n\t\t\t\t\theight: Math.abs(yScale.map(edge.high) - yScale.map(edge.low)),\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t...rect,\n\t\t\t\t\tcorners:\n\t\t\t\t\t\tradius > 0 && edge.outer ? [radius, radius, 0, 0] : undefined,\n\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\tfillOpacity: options.fillOpacity,\n\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tif (tips(options.tip, data[index], index)) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum: data[index],\n\t\t\t\t\t\tx: rect.x + rect.width / 2,\n\t\t\t\t\t\ty: top,\n\t\t\t\t\t\txValue: start,\n\t\t\t\t\t\tyValue: value,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: `${context.formatX(start)} \u2013 ${context.formatX(end)}`,\n\t\t\t\t\t\tvalue: context.formatY(value),\n\t\t\t\t\t\thit: { kind: \"rect\", rect },\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -7,8 +7,12 @@ export interface ChartMarkOptions<TDatum> {
7
7
  readonly label?: string;
8
8
  /** A field or function whose distinct values split the mark into coloured series. */
9
9
  readonly color?: ChartAccessor<TDatum, ChartValue>;
10
- /** `false` keeps the mark out of focus, tooltips and the data table. */
11
- readonly tip?: boolean;
10
+ /**
11
+ * `false` keeps the mark out of focus, tooltips and the data table; a
12
+ * function decides per datum (the point where a recorded line hands over
13
+ * to its dashed projection belongs to one of the two, not both).
14
+ */
15
+ readonly tip?: boolean | ((datum: TDatum, index: number) => boolean);
12
16
  readonly opacity?: number;
13
17
  }
14
18
  export declare function markId(id: string | undefined, kind: string, context: ChartMarkContext): string;
@@ -38,4 +42,6 @@ export declare function groupBySeries(count: number, seriesOf: (index: number) =
38
42
  * category as is.
39
43
  */
40
44
  export declare function valueOn(scale: ChartPositionScale, raw: unknown): ChartValue | undefined;
45
+ /** Whether a datum takes part in focus, tooltips and the data table. */
46
+ export declare function tips<TDatum>(tip: ChartMarkOptions<TDatum>["tip"], datum: TDatum, index: number): boolean;
41
47
  //# sourceMappingURL=shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/core/marks/shared.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,MAAM,iBAAiB,CAAC;AAEzB,gCAAgC;AAChC,MAAM,WAAW,gBAAgB,CAAC,MAAM;IACvC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnD,wEAAwE;IACxE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,MAAM,CACrB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,GACvB,MAAM,CAER;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,cAAc,CAAC,MAAM,EACpC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,CAAC,EAC7C,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EACpE,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,gBAAgB,GACvB,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,CAkB/B;AAED,wBAAgB,YAAY,CAAC,MAAM,EAClC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B;IACF,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAAC;CAC3C,CAYA;AAED,uFAAuF;AACvF,wBAAgB,KAAK,CAAC,MAAM,SAAS,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,GACrC,WAAW,CACb,MAAM,EACN;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAC3D,CAYA;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACtB,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,OAAO,GACV,UAAU,GAAG,SAAS,CAQxB"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/core/marks/shared.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACX,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,MAAM,iBAAiB,CAAC;AAEzB,gCAAgC;AAChC,MAAM,WAAW,gBAAgB,CAAC,MAAM;IACvC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnD;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,MAAM,CACrB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,GACvB,MAAM,CAER;AAED,2FAA2F;AAC3F,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,cAAc,CAAC,MAAM,EACpC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,CAAC,EAC7C,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAAG;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EACpE,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,gBAAgB,GACvB,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,CAkB/B;AAED,wBAAgB,YAAY,CAAC,MAAM,EAClC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B;IACF,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAAC;CAC3C,CAYA;AAED,uFAAuF;AACvF,wBAAgB,KAAK,CAAC,MAAM,SAAS,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,UAAU,GACrC,WAAW,CACb,MAAM,EACN;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAC3D,CAYA;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACtB,KAAK,EAAE,kBAAkB,EACzB,GAAG,EAAE,OAAO,GACV,UAAU,GAAG,SAAS,CAQxB;AAED,wEAAwE;AACxE,wBAAgB,IAAI,CAAC,MAAM,EAC1B,GAAG,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAET"}
@@ -63,12 +63,16 @@ function valueOn(scale, raw) {
63
63
  }
64
64
  return numericValue(raw);
65
65
  }
66
+ function tips(tip, datum, index) {
67
+ return typeof tip === "function" ? tip(datum, index) : tip !== false;
68
+ }
66
69
  export {
67
70
  colorChannel,
68
71
  groupBySeries,
69
72
  markId,
70
73
  paint,
71
74
  seriesResolver,
75
+ tips,
72
76
  valueOn
73
77
  };
74
78
  //# sourceMappingURL=shared.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/shared.ts"],
4
- "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartChannel,\n\tChartMarkContext,\n\tChartPaint,\n\tChartPositionScale,\n\tChartValue,\n} from \"#/core/types.ts\";\n\n/** Options every mark takes. */\nexport interface ChartMarkOptions<TDatum> {\n\t/** Stable identity, so focus and legend state survive a data update. */\n\treadonly id?: string;\n\t/** The series' name when the mark has no color channel: legend, tooltip, table. */\n\treadonly label?: string;\n\t/** A field or function whose distinct values split the mark into coloured series. */\n\treadonly color?: ChartAccessor<TDatum, ChartValue>;\n\t/** `false` keeps the mark out of focus, tooltips and the data table. */\n\treadonly tip?: boolean;\n\treadonly opacity?: number;\n}\n\nexport function markId(\n\tid: string | undefined,\n\tkind: string,\n\tcontext: ChartMarkContext,\n): string {\n\treturn id ?? `${kind}-${context.markIndex}`;\n}\n\n/** A datum's series: its color value when there is a color channel, the mark otherwise. */\nexport interface SeriesInfo {\n\treadonly key: string;\n\treadonly label: string | undefined;\n\treadonly color: string;\n}\n\nexport function seriesResolver<TDatum>(\n\tcolors: ReadonlyArray<ChartValue | undefined>,\n\toptions: ChartMarkOptions<TDatum> & { readonly fixedColor?: string },\n\tid: string,\n\tcontext: ChartMarkContext,\n): (index: number) => SeriesInfo {\n\tconst fallback =\n\t\toptions.fixedColor ?? context.paletteColor(context.markIndex);\n\tconst single: SeriesInfo = { key: id, label: options.label, color: fallback };\n\tif (options.color === undefined) {\n\t\treturn () => single;\n\t}\n\treturn (index) => {\n\t\tconst value = colors[index];\n\t\tif (value === undefined) {\n\t\t\treturn single;\n\t\t}\n\t\treturn {\n\t\t\tkey: categoryKey(value),\n\t\t\tlabel: context.seriesLabel(value),\n\t\t\tcolor: options.fixedColor ?? context.colorOf(value),\n\t\t};\n\t};\n}\n\nexport function colorChannel<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ChartMarkOptions<TDatum>,\n): {\n\treadonly values: ReadonlyArray<ChartValue | undefined>;\n\treadonly channel: ChartChannel | undefined;\n} {\n\tconst values = readChannel(data, options.color);\n\treturn {\n\t\tvalues,\n\t\tchannel:\n\t\t\toptions.color === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tvalues: values.filter(isPlaceable),\n\t\t\t\t\t\tlabel: channelLabel(options.color),\n\t\t\t\t\t},\n\t};\n}\n\n/** Keeps only the defined paint keys, so a scene snapshot shows what was asked for. */\nexport function paint<TPaint extends ChartPaint>(values: TPaint): TPaint {\n\treturn Object.fromEntries(\n\t\tObject.entries(values).filter(([, value]) => value !== undefined),\n\t) as TPaint;\n}\n\n/** Indices of `data` grouped by series, each group in data order. */\nexport function groupBySeries(\n\tcount: number,\n\tseriesOf: (index: number) => SeriesInfo,\n): ReadonlyMap<\n\tstring,\n\t{ readonly series: SeriesInfo; readonly indices: number[] }\n> {\n\tconst groups = new Map<string, { series: SeriesInfo; indices: number[] }>();\n\tfor (let index = 0; index < count; index += 1) {\n\t\tconst series = seriesOf(index);\n\t\tconst group = groups.get(series.key);\n\t\tif (group === undefined) {\n\t\t\tgroups.set(series.key, { series, indices: [index] });\n\t\t} else {\n\t\t\tgroup.indices.push(index);\n\t\t}\n\t}\n\treturn groups;\n}\n\n/**\n * A raw channel value as the scale can place it, or `undefined` for a gap. A\n * continuous scale reads numeric strings as numbers; a discrete one takes any\n * category as is.\n */\nexport function valueOn(\n\tscale: ChartPositionScale,\n\traw: unknown,\n): ChartValue | undefined {\n\tif (scale.kind === \"band\" || scale.kind === \"point\") {\n\t\treturn isPlaceable(raw) ? raw : undefined;\n\t}\n\tif (raw instanceof Date) {\n\t\treturn Number.isNaN(raw.getTime()) ? undefined : raw;\n\t}\n\treturn numericValue(raw);\n}\n"],
5
- "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,mBAAmB;AAuBrB,SAAS,OACf,IACA,MACA,SACS;AACT,SAAO,MAAM,GAAG,IAAI,IAAI,QAAQ,SAAS;AAC1C;AASO,SAAS,eACf,QACA,SACA,IACA,SACgC;AAChC,QAAM,WACL,QAAQ,cAAc,QAAQ,aAAa,QAAQ,SAAS;AAC7D,QAAM,SAAqB,EAAE,KAAK,IAAI,OAAO,QAAQ,OAAO,OAAO,SAAS;AAC5E,MAAI,QAAQ,UAAU,QAAW;AAChC,WAAO,MAAM;AAAA,EACd;AACA,SAAO,CAAC,UAAU;AACjB,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,UAAU,QAAW;AACxB,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN,KAAK,YAAY,KAAK;AAAA,MACtB,OAAO,QAAQ,YAAY,KAAK;AAAA,MAChC,OAAO,QAAQ,cAAc,QAAQ,QAAQ,KAAK;AAAA,IACnD;AAAA,EACD;AACD;AAEO,SAAS,aACf,MACA,SAIC;AACD,QAAM,SAAS,YAAY,MAAM,QAAQ,KAAK;AAC9C,SAAO;AAAA,IACN;AAAA,IACA,SACC,QAAQ,UAAU,SACf,SACA;AAAA,MACA,QAAQ,OAAO,OAAO,WAAW;AAAA,MACjC,OAAO,aAAa,QAAQ,KAAK;AAAA,IAClC;AAAA,EACJ;AACD;AAGO,SAAS,MAAiC,QAAwB;AACxE,SAAO,OAAO;AAAA,IACb,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAAA,EACjE;AACD;AAGO,SAAS,cACf,OACA,UAIC;AACD,QAAM,SAAS,oBAAI,IAAuD;AAC1E,WAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;AAC9C,UAAM,SAAS,SAAS,KAAK;AAC7B,UAAM,QAAQ,OAAO,IAAI,OAAO,GAAG;AACnC,QAAI,UAAU,QAAW;AACxB,aAAO,IAAI,OAAO,KAAK,EAAE,QAAQ,SAAS,CAAC,KAAK,EAAE,CAAC;AAAA,IACpD,OAAO;AACN,YAAM,QAAQ,KAAK,KAAK;AAAA,IACzB;AAAA,EACD;AACA,SAAO;AACR;AAOO,SAAS,QACf,OACA,KACyB;AACzB,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS,SAAS;AACpD,WAAO,YAAY,GAAG,IAAI,MAAM;AAAA,EACjC;AACA,MAAI,eAAe,MAAM;AACxB,WAAO,OAAO,MAAM,IAAI,QAAQ,CAAC,IAAI,SAAY;AAAA,EAClD;AACA,SAAO,aAAa,GAAG;AACxB;",
4
+ "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartChannel,\n\tChartMarkContext,\n\tChartPaint,\n\tChartPositionScale,\n\tChartValue,\n} from \"#/core/types.ts\";\n\n/** Options every mark takes. */\nexport interface ChartMarkOptions<TDatum> {\n\t/** Stable identity, so focus and legend state survive a data update. */\n\treadonly id?: string;\n\t/** The series' name when the mark has no color channel: legend, tooltip, table. */\n\treadonly label?: string;\n\t/** A field or function whose distinct values split the mark into coloured series. */\n\treadonly color?: ChartAccessor<TDatum, ChartValue>;\n\t/**\n\t * `false` keeps the mark out of focus, tooltips and the data table; a\n\t * function decides per datum (the point where a recorded line hands over\n\t * to its dashed projection belongs to one of the two, not both).\n\t */\n\treadonly tip?: boolean | ((datum: TDatum, index: number) => boolean);\n\treadonly opacity?: number;\n}\n\nexport function markId(\n\tid: string | undefined,\n\tkind: string,\n\tcontext: ChartMarkContext,\n): string {\n\treturn id ?? `${kind}-${context.markIndex}`;\n}\n\n/** A datum's series: its color value when there is a color channel, the mark otherwise. */\nexport interface SeriesInfo {\n\treadonly key: string;\n\treadonly label: string | undefined;\n\treadonly color: string;\n}\n\nexport function seriesResolver<TDatum>(\n\tcolors: ReadonlyArray<ChartValue | undefined>,\n\toptions: ChartMarkOptions<TDatum> & { readonly fixedColor?: string },\n\tid: string,\n\tcontext: ChartMarkContext,\n): (index: number) => SeriesInfo {\n\tconst fallback =\n\t\toptions.fixedColor ?? context.paletteColor(context.markIndex);\n\tconst single: SeriesInfo = { key: id, label: options.label, color: fallback };\n\tif (options.color === undefined) {\n\t\treturn () => single;\n\t}\n\treturn (index) => {\n\t\tconst value = colors[index];\n\t\tif (value === undefined) {\n\t\t\treturn single;\n\t\t}\n\t\treturn {\n\t\t\tkey: categoryKey(value),\n\t\t\tlabel: context.seriesLabel(value),\n\t\t\tcolor: options.fixedColor ?? context.colorOf(value),\n\t\t};\n\t};\n}\n\nexport function colorChannel<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: ChartMarkOptions<TDatum>,\n): {\n\treadonly values: ReadonlyArray<ChartValue | undefined>;\n\treadonly channel: ChartChannel | undefined;\n} {\n\tconst values = readChannel(data, options.color);\n\treturn {\n\t\tvalues,\n\t\tchannel:\n\t\t\toptions.color === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tvalues: values.filter(isPlaceable),\n\t\t\t\t\t\tlabel: channelLabel(options.color),\n\t\t\t\t\t},\n\t};\n}\n\n/** Keeps only the defined paint keys, so a scene snapshot shows what was asked for. */\nexport function paint<TPaint extends ChartPaint>(values: TPaint): TPaint {\n\treturn Object.fromEntries(\n\t\tObject.entries(values).filter(([, value]) => value !== undefined),\n\t) as TPaint;\n}\n\n/** Indices of `data` grouped by series, each group in data order. */\nexport function groupBySeries(\n\tcount: number,\n\tseriesOf: (index: number) => SeriesInfo,\n): ReadonlyMap<\n\tstring,\n\t{ readonly series: SeriesInfo; readonly indices: number[] }\n> {\n\tconst groups = new Map<string, { series: SeriesInfo; indices: number[] }>();\n\tfor (let index = 0; index < count; index += 1) {\n\t\tconst series = seriesOf(index);\n\t\tconst group = groups.get(series.key);\n\t\tif (group === undefined) {\n\t\t\tgroups.set(series.key, { series, indices: [index] });\n\t\t} else {\n\t\t\tgroup.indices.push(index);\n\t\t}\n\t}\n\treturn groups;\n}\n\n/**\n * A raw channel value as the scale can place it, or `undefined` for a gap. A\n * continuous scale reads numeric strings as numbers; a discrete one takes any\n * category as is.\n */\nexport function valueOn(\n\tscale: ChartPositionScale,\n\traw: unknown,\n): ChartValue | undefined {\n\tif (scale.kind === \"band\" || scale.kind === \"point\") {\n\t\treturn isPlaceable(raw) ? raw : undefined;\n\t}\n\tif (raw instanceof Date) {\n\t\treturn Number.isNaN(raw.getTime()) ? undefined : raw;\n\t}\n\treturn numericValue(raw);\n}\n\n/** Whether a datum takes part in focus, tooltips and the data table. */\nexport function tips<TDatum>(\n\ttip: ChartMarkOptions<TDatum>[\"tip\"],\n\tdatum: TDatum,\n\tindex: number,\n): boolean {\n\treturn typeof tip === \"function\" ? tip(datum, index) : tip !== false;\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,mBAAmB;AA2BrB,SAAS,OACf,IACA,MACA,SACS;AACT,SAAO,MAAM,GAAG,IAAI,IAAI,QAAQ,SAAS;AAC1C;AASO,SAAS,eACf,QACA,SACA,IACA,SACgC;AAChC,QAAM,WACL,QAAQ,cAAc,QAAQ,aAAa,QAAQ,SAAS;AAC7D,QAAM,SAAqB,EAAE,KAAK,IAAI,OAAO,QAAQ,OAAO,OAAO,SAAS;AAC5E,MAAI,QAAQ,UAAU,QAAW;AAChC,WAAO,MAAM;AAAA,EACd;AACA,SAAO,CAAC,UAAU;AACjB,UAAM,QAAQ,OAAO,KAAK;AAC1B,QAAI,UAAU,QAAW;AACxB,aAAO;AAAA,IACR;AACA,WAAO;AAAA,MACN,KAAK,YAAY,KAAK;AAAA,MACtB,OAAO,QAAQ,YAAY,KAAK;AAAA,MAChC,OAAO,QAAQ,cAAc,QAAQ,QAAQ,KAAK;AAAA,IACnD;AAAA,EACD;AACD;AAEO,SAAS,aACf,MACA,SAIC;AACD,QAAM,SAAS,YAAY,MAAM,QAAQ,KAAK;AAC9C,SAAO;AAAA,IACN;AAAA,IACA,SACC,QAAQ,UAAU,SACf,SACA;AAAA,MACA,QAAQ,OAAO,OAAO,WAAW;AAAA,MACjC,OAAO,aAAa,QAAQ,KAAK;AAAA,IAClC;AAAA,EACJ;AACD;AAGO,SAAS,MAAiC,QAAwB;AACxE,SAAO,OAAO;AAAA,IACb,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,UAAU,MAAS;AAAA,EACjE;AACD;AAGO,SAAS,cACf,OACA,UAIC;AACD,QAAM,SAAS,oBAAI,IAAuD;AAC1E,WAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS,GAAG;AAC9C,UAAM,SAAS,SAAS,KAAK;AAC7B,UAAM,QAAQ,OAAO,IAAI,OAAO,GAAG;AACnC,QAAI,UAAU,QAAW;AACxB,aAAO,IAAI,OAAO,KAAK,EAAE,QAAQ,SAAS,CAAC,KAAK,EAAE,CAAC;AAAA,IACpD,OAAO;AACN,YAAM,QAAQ,KAAK,KAAK;AAAA,IACzB;AAAA,EACD;AACA,SAAO;AACR;AAOO,SAAS,QACf,OACA,KACyB;AACzB,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS,SAAS;AACpD,WAAO,YAAY,GAAG,IAAI,MAAM;AAAA,EACjC;AACA,MAAI,eAAe,MAAM;AACxB,WAAO,OAAO,MAAM,IAAI,QAAQ,CAAC,IAAI,SAAY;AAAA,EAClD;AACA,SAAO,aAAa,GAAG;AACxB;AAGO,SAAS,KACf,KACA,OACA,OACU;AACV,SAAO,OAAO,QAAQ,aAAa,IAAI,OAAO,KAAK,IAAI,QAAQ;AAChE;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dodge.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/dodge.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,YAAY,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACrE,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC;AAKD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAC5B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,GAC3B,SAAS,CAmGX"}
1
+ {"version":3,"file":"dodge.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/dodge.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,YAAY,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACrE,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC;AAKD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAC5B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,GAC3B,SAAS,CAmGX"}
@@ -4,6 +4,7 @@ import {
4
4
  markId,
5
5
  paint,
6
6
  seriesResolver,
7
+ tips,
7
8
  valueOn
8
9
  } from "../shared.js";
9
10
  const DEFAULT_RADIUS = 4;
@@ -73,7 +74,7 @@ function dodgeY(data, options) {
73
74
  r,
74
75
  paint: paint({ fill: series.color, opacity: options.opacity })
75
76
  });
76
- if (options.tip !== false) {
77
+ if (tips(options.tip, data[entry.index], entry.index)) {
77
78
  points.push({
78
79
  key: `${id}:${entry.index}`,
79
80
  markId: id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/core/marks/stats/dodge.ts"],
4
- "sourcesContent": ["import { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface DodgeOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x: ChartAccessor<TDatum, ChartValue>;\n\treadonly r?: number;\n\treadonly fill?: string;\n\t/** Grow from the middle of the plot, or up from its bottom. */\n\treadonly anchor?: \"middle\" | \"bottom\";\n}\n\nconst DEFAULT_RADIUS = 4;\nconst SPACING = 1;\n\n/**\n * A beeswarm: one dot per datum along x, nudged up or down just enough not\n * to overlap, so a crowd of values shows its shape and every value stays\n * visible and focusable.\n */\nexport function dodgeY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: DodgeOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x);\n\tconst colors = colorChannel(data, options);\n\tconst r = options.r ?? DEFAULT_RADIUS;\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"point\",\n\t\tchannels: {\n\t\t\tx: {\n\t\t\t\tvalues: xs.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.x) ?? options.label,\n\t\t\t\tinset: r,\n\t\t\t},\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"dodgeY\", context);\n\t\t\tconst xScale = context.scales.x;\n\t\t\tif (xScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst { plot } = context;\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst order = xs\n\t\t\t\t.map((raw, index) => ({ index, value: valueOn(xScale, raw) }))\n\t\t\t\t.filter(\n\t\t\t\t\t(entry): entry is { index: number; value: ChartValue } =>\n\t\t\t\t\t\tentry.value !== undefined,\n\t\t\t\t)\n\t\t\t\t.map((entry) => ({ ...entry, x: xScale.center(entry.value) }))\n\t\t\t\t.sort((left, right) => left.x - right.x);\n\t\t\tconst placed: Array<{ x: number; y: number }> = [];\n\t\t\tconst diameter = r * 2 + SPACING;\n\t\t\tconst bottom = options.anchor === \"bottom\";\n\t\t\tconst baseline = bottom\n\t\t\t\t? plot.y + plot.height - r\n\t\t\t\t: plot.y + plot.height / 2;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const entry of order) {\n\t\t\t\tconst near = placed.filter(\n\t\t\t\t\t(other) => Math.abs(other.x - entry.x) < diameter,\n\t\t\t\t);\n\t\t\t\tlet offset = 0;\n\t\t\t\t// Try 0, +1, \u22121, +2, \u22122 half-diameters (only upwards from a bottom anchor).\n\t\t\t\tfor (let step = 0; ; step += 1) {\n\t\t\t\t\tconst magnitude = Math.ceil(step / (bottom ? 1 : 2)) * (diameter / 2);\n\t\t\t\t\toffset = bottom || step % 2 === 1 ? -magnitude : magnitude;\n\t\t\t\t\tconst y = baseline + offset;\n\t\t\t\t\tif (\n\t\t\t\t\t\tnear.every(\n\t\t\t\t\t\t\t(other) => Math.hypot(other.x - entry.x, other.y - y) >= diameter,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst y = baseline + offset;\n\t\t\t\tplaced.push({ x: entry.x, y });\n\t\t\t\tconst series = seriesOf(entry.index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"circle\",\n\t\t\t\t\tkey: `${id}:${entry.index}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\tcx: entry.x,\n\t\t\t\t\tcy: y,\n\t\t\t\t\tr,\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (options.tip !== false) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${entry.index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex: entry.index,\n\t\t\t\t\t\tdatum: data[entry.index],\n\t\t\t\t\t\tx: entry.x,\n\t\t\t\t\t\ty,\n\t\t\t\t\t\txValue: entry.value,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: series.label ?? context.formatX(entry.value),\n\t\t\t\t\t\tvalue: context.formatX(entry.value),\n\t\t\t\t\t\thit: {\n\t\t\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\t\t\trect: { x: entry.x - r, y: y - r, width: r * 2, height: r * 2 },\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\ttips,\n\tvalueOn,\n} from \"#/core/marks/shared.ts\";\nimport type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface DodgeOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x: ChartAccessor<TDatum, ChartValue>;\n\treadonly r?: number;\n\treadonly fill?: string;\n\t/** Grow from the middle of the plot, or up from its bottom. */\n\treadonly anchor?: \"middle\" | \"bottom\";\n}\n\nconst DEFAULT_RADIUS = 4;\nconst SPACING = 1;\n\n/**\n * A beeswarm: one dot per datum along x, nudged up or down just enough not\n * to overlap, so a crowd of values shows its shape and every value stays\n * visible and focusable.\n */\nexport function dodgeY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: DodgeOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x);\n\tconst colors = colorChannel(data, options);\n\tconst r = options.r ?? DEFAULT_RADIUS;\n\treturn {\n\t\tid: options.id,\n\t\tcoordinate: \"cartesian\",\n\t\tfocusOrder: \"point\",\n\t\tchannels: {\n\t\t\tx: {\n\t\t\t\tvalues: xs.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.x) ?? options.label,\n\t\t\t\tinset: r,\n\t\t\t},\n\t\t\tcolor: colors.channel,\n\t\t},\n\t\trender(context) {\n\t\t\tconst id = markId(options.id, \"dodgeY\", context);\n\t\t\tconst xScale = context.scales.x;\n\t\t\tif (xScale === undefined) {\n\t\t\t\treturn { nodes: [] };\n\t\t\t}\n\t\t\tconst { plot } = context;\n\t\t\tconst seriesOf = seriesResolver(\n\t\t\t\tcolors.values,\n\t\t\t\t{ ...options, fixedColor: options.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst order = xs\n\t\t\t\t.map((raw, index) => ({ index, value: valueOn(xScale, raw) }))\n\t\t\t\t.filter(\n\t\t\t\t\t(entry): entry is { index: number; value: ChartValue } =>\n\t\t\t\t\t\tentry.value !== undefined,\n\t\t\t\t)\n\t\t\t\t.map((entry) => ({ ...entry, x: xScale.center(entry.value) }))\n\t\t\t\t.sort((left, right) => left.x - right.x);\n\t\t\tconst placed: Array<{ x: number; y: number }> = [];\n\t\t\tconst diameter = r * 2 + SPACING;\n\t\t\tconst bottom = options.anchor === \"bottom\";\n\t\t\tconst baseline = bottom\n\t\t\t\t? plot.y + plot.height - r\n\t\t\t\t: plot.y + plot.height / 2;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const entry of order) {\n\t\t\t\tconst near = placed.filter(\n\t\t\t\t\t(other) => Math.abs(other.x - entry.x) < diameter,\n\t\t\t\t);\n\t\t\t\tlet offset = 0;\n\t\t\t\t// Try 0, +1, \u22121, +2, \u22122 half-diameters (only upwards from a bottom anchor).\n\t\t\t\tfor (let step = 0; ; step += 1) {\n\t\t\t\t\tconst magnitude = Math.ceil(step / (bottom ? 1 : 2)) * (diameter / 2);\n\t\t\t\t\toffset = bottom || step % 2 === 1 ? -magnitude : magnitude;\n\t\t\t\t\tconst y = baseline + offset;\n\t\t\t\t\tif (\n\t\t\t\t\t\tnear.every(\n\t\t\t\t\t\t\t(other) => Math.hypot(other.x - entry.x, other.y - y) >= diameter,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst y = baseline + offset;\n\t\t\t\tplaced.push({ x: entry.x, y });\n\t\t\t\tconst series = seriesOf(entry.index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"circle\",\n\t\t\t\t\tkey: `${id}:${entry.index}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\tcx: entry.x,\n\t\t\t\t\tcy: y,\n\t\t\t\t\tr,\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (tips(options.tip, data[entry.index], entry.index)) {\n\t\t\t\t\tpoints.push({\n\t\t\t\t\t\tkey: `${id}:${entry.index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex: entry.index,\n\t\t\t\t\t\tdatum: data[entry.index],\n\t\t\t\t\t\tx: entry.x,\n\t\t\t\t\t\ty,\n\t\t\t\t\t\txValue: entry.value,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\ttitle: series.label ?? context.formatX(entry.value),\n\t\t\t\t\t\tvalue: context.formatX(entry.value),\n\t\t\t\t\t\thit: {\n\t\t\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\t\t\trect: { x: entry.x - r, y: y - r, width: r * 2, height: r * 2 },\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { nodes, points };\n\t\t},\n\t};\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["y"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"histogram.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/histogram.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE5E,MAAM,WAAW,gBAAgB,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACzE,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,yFAAyF;IACzF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,GAAG;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC7B;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CACxB,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB3C;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAC/B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B,SAAS,CAqDX"}
1
+ {"version":3,"file":"histogram.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/histogram.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE5E,MAAM,WAAW,gBAAgB,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACzE,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,yFAAyF;IACzF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,GAAG;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC7B;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CACxB,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAC7B,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB3C;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAC/B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC/B,SAAS,CAsDX"}
@@ -54,7 +54,8 @@ function histogram(data, options) {
54
54
  return rectY(bins, {
55
55
  id: options.id,
56
56
  label: options.label,
57
- tip: options.tip,
57
+ // Bins are not the caller's data: only a plain on/off carries over.
58
+ tip: typeof options.tip === "function" ? void 0 : options.tip,
58
59
  opacity: options.opacity,
59
60
  fill: options.fill,
60
61
  x1: (bin) => bin.x1,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/core/marks/stats/histogram.ts"],
4
- "sourcesContent": ["import { isPlaceable, numericValue, readChannel } from \"#/core/channel.ts\";\nimport { rectY } from \"#/core/marks/rect.ts\";\nimport type { ChartMarkOptions } from \"#/core/marks/shared.ts\";\nimport { tickStep } from \"#/core/ticks.ts\";\nimport type { ChartAccessor, ChartMark, ChartValue } from \"#/core/types.ts\";\n\nexport interface HistogramOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x: ChartAccessor<TDatum, ChartValue>;\n\t/** About how many bins: the edges land on round numbers, so the count is approximate. */\n\treadonly bins?: number;\n\treadonly fill?: string;\n\t/** Each bin's share of the total instead of its count. */\n\treadonly normalize?: boolean;\n}\n\nexport interface Bin {\n\treadonly x1: number;\n\treadonly x2: number;\n\treadonly count: number;\n\treadonly series?: ChartValue;\n}\n\n/** Round-edged bins over the values' extent, every value in exactly one. */\nexport function binValues(\n\tvalues: ReadonlyArray<number>,\n\ttarget: number,\n): ReadonlyArray<{ x1: number; x2: number }> {\n\tconst finite = values.filter(Number.isFinite);\n\tif (finite.length === 0) {\n\t\treturn [];\n\t}\n\tconst low = Math.min(...finite);\n\tconst high = Math.max(...finite);\n\tconst step = tickStep(low, high, target) || 1;\n\tconst first = Math.floor(low / step) * step;\n\tconst count = Math.max(\n\t\t1,\n\t\tMath.ceil((high - first) / step + (high === first ? 1 : 0)),\n\t);\n\treturn Array.from({ length: count }, (_unused, index) => ({\n\t\tx1: first + index * step,\n\t\tx2: first + (index + 1) * step,\n\t}));\n}\n\nconst DEFAULT_BINS = 20;\n\n/**\n * Counts per bin, as touching rectangles over a continuous x. With a color\n * channel the series stack inside each bin.\n */\nexport function histogram<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: HistogramOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x).map(numericValue);\n\tconst colors = readChannel(data, options.color);\n\tconst edges = binValues(\n\t\txs.filter((value): value is number => value !== undefined),\n\t\toptions.bins ?? DEFAULT_BINS,\n\t);\n\tconst seriesValues =\n\t\toptions.color === undefined\n\t\t\t? [undefined]\n\t\t\t: [\n\t\t\t\t\t...new Map(\n\t\t\t\t\t\tcolors.filter(isPlaceable).map((value) => [String(value), value]),\n\t\t\t\t\t).values(),\n\t\t\t\t];\n\tconst total = xs.filter((value) => value !== undefined).length || 1;\n\tconst bins: Bin[] = [];\n\tfor (const series of seriesValues) {\n\t\tfor (const [binIndex, edge] of edges.entries()) {\n\t\t\tconst last = binIndex === edges.length - 1;\n\t\t\tlet count = 0;\n\t\t\tfor (const [index, x] of xs.entries()) {\n\t\t\t\tconst inSeries =\n\t\t\t\t\tseries === undefined || String(colors[index]) === String(series);\n\t\t\t\tif (\n\t\t\t\t\tinSeries &&\n\t\t\t\t\tx !== undefined &&\n\t\t\t\t\tx >= edge.x1 &&\n\t\t\t\t\t(x < edge.x2 || (last && x <= edge.x2))\n\t\t\t\t) {\n\t\t\t\t\tcount += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbins.push({\n\t\t\t\t...edge,\n\t\t\t\tcount: options.normalize ? count / total : count,\n\t\t\t\tseries,\n\t\t\t});\n\t\t}\n\t}\n\treturn rectY(bins, {\n\t\tid: options.id,\n\t\tlabel: options.label,\n\t\ttip: options.tip,\n\t\topacity: options.opacity,\n\t\tfill: options.fill,\n\t\tx1: (bin) => bin.x1,\n\t\tx2: (bin) => bin.x2,\n\t\ty: (bin) => bin.count,\n\t\t...(options.color === undefined\n\t\t\t? {}\n\t\t\t: { color: (bin: Bin) => bin.series as ChartValue }),\n\t});\n}\n"],
5
- "mappings": "AAAA,SAAS,aAAa,cAAc,mBAAmB;AACvD,SAAS,aAAa;AAEtB,SAAS,gBAAgB;AAoBlB,SAAS,UACf,QACA,QAC4C;AAC5C,QAAM,SAAS,OAAO,OAAO,OAAO,QAAQ;AAC5C,MAAI,OAAO,WAAW,GAAG;AACxB,WAAO,CAAC;AAAA,EACT;AACA,QAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,QAAM,OAAO,KAAK,IAAI,GAAG,MAAM;AAC/B,QAAM,OAAO,SAAS,KAAK,MAAM,MAAM,KAAK;AAC5C,QAAM,QAAQ,KAAK,MAAM,MAAM,IAAI,IAAI;AACvC,QAAM,QAAQ,KAAK;AAAA,IAClB;AAAA,IACA,KAAK,MAAM,OAAO,SAAS,QAAQ,SAAS,QAAQ,IAAI,EAAE;AAAA,EAC3D;AACA,SAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,SAAS,WAAW;AAAA,IACzD,IAAI,QAAQ,QAAQ;AAAA,IACpB,IAAI,SAAS,QAAQ,KAAK;AAAA,EAC3B,EAAE;AACH;AAEA,MAAM,eAAe;AAMd,SAAS,UACf,MACA,SACY;AACZ,QAAM,KAAK,YAAY,MAAM,QAAQ,CAAC,EAAE,IAAI,YAAY;AACxD,QAAM,SAAS,YAAY,MAAM,QAAQ,KAAK;AAC9C,QAAM,QAAQ;AAAA,IACb,GAAG,OAAO,CAAC,UAA2B,UAAU,MAAS;AAAA,IACzD,QAAQ,QAAQ;AAAA,EACjB;AACA,QAAM,eACL,QAAQ,UAAU,SACf,CAAC,MAAS,IACV;AAAA,IACA,GAAG,IAAI;AAAA,MACN,OAAO,OAAO,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,KAAK,GAAG,KAAK,CAAC;AAAA,IACjE,EAAE,OAAO;AAAA,EACV;AACH,QAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,UAAU,MAAS,EAAE,UAAU;AAClE,QAAM,OAAc,CAAC;AACrB,aAAW,UAAU,cAAc;AAClC,eAAW,CAAC,UAAU,IAAI,KAAK,MAAM,QAAQ,GAAG;AAC/C,YAAM,OAAO,aAAa,MAAM,SAAS;AACzC,UAAI,QAAQ;AACZ,iBAAW,CAAC,OAAO,CAAC,KAAK,GAAG,QAAQ,GAAG;AACtC,cAAM,WACL,WAAW,UAAa,OAAO,OAAO,KAAK,CAAC,MAAM,OAAO,MAAM;AAChE,YACC,YACA,MAAM,UACN,KAAK,KAAK,OACT,IAAI,KAAK,MAAO,QAAQ,KAAK,KAAK,KAClC;AACD,mBAAS;AAAA,QACV;AAAA,MACD;AACA,WAAK,KAAK;AAAA,QACT,GAAG;AAAA,QACH,OAAO,QAAQ,YAAY,QAAQ,QAAQ;AAAA,QAC3C;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AACA,SAAO,MAAM,MAAM;AAAA,IAClB,IAAI,QAAQ;AAAA,IACZ,OAAO,QAAQ;AAAA,IACf,KAAK,QAAQ;AAAA,IACb,SAAS,QAAQ;AAAA,IACjB,MAAM,QAAQ;AAAA,IACd,IAAI,CAAC,QAAQ,IAAI;AAAA,IACjB,IAAI,CAAC,QAAQ,IAAI;AAAA,IACjB,GAAG,CAAC,QAAQ,IAAI;AAAA,IAChB,GAAI,QAAQ,UAAU,SACnB,CAAC,IACD,EAAE,OAAO,CAAC,QAAa,IAAI,OAAqB;AAAA,EACpD,CAAC;AACF;",
4
+ "sourcesContent": ["import { isPlaceable, numericValue, readChannel } from \"#/core/channel.ts\";\nimport { rectY } from \"#/core/marks/rect.ts\";\nimport type { ChartMarkOptions } from \"#/core/marks/shared.ts\";\nimport { tickStep } from \"#/core/ticks.ts\";\nimport type { ChartAccessor, ChartMark, ChartValue } from \"#/core/types.ts\";\n\nexport interface HistogramOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x: ChartAccessor<TDatum, ChartValue>;\n\t/** About how many bins: the edges land on round numbers, so the count is approximate. */\n\treadonly bins?: number;\n\treadonly fill?: string;\n\t/** Each bin's share of the total instead of its count. */\n\treadonly normalize?: boolean;\n}\n\nexport interface Bin {\n\treadonly x1: number;\n\treadonly x2: number;\n\treadonly count: number;\n\treadonly series?: ChartValue;\n}\n\n/** Round-edged bins over the values' extent, every value in exactly one. */\nexport function binValues(\n\tvalues: ReadonlyArray<number>,\n\ttarget: number,\n): ReadonlyArray<{ x1: number; x2: number }> {\n\tconst finite = values.filter(Number.isFinite);\n\tif (finite.length === 0) {\n\t\treturn [];\n\t}\n\tconst low = Math.min(...finite);\n\tconst high = Math.max(...finite);\n\tconst step = tickStep(low, high, target) || 1;\n\tconst first = Math.floor(low / step) * step;\n\tconst count = Math.max(\n\t\t1,\n\t\tMath.ceil((high - first) / step + (high === first ? 1 : 0)),\n\t);\n\treturn Array.from({ length: count }, (_unused, index) => ({\n\t\tx1: first + index * step,\n\t\tx2: first + (index + 1) * step,\n\t}));\n}\n\nconst DEFAULT_BINS = 20;\n\n/**\n * Counts per bin, as touching rectangles over a continuous x. With a color\n * channel the series stack inside each bin.\n */\nexport function histogram<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: HistogramOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x).map(numericValue);\n\tconst colors = readChannel(data, options.color);\n\tconst edges = binValues(\n\t\txs.filter((value): value is number => value !== undefined),\n\t\toptions.bins ?? DEFAULT_BINS,\n\t);\n\tconst seriesValues =\n\t\toptions.color === undefined\n\t\t\t? [undefined]\n\t\t\t: [\n\t\t\t\t\t...new Map(\n\t\t\t\t\t\tcolors.filter(isPlaceable).map((value) => [String(value), value]),\n\t\t\t\t\t).values(),\n\t\t\t\t];\n\tconst total = xs.filter((value) => value !== undefined).length || 1;\n\tconst bins: Bin[] = [];\n\tfor (const series of seriesValues) {\n\t\tfor (const [binIndex, edge] of edges.entries()) {\n\t\t\tconst last = binIndex === edges.length - 1;\n\t\t\tlet count = 0;\n\t\t\tfor (const [index, x] of xs.entries()) {\n\t\t\t\tconst inSeries =\n\t\t\t\t\tseries === undefined || String(colors[index]) === String(series);\n\t\t\t\tif (\n\t\t\t\t\tinSeries &&\n\t\t\t\t\tx !== undefined &&\n\t\t\t\t\tx >= edge.x1 &&\n\t\t\t\t\t(x < edge.x2 || (last && x <= edge.x2))\n\t\t\t\t) {\n\t\t\t\t\tcount += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbins.push({\n\t\t\t\t...edge,\n\t\t\t\tcount: options.normalize ? count / total : count,\n\t\t\t\tseries,\n\t\t\t});\n\t\t}\n\t}\n\treturn rectY(bins, {\n\t\tid: options.id,\n\t\tlabel: options.label,\n\t\t// Bins are not the caller's data: only a plain on/off carries over.\n\t\ttip: typeof options.tip === \"function\" ? undefined : options.tip,\n\t\topacity: options.opacity,\n\t\tfill: options.fill,\n\t\tx1: (bin) => bin.x1,\n\t\tx2: (bin) => bin.x2,\n\t\ty: (bin) => bin.count,\n\t\t...(options.color === undefined\n\t\t\t? {}\n\t\t\t: { color: (bin: Bin) => bin.series as ChartValue }),\n\t});\n}\n"],
5
+ "mappings": "AAAA,SAAS,aAAa,cAAc,mBAAmB;AACvD,SAAS,aAAa;AAEtB,SAAS,gBAAgB;AAoBlB,SAAS,UACf,QACA,QAC4C;AAC5C,QAAM,SAAS,OAAO,OAAO,OAAO,QAAQ;AAC5C,MAAI,OAAO,WAAW,GAAG;AACxB,WAAO,CAAC;AAAA,EACT;AACA,QAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,QAAM,OAAO,KAAK,IAAI,GAAG,MAAM;AAC/B,QAAM,OAAO,SAAS,KAAK,MAAM,MAAM,KAAK;AAC5C,QAAM,QAAQ,KAAK,MAAM,MAAM,IAAI,IAAI;AACvC,QAAM,QAAQ,KAAK;AAAA,IAClB;AAAA,IACA,KAAK,MAAM,OAAO,SAAS,QAAQ,SAAS,QAAQ,IAAI,EAAE;AAAA,EAC3D;AACA,SAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,CAAC,SAAS,WAAW;AAAA,IACzD,IAAI,QAAQ,QAAQ;AAAA,IACpB,IAAI,SAAS,QAAQ,KAAK;AAAA,EAC3B,EAAE;AACH;AAEA,MAAM,eAAe;AAMd,SAAS,UACf,MACA,SACY;AACZ,QAAM,KAAK,YAAY,MAAM,QAAQ,CAAC,EAAE,IAAI,YAAY;AACxD,QAAM,SAAS,YAAY,MAAM,QAAQ,KAAK;AAC9C,QAAM,QAAQ;AAAA,IACb,GAAG,OAAO,CAAC,UAA2B,UAAU,MAAS;AAAA,IACzD,QAAQ,QAAQ;AAAA,EACjB;AACA,QAAM,eACL,QAAQ,UAAU,SACf,CAAC,MAAS,IACV;AAAA,IACA,GAAG,IAAI;AAAA,MACN,OAAO,OAAO,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,KAAK,GAAG,KAAK,CAAC;AAAA,IACjE,EAAE,OAAO;AAAA,EACV;AACH,QAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,UAAU,MAAS,EAAE,UAAU;AAClE,QAAM,OAAc,CAAC;AACrB,aAAW,UAAU,cAAc;AAClC,eAAW,CAAC,UAAU,IAAI,KAAK,MAAM,QAAQ,GAAG;AAC/C,YAAM,OAAO,aAAa,MAAM,SAAS;AACzC,UAAI,QAAQ;AACZ,iBAAW,CAAC,OAAO,CAAC,KAAK,GAAG,QAAQ,GAAG;AACtC,cAAM,WACL,WAAW,UAAa,OAAO,OAAO,KAAK,CAAC,MAAM,OAAO,MAAM;AAChE,YACC,YACA,MAAM,UACN,KAAK,KAAK,OACT,IAAI,KAAK,MAAO,QAAQ,KAAK,KAAK,KAClC;AACD,mBAAS;AAAA,QACV;AAAA,MACD;AACA,WAAK,KAAK;AAAA,QACT,GAAG;AAAA,QACH,OAAO,QAAQ,YAAY,QAAQ,QAAQ;AAAA,QAC3C;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AACA,SAAO,MAAM,MAAM;AAAA,IAClB,IAAI,QAAQ;AAAA,IACZ,OAAO,QAAQ;AAAA;AAAA,IAEf,KAAK,OAAO,QAAQ,QAAQ,aAAa,SAAY,QAAQ;AAAA,IAC7D,SAAS,QAAQ;AAAA,IACjB,MAAM,QAAQ;AAAA,IACd,IAAI,CAAC,QAAQ,IAAI;AAAA,IACjB,IAAI,CAAC,QAAQ,IAAI;AAAA,IACjB,GAAG,CAAC,QAAQ,IAAI;AAAA,IAChB,GAAI,QAAQ,UAAU,SACnB,CAAC,IACD,EAAE,OAAO,CAAC,QAAa,IAAI,OAAqB;AAAA,EACpD,CAAC;AACF;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"waffle.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/waffle.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAKrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,aAAa,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACtE,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,gCAAgC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAC7B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,SAAS,CAiGX"}
1
+ {"version":3,"file":"waffle.d.ts","sourceRoot":"","sources":["../../../../src/core/marks/stats/waffle.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,aAAa,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACtE,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,QAAQ,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C,gCAAgC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAC7B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,SAAS,CAiGX"}
@@ -8,7 +8,8 @@ import {
8
8
  colorChannel,
9
9
  markId,
10
10
  paint,
11
- seriesResolver
11
+ seriesResolver,
12
+ tips
12
13
  } from "../shared.js";
13
14
  import { categoryKey } from "../../scales/discrete.js";
14
15
  const DEFAULT_COLUMNS = 10;
@@ -89,7 +90,7 @@ function waffleY(data, options) {
89
90
  paint: paint({ fill: series.color, opacity: options.opacity })
90
91
  });
91
92
  }
92
- if (options.tip !== false) {
93
+ if (tips(options.tip, data[index], index)) {
93
94
  points.push({
94
95
  key: `${id}:${index}`,
95
96
  markId: id,