@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 +1 @@
1
- {"version":3,"file":"paint-scene.d.ts","sourceRoot":"","sources":["../../src/canvas/paint-scene.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,UAAU,EAAa,MAAM,iBAAiB,CAAC;AA0IzE,6EAA6E;AAC7E,wBAAgB,UAAU,CACzB,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAClC,UAAU,EAAE,MAAM,QAOlB"}
1
+ {"version":3,"file":"paint-scene.d.ts","sourceRoot":"","sources":["../../src/canvas/paint-scene.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAc,UAAU,EAAa,MAAM,iBAAiB,CAAC;AAsLzE,6EAA6E;AAC7E,wBAAgB,UAAU,CACzB,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAClC,UAAU,EAAE,MAAM,QAOlB"}
@@ -10,6 +10,36 @@ const CANVAS_ALIGN = {
10
10
  middle: "center",
11
11
  end: "right"
12
12
  };
13
+ const HATCH_STEP = 6;
14
+ const hatchCache = /* @__PURE__ */ new WeakMap();
15
+ function hatchPattern(context, color) {
16
+ const cache = hatchCache.get(context) ?? /* @__PURE__ */ new Map();
17
+ hatchCache.set(context, cache);
18
+ const cached = cache.get(color);
19
+ if (cached !== void 0) {
20
+ return cached;
21
+ }
22
+ const tile = document.createElement("canvas");
23
+ tile.width = HATCH_STEP;
24
+ tile.height = HATCH_STEP;
25
+ const pen = tile.getContext("2d");
26
+ if (pen === null) {
27
+ return color;
28
+ }
29
+ pen.strokeStyle = color;
30
+ pen.lineWidth = 1.5;
31
+ pen.beginPath();
32
+ pen.moveTo(0, HATCH_STEP);
33
+ pen.lineTo(HATCH_STEP, 0);
34
+ pen.moveTo(-1, 1);
35
+ pen.lineTo(1, -1);
36
+ pen.moveTo(HATCH_STEP - 1, HATCH_STEP + 1);
37
+ pen.lineTo(HATCH_STEP + 1, HATCH_STEP - 1);
38
+ pen.stroke();
39
+ const pattern = context.createPattern(tile, "repeat") ?? color;
40
+ cache.set(color, pattern);
41
+ return pattern;
42
+ }
13
43
  function dashes(dasharray) {
14
44
  if (!dasharray) {
15
45
  return [];
@@ -21,7 +51,7 @@ function fillAndStroke(environment, paint, draw) {
21
51
  const opacity = paint.opacity ?? 1;
22
52
  if (paint.fill && paint.fill !== "none") {
23
53
  context.globalAlpha = opacity * (paint.fillOpacity ?? 1);
24
- context.fillStyle = resolve(paint.fill);
54
+ context.fillStyle = paint.hatch ? hatchPattern(context, resolve(paint.fill)) : resolve(paint.fill);
25
55
  draw("fill");
26
56
  }
27
57
  if (paint.stroke && paint.stroke !== "none") {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/paint-scene.ts"],
4
- "sourcesContent": ["import { roundedBarPath } from \"#/core/paths.ts\";\nimport type { ChartPaint, ChartScene, SceneNode } from \"#/core/types.ts\";\n\nconst CANVAS_BASELINE = {\n\ttop: \"top\",\n\tmiddle: \"middle\",\n\tbottom: \"bottom\",\n\talphabetic: \"alphabetic\",\n} as const satisfies Record<string, CanvasTextBaseline>;\n\nconst CANVAS_ALIGN = {\n\tstart: \"left\",\n\tmiddle: \"center\",\n\tend: \"right\",\n} as const satisfies Record<string, CanvasTextAlign>;\n\nfunction dashes(dasharray: string | undefined): number[] {\n\tif (!dasharray) {\n\t\treturn [];\n\t}\n\treturn dasharray\n\t\t.split(/[\\s,]+/)\n\t\t.map(Number)\n\t\t.filter((value) => Number.isFinite(value));\n}\n\ninterface PaintEnvironment {\n\treadonly context: CanvasRenderingContext2D;\n\treadonly resolve: (color: string) => string;\n\treadonly fontFamily: string;\n}\n\nfunction fillAndStroke(\n\tenvironment: PaintEnvironment,\n\tpaint: ChartPaint,\n\tdraw: (mode: \"fill\" | \"stroke\") => void,\n) {\n\tconst { context, resolve } = environment;\n\tconst opacity = paint.opacity ?? 1;\n\tif (paint.fill && paint.fill !== \"none\") {\n\t\tcontext.globalAlpha = opacity * (paint.fillOpacity ?? 1);\n\t\tcontext.fillStyle = resolve(paint.fill);\n\t\tdraw(\"fill\");\n\t}\n\tif (paint.stroke && paint.stroke !== \"none\") {\n\t\tcontext.globalAlpha = opacity * (paint.strokeOpacity ?? 1);\n\t\tcontext.strokeStyle = resolve(paint.stroke);\n\t\tcontext.lineWidth = paint.strokeWidth ?? 1;\n\t\tcontext.lineCap = paint.strokeLinecap ?? \"butt\";\n\t\tcontext.lineJoin = paint.strokeLinejoin ?? \"miter\";\n\t\tcontext.setLineDash(dashes(paint.strokeDasharray));\n\t\tdraw(\"stroke\");\n\t\tcontext.setLineDash([]);\n\t}\n\tcontext.globalAlpha = 1;\n}\n\nfunction paintNode(environment: PaintEnvironment, node: SceneNode) {\n\tconst { context } = environment;\n\tswitch (node.kind) {\n\t\tcase \"group\":\n\t\t\tcontext.save();\n\t\t\tif (node.translate) {\n\t\t\t\tcontext.translate(node.translate.x, node.translate.y);\n\t\t\t}\n\t\t\tif (node.clip) {\n\t\t\t\tcontext.beginPath();\n\t\t\t\tcontext.rect(\n\t\t\t\t\tnode.clip.x,\n\t\t\t\t\tnode.clip.y,\n\t\t\t\t\tnode.clip.width,\n\t\t\t\t\tnode.clip.height,\n\t\t\t\t);\n\t\t\t\tcontext.clip();\n\t\t\t}\n\t\t\tfor (const child of node.children) {\n\t\t\t\tpaintNode(environment, child);\n\t\t\t}\n\t\t\tcontext.restore();\n\t\t\treturn;\n\t\tcase \"rect\": {\n\t\t\tconst path = node.corners\n\t\t\t\t? new Path2D(roundedBarPath({ ...node, radius: node.corners }))\n\t\t\t\t: undefined;\n\t\t\tfillAndStroke(environment, node.paint, (mode) => {\n\t\t\t\tif (path) {\n\t\t\t\t\tcontext[mode](path);\n\t\t\t\t} else if (mode === \"fill\") {\n\t\t\t\t\tcontext.fillRect(node.x, node.y, node.width, node.height);\n\t\t\t\t} else {\n\t\t\t\t\tcontext.strokeRect(node.x, node.y, node.width, node.height);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tcase \"path\": {\n\t\t\tif (node.d === \"\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst path = new Path2D(node.d);\n\t\t\tfillAndStroke(environment, node.paint, (mode) => context[mode](path));\n\t\t\treturn;\n\t\t}\n\t\tcase \"circle\": {\n\t\t\tconst path = new Path2D();\n\t\t\tpath.arc(node.cx, node.cy, node.r, 0, Math.PI * 2);\n\t\t\tfillAndStroke(environment, node.paint, (mode) => context[mode](path));\n\t\t\treturn;\n\t\t}\n\t\tcase \"line\": {\n\t\t\tconst path = new Path2D();\n\t\t\tpath.moveTo(node.x1, node.y1);\n\t\t\tpath.lineTo(node.x2, node.y2);\n\t\t\tfillAndStroke(environment, { ...node.paint, fill: undefined }, () =>\n\t\t\t\tcontext.stroke(path),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tcase \"text\": {\n\t\t\tconst { paint } = node;\n\t\t\tcontext.save();\n\t\t\tcontext.translate(node.x, node.y);\n\t\t\tif (node.rotate) {\n\t\t\t\tcontext.rotate((node.rotate * Math.PI) / 180);\n\t\t\t}\n\t\t\tcontext.font = `${paint.fontWeight ?? 400} ${paint.fontSize ?? 12}px ${environment.fontFamily}`;\n\t\t\tcontext.textAlign = CANVAS_ALIGN[paint.textAnchor ?? \"start\"];\n\t\t\tcontext.textBaseline = CANVAS_BASELINE[paint.baseline ?? \"alphabetic\"];\n\t\t\tfillAndStroke(environment, paint, (mode) =>\n\t\t\t\tmode === \"fill\"\n\t\t\t\t\t? context.fillText(node.text, 0, 0)\n\t\t\t\t\t: context.strokeText(node.text, 0, 0),\n\t\t\t);\n\t\t\tcontext.restore();\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/** Paints the whole scene. The canvas is already scaled to device pixels. */\nexport function paintScene(\n\tcontext: CanvasRenderingContext2D,\n\tscene: ChartScene,\n\tresolve: (color: string) => string,\n\tfontFamily: string,\n) {\n\tcontext.clearRect(0, 0, scene.width, scene.height);\n\tconst environment = { context, resolve, fontFamily };\n\tfor (const node of scene.nodes) {\n\t\tpaintNode(environment, node);\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { roundedBarPath } from \"#/core/paths.ts\";\nimport type { ChartPaint, ChartScene, SceneNode } from \"#/core/types.ts\";\n\nconst CANVAS_BASELINE = {\n\ttop: \"top\",\n\tmiddle: \"middle\",\n\tbottom: \"bottom\",\n\talphabetic: \"alphabetic\",\n} as const satisfies Record<string, CanvasTextBaseline>;\n\nconst CANVAS_ALIGN = {\n\tstart: \"left\",\n\tmiddle: \"center\",\n\tend: \"right\",\n} as const satisfies Record<string, CanvasTextAlign>;\n\nconst HATCH_STEP = 6;\nconst hatchCache = new WeakMap<\n\tCanvasRenderingContext2D,\n\tMap<string, CanvasPattern | string>\n>();\n\n/** Diagonal lines every few pixels in the colour, as the SVG pattern draws them. */\nfunction hatchPattern(\n\tcontext: CanvasRenderingContext2D,\n\tcolor: string,\n): CanvasPattern | string {\n\tconst cache =\n\t\thatchCache.get(context) ?? new Map<string, CanvasPattern | string>();\n\thatchCache.set(context, cache);\n\tconst cached = cache.get(color);\n\tif (cached !== undefined) {\n\t\treturn cached;\n\t}\n\tconst tile = document.createElement(\"canvas\");\n\ttile.width = HATCH_STEP;\n\ttile.height = HATCH_STEP;\n\tconst pen = tile.getContext(\"2d\");\n\tif (pen === null) {\n\t\treturn color;\n\t}\n\tpen.strokeStyle = color;\n\tpen.lineWidth = 1.5;\n\tpen.beginPath();\n\t// One diagonal across the tile, plus the two corner stubs that join it to\n\t// the neighbouring tiles' lines.\n\tpen.moveTo(0, HATCH_STEP);\n\tpen.lineTo(HATCH_STEP, 0);\n\tpen.moveTo(-1, 1);\n\tpen.lineTo(1, -1);\n\tpen.moveTo(HATCH_STEP - 1, HATCH_STEP + 1);\n\tpen.lineTo(HATCH_STEP + 1, HATCH_STEP - 1);\n\tpen.stroke();\n\tconst pattern = context.createPattern(tile, \"repeat\") ?? color;\n\tcache.set(color, pattern);\n\treturn pattern;\n}\n\nfunction dashes(dasharray: string | undefined): number[] {\n\tif (!dasharray) {\n\t\treturn [];\n\t}\n\treturn dasharray\n\t\t.split(/[\\s,]+/)\n\t\t.map(Number)\n\t\t.filter((value) => Number.isFinite(value));\n}\n\ninterface PaintEnvironment {\n\treadonly context: CanvasRenderingContext2D;\n\treadonly resolve: (color: string) => string;\n\treadonly fontFamily: string;\n}\n\nfunction fillAndStroke(\n\tenvironment: PaintEnvironment,\n\tpaint: ChartPaint,\n\tdraw: (mode: \"fill\" | \"stroke\") => void,\n) {\n\tconst { context, resolve } = environment;\n\tconst opacity = paint.opacity ?? 1;\n\tif (paint.fill && paint.fill !== \"none\") {\n\t\tcontext.globalAlpha = opacity * (paint.fillOpacity ?? 1);\n\t\tcontext.fillStyle = paint.hatch\n\t\t\t? hatchPattern(context, resolve(paint.fill))\n\t\t\t: resolve(paint.fill);\n\t\tdraw(\"fill\");\n\t}\n\tif (paint.stroke && paint.stroke !== \"none\") {\n\t\tcontext.globalAlpha = opacity * (paint.strokeOpacity ?? 1);\n\t\tcontext.strokeStyle = resolve(paint.stroke);\n\t\tcontext.lineWidth = paint.strokeWidth ?? 1;\n\t\tcontext.lineCap = paint.strokeLinecap ?? \"butt\";\n\t\tcontext.lineJoin = paint.strokeLinejoin ?? \"miter\";\n\t\tcontext.setLineDash(dashes(paint.strokeDasharray));\n\t\tdraw(\"stroke\");\n\t\tcontext.setLineDash([]);\n\t}\n\tcontext.globalAlpha = 1;\n}\n\nfunction paintNode(environment: PaintEnvironment, node: SceneNode) {\n\tconst { context } = environment;\n\tswitch (node.kind) {\n\t\tcase \"group\":\n\t\t\tcontext.save();\n\t\t\tif (node.translate) {\n\t\t\t\tcontext.translate(node.translate.x, node.translate.y);\n\t\t\t}\n\t\t\tif (node.clip) {\n\t\t\t\tcontext.beginPath();\n\t\t\t\tcontext.rect(\n\t\t\t\t\tnode.clip.x,\n\t\t\t\t\tnode.clip.y,\n\t\t\t\t\tnode.clip.width,\n\t\t\t\t\tnode.clip.height,\n\t\t\t\t);\n\t\t\t\tcontext.clip();\n\t\t\t}\n\t\t\tfor (const child of node.children) {\n\t\t\t\tpaintNode(environment, child);\n\t\t\t}\n\t\t\tcontext.restore();\n\t\t\treturn;\n\t\tcase \"rect\": {\n\t\t\tconst path = node.corners\n\t\t\t\t? new Path2D(roundedBarPath({ ...node, radius: node.corners }))\n\t\t\t\t: undefined;\n\t\t\tfillAndStroke(environment, node.paint, (mode) => {\n\t\t\t\tif (path) {\n\t\t\t\t\tcontext[mode](path);\n\t\t\t\t} else if (mode === \"fill\") {\n\t\t\t\t\tcontext.fillRect(node.x, node.y, node.width, node.height);\n\t\t\t\t} else {\n\t\t\t\t\tcontext.strokeRect(node.x, node.y, node.width, node.height);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tcase \"path\": {\n\t\t\tif (node.d === \"\") {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst path = new Path2D(node.d);\n\t\t\tfillAndStroke(environment, node.paint, (mode) => context[mode](path));\n\t\t\treturn;\n\t\t}\n\t\tcase \"circle\": {\n\t\t\tconst path = new Path2D();\n\t\t\tpath.arc(node.cx, node.cy, node.r, 0, Math.PI * 2);\n\t\t\tfillAndStroke(environment, node.paint, (mode) => context[mode](path));\n\t\t\treturn;\n\t\t}\n\t\tcase \"line\": {\n\t\t\tconst path = new Path2D();\n\t\t\tpath.moveTo(node.x1, node.y1);\n\t\t\tpath.lineTo(node.x2, node.y2);\n\t\t\tfillAndStroke(environment, { ...node.paint, fill: undefined }, () =>\n\t\t\t\tcontext.stroke(path),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tcase \"text\": {\n\t\t\tconst { paint } = node;\n\t\t\tcontext.save();\n\t\t\tcontext.translate(node.x, node.y);\n\t\t\tif (node.rotate) {\n\t\t\t\tcontext.rotate((node.rotate * Math.PI) / 180);\n\t\t\t}\n\t\t\tcontext.font = `${paint.fontWeight ?? 400} ${paint.fontSize ?? 12}px ${environment.fontFamily}`;\n\t\t\tcontext.textAlign = CANVAS_ALIGN[paint.textAnchor ?? \"start\"];\n\t\t\tcontext.textBaseline = CANVAS_BASELINE[paint.baseline ?? \"alphabetic\"];\n\t\t\tfillAndStroke(environment, paint, (mode) =>\n\t\t\t\tmode === \"fill\"\n\t\t\t\t\t? context.fillText(node.text, 0, 0)\n\t\t\t\t\t: context.strokeText(node.text, 0, 0),\n\t\t\t);\n\t\t\tcontext.restore();\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/** Paints the whole scene. The canvas is already scaled to device pixels. */\nexport function paintScene(\n\tcontext: CanvasRenderingContext2D,\n\tscene: ChartScene,\n\tresolve: (color: string) => string,\n\tfontFamily: string,\n) {\n\tcontext.clearRect(0, 0, scene.width, scene.height);\n\tconst environment = { context, resolve, fontFamily };\n\tfor (const node of scene.nodes) {\n\t\tpaintNode(environment, node);\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../../src/core/marks/area.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,KAAK,EACX,aAAa,EACb,UAAU,EACV,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CACzB;AAsLD,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX;AAED,+CAA+C;AAC/C,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX"}
1
+ {"version":3,"file":"area.d.ts","sourceRoot":"","sources":["../../../src/core/marks/area.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,KAAK,EACX,aAAa,EACb,UAAU,EACV,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CACzB;AAsLD,sDAAsD;AACtD,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX;AAED,+CAA+C;AAC/C,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX"}
@@ -9,7 +9,8 @@ import {
9
9
  groupBySeries,
10
10
  markId,
11
11
  paint,
12
- seriesResolver
12
+ seriesResolver,
13
+ tips
13
14
  } from "./shared.js";
14
15
  import { stackSegments } from "./stack.js";
15
16
  import { areaPath, linePath } from "../paths.js";
@@ -110,7 +111,7 @@ function areaMark(kind, data, options) {
110
111
  const run = runs[runs.length - 1];
111
112
  run.top.push(top);
112
113
  run.bottom.push(place(along, edge.low));
113
- if (options.tip === false) {
114
+ if (!tips(options.tip, data[index], index)) {
114
115
  continue;
115
116
  }
116
117
  const value = explicit ? edge.high : values[index] ?? 0;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/area.ts"],
4
- "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tcolorChannel,\n\tgroupBySeries,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { areaPath, type ChartXY, linePath } from \"#/core/paths.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartCurve,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface AreaOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** Explicit lower and upper edges: a confidence band, a min-max range. */\n\treadonly from?: ChartAccessor<TDatum, ChartValue>;\n\treadonly to?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\t/** Draw the upper edge as a line in the series colour. */\n\treadonly line?: boolean;\n\treadonly strokeWidth?: number;\n\treadonly strokeDasharray?: string;\n\treadonly curve?: ChartCurve;\n\t/** Series stack on one another. On by default when there is a color channel. */\n\treadonly stack?: boolean;\n}\n\nconst DEFAULT_FILL_OPACITY = 0.3;\nconst DEFAULT_STROKE_WIDTH = 2;\n\nfunction areaMark<TDatum>(\n\tkind: \"areaY\" | \"areaX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: AreaOptions<TDatum>,\n): ChartMark {\n\tconst vertical = kind === \"areaY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(\n\t\tdata,\n\t\tpositionKey ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst values = readChannel(\n\t\tdata,\n\t\tvalueKey ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst explicit = options.from !== undefined && options.to !== undefined;\n\tconst froms = readChannel(data, options.from).map(numericValue);\n\tconst tos = readChannel(data, options.to).map(numericValue);\n\tconst stacked = !explicit && (options.stack ?? options.color !== undefined);\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tpositions.map((position) =>\n\t\t\t\t\tisPlaceable(position) ? categoryKey(position) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\tconst edges = positions.map((position, index) => {\n\t\tif (!isPlaceable(position)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (explicit) {\n\t\t\tconst low = froms[index];\n\t\t\tconst high = tos[index];\n\t\t\treturn low === undefined || high === undefined\n\t\t\t\t? undefined\n\t\t\t\t: { low, high };\n\t\t}\n\t\tconst value = values[index];\n\t\tif (value === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn segments[index] ?? { low: 0, high: value };\n\t});\n\n\tconst positionChannel = {\n\t\tvalues: positions.filter(isPlaceable),\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: edges.flatMap((edge) => (edge ? [edge.low, edge.high] : [])),\n\t\tincludeZero: !explicit,\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.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tfunction place(along: number, value: number): ChartXY {\n\t\t\t\tconst across = valueScale?.map(value) ?? 0;\n\t\t\t\treturn vertical ? { x: along, y: across } : { x: across, y: along };\n\t\t\t}\n\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\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\tconst runs: Array<{ top: ChartXY[]; bottom: ChartXY[] }> = [\n\t\t\t\t\t{ top: [], bottom: [] },\n\t\t\t\t];\n\t\t\t\tfor (const index of indices) {\n\t\t\t\t\tconst position = positions[index];\n\t\t\t\t\tconst edge = edges[index];\n\t\t\t\t\tif (!isPlaceable(position) || edge === undefined) {\n\t\t\t\t\t\truns.push({ top: [], bottom: [] });\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 top = place(along, edge.high);\n\t\t\t\t\tconst run = runs[runs.length - 1];\n\t\t\t\t\trun.top.push(top);\n\t\t\t\t\trun.bottom.push(place(along, edge.low));\n\t\t\t\t\tif (options.tip === false) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst value = explicit ? edge.high : (values[index] ?? 0);\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: top.x,\n\t\t\t\t\t\ty: top.y,\n\t\t\t\t\t\txValue: vertical ? position : value,\n\t\t\t\t\t\tyValue: vertical ? value : position,\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: vertical\n\t\t\t\t\t\t\t? context.formatX(position)\n\t\t\t\t\t\t\t: context.formatY(position),\n\t\t\t\t\t\tvalue: vertical ? context.formatY(value) : context.formatX(value),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst shaped = runs.filter((run) => run.top.length > 0);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:area:${series.key}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: shaped\n\t\t\t\t\t\t.map((run) => areaPath(run.top, run.bottom, options.curve))\n\t\t\t\t\t\t.join(\"\"),\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 ?? DEFAULT_FILL_OPACITY,\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.line) {\n\t\t\t\t\tnodes.push({\n\t\t\t\t\t\tkind: \"path\",\n\t\t\t\t\t\tkey: `${id}:line:${series.key}`,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t\td: shaped.map((run) => linePath(run.top, options.curve)).join(\"\"),\n\t\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t\t\tstroke: series.color,\n\t\t\t\t\t\t\tstrokeWidth: options.strokeWidth ?? DEFAULT_STROKE_WIDTH,\n\t\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\n\t\t\t\t\t\t\tstrokeLinecap: \"round\",\n\t\t\t\t\t\t\tstrokeLinejoin: \"round\",\n\t\t\t\t\t\t\topacity: options.opacity,\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\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\n/** A filled band under a series, over x positions. */\nexport function areaY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: AreaOptions<TDatum> = {},\n): ChartMark {\n\treturn areaMark(\"areaY\", data, options);\n}\n\n/** A filled band along x, over y positions. */\nexport function areaX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: AreaOptions<TDatum> = {},\n): ChartMark {\n\treturn areaMark(\"areaX\", data, options);\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\tgroupBySeries,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\ttips,\n} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { areaPath, type ChartXY, linePath } from \"#/core/paths.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartCurve,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface AreaOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** Explicit lower and upper edges: a confidence band, a min-max range. */\n\treadonly from?: ChartAccessor<TDatum, ChartValue>;\n\treadonly to?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\t/** Draw the upper edge as a line in the series colour. */\n\treadonly line?: boolean;\n\treadonly strokeWidth?: number;\n\treadonly strokeDasharray?: string;\n\treadonly curve?: ChartCurve;\n\t/** Series stack on one another. On by default when there is a color channel. */\n\treadonly stack?: boolean;\n}\n\nconst DEFAULT_FILL_OPACITY = 0.3;\nconst DEFAULT_STROKE_WIDTH = 2;\n\nfunction areaMark<TDatum>(\n\tkind: \"areaY\" | \"areaX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: AreaOptions<TDatum>,\n): ChartMark {\n\tconst vertical = kind === \"areaY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(\n\t\tdata,\n\t\tpositionKey ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst values = readChannel(\n\t\tdata,\n\t\tvalueKey ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst explicit = options.from !== undefined && options.to !== undefined;\n\tconst froms = readChannel(data, options.from).map(numericValue);\n\tconst tos = readChannel(data, options.to).map(numericValue);\n\tconst stacked = !explicit && (options.stack ?? options.color !== undefined);\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tpositions.map((position) =>\n\t\t\t\t\tisPlaceable(position) ? categoryKey(position) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\tconst edges = positions.map((position, index) => {\n\t\tif (!isPlaceable(position)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (explicit) {\n\t\t\tconst low = froms[index];\n\t\t\tconst high = tos[index];\n\t\t\treturn low === undefined || high === undefined\n\t\t\t\t? undefined\n\t\t\t\t: { low, high };\n\t\t}\n\t\tconst value = values[index];\n\t\tif (value === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn segments[index] ?? { low: 0, high: value };\n\t});\n\n\tconst positionChannel = {\n\t\tvalues: positions.filter(isPlaceable),\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: edges.flatMap((edge) => (edge ? [edge.low, edge.high] : [])),\n\t\tincludeZero: !explicit,\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.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tfunction place(along: number, value: number): ChartXY {\n\t\t\t\tconst across = valueScale?.map(value) ?? 0;\n\t\t\t\treturn vertical ? { x: along, y: across } : { x: across, y: along };\n\t\t\t}\n\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\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\tconst runs: Array<{ top: ChartXY[]; bottom: ChartXY[] }> = [\n\t\t\t\t\t{ top: [], bottom: [] },\n\t\t\t\t];\n\t\t\t\tfor (const index of indices) {\n\t\t\t\t\tconst position = positions[index];\n\t\t\t\t\tconst edge = edges[index];\n\t\t\t\t\tif (!isPlaceable(position) || edge === undefined) {\n\t\t\t\t\t\truns.push({ top: [], bottom: [] });\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 top = place(along, edge.high);\n\t\t\t\t\tconst run = runs[runs.length - 1];\n\t\t\t\t\trun.top.push(top);\n\t\t\t\t\trun.bottom.push(place(along, edge.low));\n\t\t\t\t\tif (!tips(options.tip, data[index], index)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tconst value = explicit ? edge.high : (values[index] ?? 0);\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: top.x,\n\t\t\t\t\t\ty: top.y,\n\t\t\t\t\t\txValue: vertical ? position : value,\n\t\t\t\t\t\tyValue: vertical ? value : position,\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: vertical\n\t\t\t\t\t\t\t? context.formatX(position)\n\t\t\t\t\t\t\t: context.formatY(position),\n\t\t\t\t\t\tvalue: vertical ? context.formatY(value) : context.formatX(value),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst shaped = runs.filter((run) => run.top.length > 0);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:area:${series.key}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: shaped\n\t\t\t\t\t\t.map((run) => areaPath(run.top, run.bottom, options.curve))\n\t\t\t\t\t\t.join(\"\"),\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 ?? DEFAULT_FILL_OPACITY,\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.line) {\n\t\t\t\t\tnodes.push({\n\t\t\t\t\t\tkind: \"path\",\n\t\t\t\t\t\tkey: `${id}:line:${series.key}`,\n\t\t\t\t\t\tseries: series.key,\n\t\t\t\t\t\trole: \"mark\",\n\t\t\t\t\t\td: shaped.map((run) => linePath(run.top, options.curve)).join(\"\"),\n\t\t\t\t\t\tpaint: paint({\n\t\t\t\t\t\t\tfill: \"none\",\n\t\t\t\t\t\t\tstroke: series.color,\n\t\t\t\t\t\t\tstrokeWidth: options.strokeWidth ?? DEFAULT_STROKE_WIDTH,\n\t\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\n\t\t\t\t\t\t\tstrokeLinecap: \"round\",\n\t\t\t\t\t\t\tstrokeLinejoin: \"round\",\n\t\t\t\t\t\t\topacity: options.opacity,\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\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\n/** A filled band under a series, over x positions. */\nexport function areaY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: AreaOptions<TDatum> = {},\n): ChartMark {\n\treturn areaMark(\"areaY\", data, options);\n}\n\n/** A filled band along x, over y positions. */\nexport function areaX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: AreaOptions<TDatum> = {},\n): ChartMark {\n\treturn areaMark(\"areaX\", data, options);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -18,6 +18,11 @@ export interface BarOptions<TDatum> extends ChartMarkOptions<TDatum> {
18
18
  readonly radius?: number;
19
19
  /** Pixels kept clear on each side of the bar inside its band. */
20
20
  readonly inset?: number;
21
+ /**
22
+ * Bars to draw hatched and outlined: projections, stages still in flight,
23
+ * anything pencilled in rather than recorded.
24
+ */
25
+ readonly projected?: (datum: TDatum, index: number) => boolean;
21
26
  }
22
27
  /** Upright bars: categories along x, values up y. */
23
28
  export declare function barY<TDatum>(data: ReadonlyArray<TDatum>, options?: BarOptions<TDatum>): ChartMark;
@@ -1 +1 @@
1
- {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../../src/core/marks/bar.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAKrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EACX,aAAa,EAEb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACnE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,8FAA8F;IAC9F,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AA6ND,qDAAqD;AACrD,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAEX;AAED,6DAA6D;AAC7D,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAEX"}
1
+ {"version":3,"file":"bar.d.ts","sourceRoot":"","sources":["../../../src/core/marks/bar.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EACX,aAAa,EAEb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACnE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,8FAA8F;IAC9F,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,gFAAgF;IAChF,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CAC/D;AAwOD,qDAAqD;AACrD,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAEX;AAED,6DAA6D;AAC7D,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAEX"}
@@ -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 { stackSegments } from "./stack.js";
14
15
  import { categoryKey } from "../scales/discrete.js";
@@ -133,15 +134,24 @@ function barMark(kind, data, options) {
133
134
  role: "mark",
134
135
  ...rect,
135
136
  corners: corners(vertical, bar, radius, explicit),
136
- paint: paint({
137
- fill: series.color,
138
- fillOpacity: options.fillOpacity,
139
- stroke: options.stroke,
140
- strokeDasharray: options.strokeDasharray,
141
- opacity: options.opacity
142
- })
137
+ paint: paint(
138
+ options.projected?.(data[bar.index], bar.index) ? {
139
+ fill: series.color,
140
+ hatch: true,
141
+ stroke: series.color,
142
+ strokeWidth: 1,
143
+ strokeDasharray: "3 2",
144
+ opacity: options.opacity
145
+ } : {
146
+ fill: series.color,
147
+ fillOpacity: options.fillOpacity,
148
+ stroke: options.stroke,
149
+ strokeDasharray: options.strokeDasharray,
150
+ opacity: options.opacity
151
+ }
152
+ )
143
153
  });
144
- if (options.tip === false) {
154
+ if (!tips(options.tip, data[bar.index], bar.index)) {
145
155
  continue;
146
156
  }
147
157
  const along = alongStart + alongSize / 2;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/bar.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} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartCorners,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface BarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** Explicit start and end of the bar on the value axis: floating bars, ranges, Gantt rows. */\n\treadonly from?: ChartAccessor<TDatum, ChartValue>;\n\treadonly to?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\treadonly stroke?: string;\n\treadonly strokeDasharray?: string;\n\t/** Series stack on one another. On by default when there is a color channel. */\n\treadonly stack?: boolean;\n\t/** Series stand side by side inside the band instead of stacking. */\n\treadonly group?: boolean;\n\t/** Corner radius of the bar's far end. */\n\treadonly radius?: number;\n\t/** Pixels kept clear on each side of the bar inside its band. */\n\treadonly inset?: number;\n}\n\nconst DEFAULT_RADIUS = 4;\n\ninterface BarDatum {\n\treadonly index: number;\n\treadonly position: ChartValue;\n\treadonly low: number;\n\treadonly high: number;\n\treadonly value: number;\n\t/** Round the far end: the outer segment of a stack, or any unstacked bar. */\n\treadonly outer: boolean;\n}\n\nfunction barMark<TDatum>(\n\tkind: \"barY\" | \"barX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum>,\n): ChartMark {\n\tconst vertical = kind === \"barY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(\n\t\tdata,\n\t\tpositionKey ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst values = readChannel(\n\t\tdata,\n\t\tvalueKey ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst explicit = options.from !== undefined && options.to !== undefined;\n\tconst froms = readChannel(data, options.from).map(numericValue);\n\tconst tos = readChannel(data, options.to).map(numericValue);\n\tconst stacked =\n\t\t!explicit &&\n\t\t!options.group &&\n\t\t(options.stack ?? options.color !== undefined);\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tpositions.map((position) =>\n\t\t\t\t\tisPlaceable(position) ? categoryKey(position) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\n\tconst bars: BarDatum[] = [];\n\tfor (const [index, position] of positions.entries()) {\n\t\tif (!isPlaceable(position)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (explicit) {\n\t\t\tconst low = froms[index];\n\t\t\tconst high = tos[index];\n\t\t\tif (low !== undefined && high !== undefined) {\n\t\t\t\tbars.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tposition,\n\t\t\t\t\tlow,\n\t\t\t\t\thigh,\n\t\t\t\t\tvalue: high - low,\n\t\t\t\t\touter: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = values[index];\n\t\tif (value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst segment = segments[index];\n\t\tbars.push(\n\t\t\tsegment === undefined\n\t\t\t\t? { index, position, low: 0, high: value, value, outer: true }\n\t\t\t\t: { index, position, ...segment, value },\n\t\t);\n\t}\n\n\tconst positionChannel = {\n\t\tvalues: bars.map((bar) => bar.position),\n\t\tdiscrete: \"band\" as const,\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: bars.flatMap((bar) => [bar.low, bar.high]),\n\t\tincludeZero: !explicit,\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.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst seriesOrder = [\n\t\t\t\t...new Set(bars.map((bar) => seriesOf(bar.index).key)),\n\t\t\t];\n\t\t\tconst lanes = options.group ? Math.max(1, seriesOrder.length) : 1;\n\t\t\tconst laneWidth = positionScale.bandwidth / lanes;\n\t\t\tconst inset = options.inset ?? 0;\n\t\t\tconst radius = options.radius ?? DEFAULT_RADIUS;\n\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const bar of bars) {\n\t\t\t\tconst series = seriesOf(bar.index);\n\t\t\t\tconst lane = options.group ? seriesOrder.indexOf(series.key) : 0;\n\t\t\t\tconst alongStart =\n\t\t\t\t\tpositionScale.map(bar.position) + lane * laneWidth + inset;\n\t\t\t\tconst alongSize = Math.max(0, laneWidth - inset * 2);\n\t\t\t\tconst lowPixel = valueScale.map(bar.low);\n\t\t\t\tconst highPixel = valueScale.map(bar.high);\n\t\t\t\tconst acrossStart = Math.min(lowPixel, highPixel);\n\t\t\t\tconst acrossSize = Math.abs(highPixel - lowPixel);\n\t\t\t\tconst rect = vertical\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tx: alongStart,\n\t\t\t\t\t\t\ty: acrossStart,\n\t\t\t\t\t\t\twidth: alongSize,\n\t\t\t\t\t\t\theight: acrossSize,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tx: acrossStart,\n\t\t\t\t\t\t\ty: alongStart,\n\t\t\t\t\t\t\twidth: acrossSize,\n\t\t\t\t\t\t\theight: alongSize,\n\t\t\t\t\t\t};\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\tkey: `${id}:${bar.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: corners(vertical, bar, radius, explicit),\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\tstroke: options.stroke,\n\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\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 along = alongStart + alongSize / 2;\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${bar.index}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex: bar.index,\n\t\t\t\t\tdatum: data[bar.index],\n\t\t\t\t\tx: vertical ? along : highPixel,\n\t\t\t\t\ty: vertical ? highPixel : along,\n\t\t\t\t\txValue: vertical ? bar.position : bar.value,\n\t\t\t\t\tyValue: vertical ? bar.value : bar.position,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: vertical\n\t\t\t\t\t\t? context.formatX(bar.position)\n\t\t\t\t\t\t: context.formatY(bar.position),\n\t\t\t\t\tvalue: vertical\n\t\t\t\t\t\t? context.formatY(bar.value)\n\t\t\t\t\t\t: context.formatX(bar.value),\n\t\t\t\t\thit: { kind: \"rect\", rect },\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\n/** Rounds the end of the bar away from zero, and only that end: stacked joins stay square. */\nfunction corners(\n\tvertical: boolean,\n\tbar: BarDatum,\n\tradius: number,\n\texplicit: boolean,\n): ChartCorners | undefined {\n\tif (radius === 0 || !bar.outer) {\n\t\treturn undefined;\n\t}\n\tif (explicit) {\n\t\treturn [radius, radius, radius, radius];\n\t}\n\tconst positive = bar.high >= bar.low;\n\tif (vertical) {\n\t\treturn positive ? [radius, radius, 0, 0] : [0, 0, radius, radius];\n\t}\n\treturn positive ? [0, radius, radius, 0] : [radius, 0, 0, radius];\n}\n\n/** Upright bars: categories along x, values up y. */\nexport function barY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum> = {},\n): ChartMark {\n\treturn barMark(\"barY\", data, options);\n}\n\n/** Bars on their side: categories down y, values along x. */\nexport function barX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum> = {},\n): ChartMark {\n\treturn barMark(\"barX\", data, options);\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} from \"#/core/marks/shared.ts\";\nimport { stackSegments } from \"#/core/marks/stack.ts\";\nimport { categoryKey } from \"#/core/scales/discrete.ts\";\nimport type {\n\tChartAccessor,\n\tChartCorners,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface BarOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** Explicit start and end of the bar on the value axis: floating bars, ranges, Gantt rows. */\n\treadonly from?: ChartAccessor<TDatum, ChartValue>;\n\treadonly to?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\treadonly stroke?: string;\n\treadonly strokeDasharray?: string;\n\t/** Series stack on one another. On by default when there is a color channel. */\n\treadonly stack?: boolean;\n\t/** Series stand side by side inside the band instead of stacking. */\n\treadonly group?: boolean;\n\t/** Corner radius of the bar's far end. */\n\treadonly radius?: number;\n\t/** Pixels kept clear on each side of the bar inside its band. */\n\treadonly inset?: number;\n\t/**\n\t * Bars to draw hatched and outlined: projections, stages still in flight,\n\t * anything pencilled in rather than recorded.\n\t */\n\treadonly projected?: (datum: TDatum, index: number) => boolean;\n}\n\nconst DEFAULT_RADIUS = 4;\n\ninterface BarDatum {\n\treadonly index: number;\n\treadonly position: ChartValue;\n\treadonly low: number;\n\treadonly high: number;\n\treadonly value: number;\n\t/** Round the far end: the outer segment of a stack, or any unstacked bar. */\n\treadonly outer: boolean;\n}\n\nfunction barMark<TDatum>(\n\tkind: \"barY\" | \"barX\",\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum>,\n): ChartMark {\n\tconst vertical = kind === \"barY\";\n\tconst positionKey = vertical ? options.x : options.y;\n\tconst valueKey = vertical ? options.y : options.x;\n\tconst positions = readChannel(\n\t\tdata,\n\t\tpositionKey ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst values = readChannel(\n\t\tdata,\n\t\tvalueKey ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t).map(numericValue);\n\tconst colors = colorChannel(data, options);\n\tconst explicit = options.from !== undefined && options.to !== undefined;\n\tconst froms = readChannel(data, options.from).map(numericValue);\n\tconst tos = readChannel(data, options.to).map(numericValue);\n\tconst stacked =\n\t\t!explicit &&\n\t\t!options.group &&\n\t\t(options.stack ?? options.color !== undefined);\n\tconst segments = stacked\n\t\t? stackSegments(\n\t\t\t\tpositions.map((position) =>\n\t\t\t\t\tisPlaceable(position) ? categoryKey(position) : undefined,\n\t\t\t\t),\n\t\t\t\tvalues,\n\t\t\t)\n\t\t: [];\n\n\tconst bars: BarDatum[] = [];\n\tfor (const [index, position] of positions.entries()) {\n\t\tif (!isPlaceable(position)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (explicit) {\n\t\t\tconst low = froms[index];\n\t\t\tconst high = tos[index];\n\t\t\tif (low !== undefined && high !== undefined) {\n\t\t\t\tbars.push({\n\t\t\t\t\tindex,\n\t\t\t\t\tposition,\n\t\t\t\t\tlow,\n\t\t\t\t\thigh,\n\t\t\t\t\tvalue: high - low,\n\t\t\t\t\touter: true,\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst value = values[index];\n\t\tif (value === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst segment = segments[index];\n\t\tbars.push(\n\t\t\tsegment === undefined\n\t\t\t\t? { index, position, low: 0, high: value, value, outer: true }\n\t\t\t\t: { index, position, ...segment, value },\n\t\t);\n\t}\n\n\tconst positionChannel = {\n\t\tvalues: bars.map((bar) => bar.position),\n\t\tdiscrete: \"band\" as const,\n\t\tlabel: channelLabel(positionKey),\n\t};\n\tconst valueChannel = {\n\t\tvalues: bars.flatMap((bar) => [bar.low, bar.high]),\n\t\tincludeZero: !explicit,\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.fill },\n\t\t\t\tid,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tconst seriesOrder = [\n\t\t\t\t...new Set(bars.map((bar) => seriesOf(bar.index).key)),\n\t\t\t];\n\t\t\tconst lanes = options.group ? Math.max(1, seriesOrder.length) : 1;\n\t\t\tconst laneWidth = positionScale.bandwidth / lanes;\n\t\t\tconst inset = options.inset ?? 0;\n\t\t\tconst radius = options.radius ?? DEFAULT_RADIUS;\n\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const bar of bars) {\n\t\t\t\tconst series = seriesOf(bar.index);\n\t\t\t\tconst lane = options.group ? seriesOrder.indexOf(series.key) : 0;\n\t\t\t\tconst alongStart =\n\t\t\t\t\tpositionScale.map(bar.position) + lane * laneWidth + inset;\n\t\t\t\tconst alongSize = Math.max(0, laneWidth - inset * 2);\n\t\t\t\tconst lowPixel = valueScale.map(bar.low);\n\t\t\t\tconst highPixel = valueScale.map(bar.high);\n\t\t\t\tconst acrossStart = Math.min(lowPixel, highPixel);\n\t\t\t\tconst acrossSize = Math.abs(highPixel - lowPixel);\n\t\t\t\tconst rect = vertical\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tx: alongStart,\n\t\t\t\t\t\t\ty: acrossStart,\n\t\t\t\t\t\t\twidth: alongSize,\n\t\t\t\t\t\t\theight: acrossSize,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tx: acrossStart,\n\t\t\t\t\t\t\ty: alongStart,\n\t\t\t\t\t\t\twidth: acrossSize,\n\t\t\t\t\t\t\theight: alongSize,\n\t\t\t\t\t\t};\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\tkey: `${id}:${bar.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: corners(vertical, bar, radius, explicit),\n\t\t\t\t\tpaint: paint(\n\t\t\t\t\t\toptions.projected?.(data[bar.index], bar.index)\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\t\t\t\thatch: true,\n\t\t\t\t\t\t\t\t\tstroke: series.color,\n\t\t\t\t\t\t\t\t\tstrokeWidth: 1,\n\t\t\t\t\t\t\t\t\tstrokeDasharray: \"3 2\",\n\t\t\t\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tfill: series.color,\n\t\t\t\t\t\t\t\t\tfillOpacity: options.fillOpacity,\n\t\t\t\t\t\t\t\t\tstroke: options.stroke,\n\t\t\t\t\t\t\t\t\tstrokeDasharray: options.strokeDasharray,\n\t\t\t\t\t\t\t\t\topacity: options.opacity,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t\tif (!tips(options.tip, data[bar.index], bar.index)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst along = alongStart + alongSize / 2;\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${bar.index}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex: bar.index,\n\t\t\t\t\tdatum: data[bar.index],\n\t\t\t\t\tx: vertical ? along : highPixel,\n\t\t\t\t\ty: vertical ? highPixel : along,\n\t\t\t\t\txValue: vertical ? bar.position : bar.value,\n\t\t\t\t\tyValue: vertical ? bar.value : bar.position,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\tseriesLabel: series.label,\n\t\t\t\t\tcolor: series.color,\n\t\t\t\t\ttitle: vertical\n\t\t\t\t\t\t? context.formatX(bar.position)\n\t\t\t\t\t\t: context.formatY(bar.position),\n\t\t\t\t\tvalue: vertical\n\t\t\t\t\t\t? context.formatY(bar.value)\n\t\t\t\t\t\t: context.formatX(bar.value),\n\t\t\t\t\thit: { kind: \"rect\", rect },\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\n/** Rounds the end of the bar away from zero, and only that end: stacked joins stay square. */\nfunction corners(\n\tvertical: boolean,\n\tbar: BarDatum,\n\tradius: number,\n\texplicit: boolean,\n): ChartCorners | undefined {\n\tif (radius === 0 || !bar.outer) {\n\t\treturn undefined;\n\t}\n\tif (explicit) {\n\t\treturn [radius, radius, radius, radius];\n\t}\n\tconst positive = bar.high >= bar.low;\n\tif (vertical) {\n\t\treturn positive ? [radius, radius, 0, 0] : [0, 0, radius, radius];\n\t}\n\treturn positive ? [0, radius, radius, 0] : [radius, 0, 0, radius];\n}\n\n/** Upright bars: categories along x, values up y. */\nexport function barY<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum> = {},\n): ChartMark {\n\treturn barMark(\"barY\", data, options);\n}\n\n/** Bars on their side: categories down y, values along x. */\nexport function barX<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: BarOptions<TDatum> = {},\n): ChartMark {\n\treturn barMark(\"barX\", data, options);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cell.d.ts","sourceRoot":"","sources":["../../../src/core/marks/cell.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAChC,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,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAKD;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,SAAS,CAqFX"}
1
+ {"version":3,"file":"cell.d.ts","sourceRoot":"","sources":["../../../src/core/marks/cell.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,wBAAwB,CAAC;AAChC,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,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAKD;;;GAGG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAC1B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,SAAS,CAqFX"}
@@ -5,6 +5,7 @@ import {
5
5
  markId,
6
6
  paint,
7
7
  seriesResolver,
8
+ tips,
8
9
  valueOn
9
10
  } from "./shared.js";
10
11
  const DEFAULT_INSET = 1;
@@ -70,7 +71,7 @@ function cell(data, options) {
70
71
  corners: [radius, radius, radius, radius],
71
72
  paint: paint({ fill: series.color, opacity: options.opacity })
72
73
  });
73
- if (options.tip !== false) {
74
+ if (tips(options.tip, datum, index)) {
74
75
  points.push({
75
76
  key: `${id}:${index}`,
76
77
  markId: id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/cell.ts"],
4
- "sourcesContent": ["import { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport { formatValue } from \"#/core/format.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 CellOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\t/** Pixels kept clear around each cell. */\n\treadonly inset?: number;\n\treadonly radius?: number;\n}\n\nconst DEFAULT_INSET = 1;\nconst DEFAULT_RADIUS = 2;\n\n/**\n * A rectangle per (x, y) pair of categories, filled by its color value: a\n * heatmap, a calendar, a matrix.\n */\nexport function cell<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: CellOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x);\n\tconst ys = readChannel(data, options.y);\n\tconst colors = colorChannel(data, options);\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\tdiscrete: \"band\",\n\t\t\t\tpadding: 0,\n\t\t\t\tlabel: channelLabel(options.x),\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: ys.filter(isPlaceable),\n\t\t\t\tdiscrete: \"band\",\n\t\t\t\tpadding: 0,\n\t\t\t\tlabel: channelLabel(options.y),\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, \"cell\", 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 ?? DEFAULT_INSET;\n\t\t\tconst radius = options.radius ?? DEFAULT_RADIUS;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, datum] of data.entries()) {\n\t\t\t\tconst xValue = valueOn(xScale, xs[index]);\n\t\t\t\tconst yValue = valueOn(yScale, ys[index]);\n\t\t\t\tif (xValue === undefined || yValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst rect = {\n\t\t\t\t\tx: xScale.map(xValue) + inset,\n\t\t\t\t\ty: yScale.map(yValue) + inset,\n\t\t\t\t\twidth: Math.max(0, xScale.bandwidth - inset * 2),\n\t\t\t\t\theight: Math.max(0, yScale.bandwidth - inset * 2),\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst colorValue = colors.values[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\trole: \"mark\",\n\t\t\t\t\t...rect,\n\t\t\t\t\tcorners: [radius, radius, radius, radius],\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}:${index}`,\n\t\t\t\t\t\tmarkId: id,\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tdatum,\n\t\t\t\t\t\tx: rect.x + rect.width / 2,\n\t\t\t\t\t\ty: rect.y + rect.height / 2,\n\t\t\t\t\t\txValue,\n\t\t\t\t\t\tyValue,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\tseriesLabel: options.label,\n\t\t\t\t\t\ttitle: `${context.formatX(xValue)} \u00B7 ${context.formatY(yValue)}`,\n\t\t\t\t\t\tvalue:\n\t\t\t\t\t\t\tcolorValue === undefined\n\t\t\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t\t\t: formatValue(colorValue, context.locale),\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 { channelLabel, isPlaceable, readChannel } from \"#/core/channel.ts\";\nimport { formatValue } from \"#/core/format.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 CellOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\treadonly fill?: string;\n\t/** Pixels kept clear around each cell. */\n\treadonly inset?: number;\n\treadonly radius?: number;\n}\n\nconst DEFAULT_INSET = 1;\nconst DEFAULT_RADIUS = 2;\n\n/**\n * A rectangle per (x, y) pair of categories, filled by its color value: a\n * heatmap, a calendar, a matrix.\n */\nexport function cell<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: CellOptions<TDatum>,\n): ChartMark {\n\tconst xs = readChannel(data, options.x);\n\tconst ys = readChannel(data, options.y);\n\tconst colors = colorChannel(data, options);\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\tdiscrete: \"band\",\n\t\t\t\tpadding: 0,\n\t\t\t\tlabel: channelLabel(options.x),\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: ys.filter(isPlaceable),\n\t\t\t\tdiscrete: \"band\",\n\t\t\t\tpadding: 0,\n\t\t\t\tlabel: channelLabel(options.y),\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, \"cell\", 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 ?? DEFAULT_INSET;\n\t\t\tconst radius = options.radius ?? DEFAULT_RADIUS;\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, datum] of data.entries()) {\n\t\t\t\tconst xValue = valueOn(xScale, xs[index]);\n\t\t\t\tconst yValue = valueOn(yScale, ys[index]);\n\t\t\t\tif (xValue === undefined || yValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst rect = {\n\t\t\t\t\tx: xScale.map(xValue) + inset,\n\t\t\t\t\ty: yScale.map(yValue) + inset,\n\t\t\t\t\twidth: Math.max(0, xScale.bandwidth - inset * 2),\n\t\t\t\t\theight: Math.max(0, yScale.bandwidth - inset * 2),\n\t\t\t\t};\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst colorValue = colors.values[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\trole: \"mark\",\n\t\t\t\t\t...rect,\n\t\t\t\t\tcorners: [radius, radius, radius, radius],\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, datum, 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,\n\t\t\t\t\t\tx: rect.x + rect.width / 2,\n\t\t\t\t\t\ty: rect.y + rect.height / 2,\n\t\t\t\t\t\txValue,\n\t\t\t\t\t\tyValue,\n\t\t\t\t\t\tcolor: series.color,\n\t\t\t\t\t\tseriesLabel: options.label,\n\t\t\t\t\t\ttitle: `${context.formatX(xValue)} \u00B7 ${context.formatY(yValue)}`,\n\t\t\t\t\t\tvalue:\n\t\t\t\t\t\t\tcolorValue === undefined\n\t\t\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t\t\t: formatValue(colorValue, context.locale),\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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/core/marks/dot.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAMrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACnE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,4EAA4E;IAC5E,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxD,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAKD,8EAA8E;AAC9E,wBAAgB,GAAG,CAAC,MAAM,EACzB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAkHX"}
1
+ {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/core/marks/dot.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,aAAa,EACb,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,UAAU,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACnE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,4EAA4E;IAC5E,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxD,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAKD,8EAA8E;AAC9E,wBAAgB,GAAG,CAAC,MAAM,EACzB,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,UAAU,CAAC,MAAM,CAAM,GAC9B,SAAS,CAkHX"}
@@ -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
  const DEFAULT_RADIUS = 4;
@@ -93,7 +94,7 @@ function dot(data, options = {}) {
93
94
  opacity: options.opacity
94
95
  })
95
96
  });
96
- if (options.tip !== false) {
97
+ if (tips(options.tip, datum, index)) {
97
98
  points.push({
98
99
  key: `${id}:${index}`,
99
100
  markId: id,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/dot.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 type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface DotOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** A radius in pixels, or a field whose values set the area of each dot. */\n\treadonly r?: number | ChartAccessor<TDatum, ChartValue>;\n\t/** The largest radius a sized dot reaches. */\n\treadonly maxRadius?: number;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\treadonly stroke?: string;\n\treadonly strokeWidth?: number;\n}\n\nconst DEFAULT_RADIUS = 4;\nconst DEFAULT_MAX_RADIUS = 16;\n\n/** A dot per datum: a scatter plot, or a bubble chart when `r` is a field. */\nexport function dot<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: DotOptions<TDatum> = {},\n): ChartMark {\n\tconst xs = readChannel(\n\t\tdata,\n\t\toptions.x ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst ys = readChannel(\n\t\tdata,\n\t\toptions.y ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t);\n\tconst colors = colorChannel(data, options);\n\tconst sized = options.r !== undefined && typeof options.r !== \"number\";\n\tconst sizes = sized\n\t\t? readChannel(data, options.r as ChartAccessor<TDatum, ChartValue>).map(\n\t\t\t\tnumericValue,\n\t\t\t)\n\t\t: [];\n\tconst largest = Math.max(0, ...sizes.map((size) => Math.abs(size ?? 0)));\n\tconst reach =\n\t\ttypeof options.r === \"number\"\n\t\t\t? options.r\n\t\t\t: sized\n\t\t\t\t? (options.maxRadius ?? DEFAULT_MAX_RADIUS)\n\t\t\t\t: DEFAULT_RADIUS;\n\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),\n\t\t\t\tinset: reach,\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: ys.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.y) ?? options.label,\n\t\t\t\tinset: reach,\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, \"dot\", 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 maxRadius = options.maxRadius ?? DEFAULT_MAX_RADIUS;\n\t\t\t// Area, not radius, carries the value: a dot twice the value looks twice as big.\n\t\t\tfunction radiusOf(index: number): number {\n\t\t\t\tif (typeof options.r === \"number\") return options.r;\n\t\t\t\tif (!sized) return DEFAULT_RADIUS;\n\t\t\t\tconst size = Math.abs(sizes[index] ?? 0);\n\t\t\t\treturn largest === 0 ? 0 : Math.sqrt(size / largest) * maxRadius;\n\t\t\t}\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, datum] of data.entries()) {\n\t\t\t\tconst xValue = valueOn(xScale, xs[index]);\n\t\t\t\tconst yValue = valueOn(yScale, ys[index]);\n\t\t\t\tif (xValue === undefined || yValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst cx = xScale.center(xValue);\n\t\t\t\tconst cy = yScale.center(yValue);\n\t\t\t\tconst r = radiusOf(index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"circle\",\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\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tr,\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\tstroke: options.stroke,\n\t\t\t\t\t\tstrokeWidth: options.strokeWidth,\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,\n\t\t\t\t\t\tx: cx,\n\t\t\t\t\t\ty: cy,\n\t\t\t\t\t\txValue,\n\t\t\t\t\t\tyValue,\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(xValue),\n\t\t\t\t\t\tvalue: context.formatY(yValue),\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: cx - r, y: cy - 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 {\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 type {\n\tChartAccessor,\n\tChartMark,\n\tChartPoint,\n\tChartValue,\n\tSceneNode,\n} from \"#/core/types.ts\";\n\nexport interface DotOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\treadonly x?: ChartAccessor<TDatum, ChartValue>;\n\treadonly y?: ChartAccessor<TDatum, ChartValue>;\n\t/** A radius in pixels, or a field whose values set the area of each dot. */\n\treadonly r?: number | ChartAccessor<TDatum, ChartValue>;\n\t/** The largest radius a sized dot reaches. */\n\treadonly maxRadius?: number;\n\treadonly fill?: string;\n\treadonly fillOpacity?: number;\n\treadonly stroke?: string;\n\treadonly strokeWidth?: number;\n}\n\nconst DEFAULT_RADIUS = 4;\nconst DEFAULT_MAX_RADIUS = 16;\n\n/** A dot per datum: a scatter plot, or a bubble chart when `r` is a field. */\nexport function dot<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: DotOptions<TDatum> = {},\n): ChartMark {\n\tconst xs = readChannel(\n\t\tdata,\n\t\toptions.x ?? ((_datum: TDatum, index: number) => index),\n\t);\n\tconst ys = readChannel(\n\t\tdata,\n\t\toptions.y ?? ((datum: TDatum) => datum as unknown as ChartValue),\n\t);\n\tconst colors = colorChannel(data, options);\n\tconst sized = options.r !== undefined && typeof options.r !== \"number\";\n\tconst sizes = sized\n\t\t? readChannel(data, options.r as ChartAccessor<TDatum, ChartValue>).map(\n\t\t\t\tnumericValue,\n\t\t\t)\n\t\t: [];\n\tconst largest = Math.max(0, ...sizes.map((size) => Math.abs(size ?? 0)));\n\tconst reach =\n\t\ttypeof options.r === \"number\"\n\t\t\t? options.r\n\t\t\t: sized\n\t\t\t\t? (options.maxRadius ?? DEFAULT_MAX_RADIUS)\n\t\t\t\t: DEFAULT_RADIUS;\n\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),\n\t\t\t\tinset: reach,\n\t\t\t},\n\t\t\ty: {\n\t\t\t\tvalues: ys.filter(isPlaceable),\n\t\t\t\tlabel: channelLabel(options.y) ?? options.label,\n\t\t\t\tinset: reach,\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, \"dot\", 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 maxRadius = options.maxRadius ?? DEFAULT_MAX_RADIUS;\n\t\t\t// Area, not radius, carries the value: a dot twice the value looks twice as big.\n\t\t\tfunction radiusOf(index: number): number {\n\t\t\t\tif (typeof options.r === \"number\") return options.r;\n\t\t\t\tif (!sized) return DEFAULT_RADIUS;\n\t\t\t\tconst size = Math.abs(sizes[index] ?? 0);\n\t\t\t\treturn largest === 0 ? 0 : Math.sqrt(size / largest) * maxRadius;\n\t\t\t}\n\t\t\tconst nodes: SceneNode[] = [];\n\t\t\tconst points: ChartPoint[] = [];\n\t\t\tfor (const [index, datum] of data.entries()) {\n\t\t\t\tconst xValue = valueOn(xScale, xs[index]);\n\t\t\t\tconst yValue = valueOn(yScale, ys[index]);\n\t\t\t\tif (xValue === undefined || yValue === undefined) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(index);\n\t\t\t\tconst cx = xScale.center(xValue);\n\t\t\t\tconst cy = yScale.center(yValue);\n\t\t\t\tconst r = radiusOf(index);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"circle\",\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\tcx,\n\t\t\t\t\tcy,\n\t\t\t\t\tr,\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\tstroke: options.stroke,\n\t\t\t\t\t\tstrokeWidth: options.strokeWidth,\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, datum, 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,\n\t\t\t\t\t\tx: cx,\n\t\t\t\t\t\ty: cy,\n\t\t\t\t\t\txValue,\n\t\t\t\t\t\tyValue,\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(xValue),\n\t\t\t\t\t\tvalue: context.formatY(yValue),\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: cx - r, y: cy - 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": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"funnel.d.ts","sourceRoot":"","sources":["../../../src/core/marks/funnel.ts"],"names":[],"mappings":"AAQA,OAAO,EACN,KAAK,gBAAgB,EAIrB,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,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,yCAAyC;IACzC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B;AAKD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAC5B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,SAAS,CA8HX"}
1
+ {"version":3,"file":"funnel.d.ts","sourceRoot":"","sources":["../../../src/core/marks/funnel.ts"],"names":[],"mappings":"AAQA,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,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClD,yCAAyC;IACzC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B;AAKD;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAC5B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,GAC5B,SAAS,CA8HX"}
@@ -9,7 +9,8 @@ import { funnelSlices } from "./funnel-layout.js";
9
9
  import {
10
10
  markId,
11
11
  paint,
12
- seriesResolver
12
+ seriesResolver,
13
+ tips
13
14
  } from "./shared.js";
14
15
  import { categoryKey } from "../scales/discrete.js";
15
16
  const LABEL_ZONE = 36;
@@ -103,7 +104,7 @@ function funnel(data, options) {
103
104
  }
104
105
  );
105
106
  }
106
- if (options.tip === false) {
107
+ if (!tips(options.tip, data[slice.index], slice.index)) {
107
108
  continue;
108
109
  }
109
110
  const previous = slice.index > 0 ? values[slice.index - 1] : void 0;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/core/marks/funnel.ts"],
4
- "sourcesContent": ["import {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { formatPercentage } from \"#/core/format.ts\";\nimport { funnelSlices } from \"#/core/marks/funnel-layout.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n} from \"#/core/marks/shared.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 FunnelOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** The step: \"Visites\", \"Inscriptions\", \"Missions\". */\n\treadonly category: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** Pixels of blank between two steps. */\n\treadonly gap?: number;\n\treadonly fill?: string;\n\t/** `false` drops the step name and value written above each step. */\n\treadonly labels?: boolean;\n}\n\n/** Room kept above the shape for each step's name and value. */\nconst LABEL_ZONE = 36;\n\n/**\n * Steps left to right, each as tall as its value, each sloping down to the\n * next: the drop between two stages is the shape itself. The tooltip gives\n * the conversion from the step before.\n */\nexport function funnel<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: FunnelOptions<TDatum>,\n): ChartMark {\n\tconst categories = readChannel(data, options.category);\n\tconst values = readChannel(data, options.value).map(\n\t\t(value) => numericValue(value) ?? 0,\n\t);\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\tfocusOrder: \"point\",\n\t\tcolorLegend: options.labels === false,\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, \"funnel\", context);\n\t\t\tconst { plot, theme } = context;\n\t\t\tconst labelled = options.labels !== false;\n\t\t\tconst top = plot.y + (labelled ? LABEL_ZONE : 0);\n\t\t\tconst height = Math.max(0, plot.height - (labelled ? LABEL_ZONE : 0));\n\t\t\tconst slices = funnelSlices({\n\t\t\t\tvalues,\n\t\t\t\tinnerWidth: plot.width,\n\t\t\t\tinnerHeight: height,\n\t\t\t\tcenterY: top + height / 2,\n\t\t\t\toriginX: plot.x,\n\t\t\t\tgap: options.gap,\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 slice of slices) {\n\t\t\t\tconst category = categories[slice.index];\n\t\t\t\tif (!isPlaceable(category) || slice.path === \"\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(slice.index);\n\t\t\t\tconst key = categoryKey(category);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:${key}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: slice.path,\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (labelled) {\n\t\t\t\t\tnodes.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\t\tkey: `${id}:name:${key}`,\n\t\t\t\t\t\t\trole: \"label\",\n\t\t\t\t\t\t\tx: slice.x,\n\t\t\t\t\t\t\ty: plot.y,\n\t\t\t\t\t\t\ttext: series.label ?? context.formatX(category),\n\t\t\t\t\t\t\tpaint: {\n\t\t\t\t\t\t\t\tfill: theme.muted,\n\t\t\t\t\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\t\t\t\t\tbaseline: \"top\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\t\tkey: `${id}:value:${key}`,\n\t\t\t\t\t\t\trole: \"label\",\n\t\t\t\t\t\t\tx: slice.x,\n\t\t\t\t\t\t\ty: plot.y + theme.fontSize + 4,\n\t\t\t\t\t\t\ttext: context.formatY(slice.value),\n\t\t\t\t\t\t\tpaint: {\n\t\t\t\t\t\t\t\tfill: theme.foreground,\n\t\t\t\t\t\t\t\tfontSize: theme.fontSize + 2,\n\t\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\t\tbaseline: \"top\",\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\tif (options.tip === false) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst previous = slice.index > 0 ? values[slice.index - 1] : undefined;\n\t\t\t\tconst conversion =\n\t\t\t\t\tprevious !== undefined && previous > 0\n\t\t\t\t\t\t? ` (${formatPercentage(slice.value / previous, context.locale)})`\n\t\t\t\t\t\t: \"\";\n\t\t\t\tconst centerY = top + height / 2;\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${key}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex: slice.index,\n\t\t\t\t\tdatum: data[slice.index],\n\t\t\t\t\tx: slice.x + slice.width / 2,\n\t\t\t\t\ty: centerY,\n\t\t\t\t\txValue: category,\n\t\t\t\t\tyValue: slice.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(slice.value)}${conversion}`,\n\t\t\t\t\thit: {\n\t\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\t\trect: {\n\t\t\t\t\t\t\tx: slice.x,\n\t\t\t\t\t\t\ty: centerY - slice.leftHeight / 2,\n\t\t\t\t\t\t\twidth: slice.width,\n\t\t\t\t\t\t\theight: slice.leftHeight,\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 {\n\tchannelLabel,\n\tisPlaceable,\n\tnumericValue,\n\treadChannel,\n} from \"#/core/channel.ts\";\nimport { formatPercentage } from \"#/core/format.ts\";\nimport { funnelSlices } from \"#/core/marks/funnel-layout.ts\";\nimport {\n\ttype ChartMarkOptions,\n\tmarkId,\n\tpaint,\n\tseriesResolver,\n\ttips,\n} from \"#/core/marks/shared.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 FunnelOptions<TDatum> extends ChartMarkOptions<TDatum> {\n\t/** The step: \"Visites\", \"Inscriptions\", \"Missions\". */\n\treadonly category: ChartAccessor<TDatum, ChartValue>;\n\treadonly value: ChartAccessor<TDatum, ChartValue>;\n\t/** Pixels of blank between two steps. */\n\treadonly gap?: number;\n\treadonly fill?: string;\n\t/** `false` drops the step name and value written above each step. */\n\treadonly labels?: boolean;\n}\n\n/** Room kept above the shape for each step's name and value. */\nconst LABEL_ZONE = 36;\n\n/**\n * Steps left to right, each as tall as its value, each sloping down to the\n * next: the drop between two stages is the shape itself. The tooltip gives\n * the conversion from the step before.\n */\nexport function funnel<TDatum>(\n\tdata: ReadonlyArray<TDatum>,\n\toptions: FunnelOptions<TDatum>,\n): ChartMark {\n\tconst categories = readChannel(data, options.category);\n\tconst values = readChannel(data, options.value).map(\n\t\t(value) => numericValue(value) ?? 0,\n\t);\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\tfocusOrder: \"point\",\n\t\tcolorLegend: options.labels === false,\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, \"funnel\", context);\n\t\t\tconst { plot, theme } = context;\n\t\t\tconst labelled = options.labels !== false;\n\t\t\tconst top = plot.y + (labelled ? LABEL_ZONE : 0);\n\t\t\tconst height = Math.max(0, plot.height - (labelled ? LABEL_ZONE : 0));\n\t\t\tconst slices = funnelSlices({\n\t\t\t\tvalues,\n\t\t\t\tinnerWidth: plot.width,\n\t\t\t\tinnerHeight: height,\n\t\t\t\tcenterY: top + height / 2,\n\t\t\t\toriginX: plot.x,\n\t\t\t\tgap: options.gap,\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 slice of slices) {\n\t\t\t\tconst category = categories[slice.index];\n\t\t\t\tif (!isPlaceable(category) || slice.path === \"\") {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst series = seriesOf(slice.index);\n\t\t\t\tconst key = categoryKey(category);\n\t\t\t\tnodes.push({\n\t\t\t\t\tkind: \"path\",\n\t\t\t\t\tkey: `${id}:${key}`,\n\t\t\t\t\tseries: series.key,\n\t\t\t\t\trole: \"mark\",\n\t\t\t\t\td: slice.path,\n\t\t\t\t\tpaint: paint({ fill: series.color, opacity: options.opacity }),\n\t\t\t\t});\n\t\t\t\tif (labelled) {\n\t\t\t\t\tnodes.push(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\t\tkey: `${id}:name:${key}`,\n\t\t\t\t\t\t\trole: \"label\",\n\t\t\t\t\t\t\tx: slice.x,\n\t\t\t\t\t\t\ty: plot.y,\n\t\t\t\t\t\t\ttext: series.label ?? context.formatX(category),\n\t\t\t\t\t\t\tpaint: {\n\t\t\t\t\t\t\t\tfill: theme.muted,\n\t\t\t\t\t\t\t\tfontSize: theme.fontSize,\n\t\t\t\t\t\t\t\tbaseline: \"top\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkind: \"text\",\n\t\t\t\t\t\t\tkey: `${id}:value:${key}`,\n\t\t\t\t\t\t\trole: \"label\",\n\t\t\t\t\t\t\tx: slice.x,\n\t\t\t\t\t\t\ty: plot.y + theme.fontSize + 4,\n\t\t\t\t\t\t\ttext: context.formatY(slice.value),\n\t\t\t\t\t\t\tpaint: {\n\t\t\t\t\t\t\t\tfill: theme.foreground,\n\t\t\t\t\t\t\t\tfontSize: theme.fontSize + 2,\n\t\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\t\tbaseline: \"top\",\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\tif (!tips(options.tip, data[slice.index], slice.index)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst previous = slice.index > 0 ? values[slice.index - 1] : undefined;\n\t\t\t\tconst conversion =\n\t\t\t\t\tprevious !== undefined && previous > 0\n\t\t\t\t\t\t? ` (${formatPercentage(slice.value / previous, context.locale)})`\n\t\t\t\t\t\t: \"\";\n\t\t\t\tconst centerY = top + height / 2;\n\t\t\t\tpoints.push({\n\t\t\t\t\tkey: `${id}:${key}`,\n\t\t\t\t\tmarkId: id,\n\t\t\t\t\tindex: slice.index,\n\t\t\t\t\tdatum: data[slice.index],\n\t\t\t\t\tx: slice.x + slice.width / 2,\n\t\t\t\t\ty: centerY,\n\t\t\t\t\txValue: category,\n\t\t\t\t\tyValue: slice.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(slice.value)}${conversion}`,\n\t\t\t\t\thit: {\n\t\t\t\t\t\tkind: \"rect\",\n\t\t\t\t\t\trect: {\n\t\t\t\t\t\t\tx: slice.x,\n\t\t\t\t\t\t\ty: centerY - slice.leftHeight / 2,\n\t\t\t\t\t\t\twidth: slice.width,\n\t\t\t\t\t\t\theight: slice.leftHeight,\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": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../../src/core/marks/line.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,gBAAgB,EAOrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EACX,aAAa,EACb,UAAU,EACV,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAkKD,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX;AAED,yDAAyD;AACzD,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX"}
1
+ {"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../../src/core/marks/line.ts"],"names":[],"mappings":"AACA,OAAO,EACN,KAAK,gBAAgB,EAQrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EACX,aAAa,EACb,UAAU,EACV,SAAS,EAET,UAAU,EAEV,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW,CAAC,MAAM,CAAE,SAAQ,gBAAgB,CAAC,MAAM,CAAC;IACpE,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAkKD,8EAA8E;AAC9E,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX;AAED,yDAAyD;AACzD,wBAAgB,KAAK,CAAC,MAAM,EAC3B,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAC3B,OAAO,GAAE,WAAW,CAAC,MAAM,CAAM,GAC/B,SAAS,CAEX"}
@@ -5,6 +5,7 @@ import {
5
5
  markId,
6
6
  paint,
7
7
  seriesResolver,
8
+ tips,
8
9
  valueOn
9
10
  } from "./shared.js";
10
11
  import { linePath } from "../paths.js";
@@ -72,7 +73,7 @@ function lineMark(kind, data, options) {
72
73
  const across = valueScale.center(value);
73
74
  const xy = vertical ? { x: along, y: across } : { x: across, y: along };
74
75
  runs[runs.length - 1].push(xy);
75
- if (options.tip !== false) {
76
+ if (tips(options.tip, data[index], index)) {
76
77
  points.push({
77
78
  key: `${id}:${index}`,
78
79
  markId: id,