graphein 0.20.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation/animate.d.ts +6 -1
- package/dist/animation/animate.d.ts.map +1 -1
- package/dist/animation/animate.js +2 -2
- package/dist/animation/animate.js.map +2 -2
- package/dist/animation/env.d.ts +5 -0
- package/dist/animation/env.d.ts.map +1 -1
- package/dist/animation/env.js +4 -0
- package/dist/animation/env.js.map +2 -2
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.d.ts.map +1 -1
- package/dist/animation/index.js +1 -0
- package/dist/animation/index.js.map +2 -2
- package/dist/animation/stagger.d.ts +13 -0
- package/dist/animation/stagger.d.ts.map +1 -0
- package/dist/animation/stagger.js +13 -0
- package/dist/animation/stagger.js.map +7 -0
- package/dist/axes/draw.d.ts +5 -1
- package/dist/axes/draw.d.ts.map +1 -1
- package/dist/axes/draw.js +13 -1
- package/dist/axes/draw.js.map +2 -2
- package/dist/axes/morph.d.ts +111 -0
- package/dist/axes/morph.d.ts.map +1 -0
- package/dist/axes/morph.js +207 -0
- package/dist/axes/morph.js.map +7 -0
- package/dist/axes/overlay.d.ts.map +1 -1
- package/dist/axes/overlay.js +88 -25
- package/dist/axes/overlay.js.map +2 -2
- package/dist/axes/text.d.ts +2 -0
- package/dist/axes/text.d.ts.map +1 -1
- package/dist/axes/text.js +1 -0
- package/dist/axes/text.js.map +2 -2
- package/dist/axes/tickLabels.d.ts +2 -0
- package/dist/axes/tickLabels.d.ts.map +1 -1
- package/dist/axes/tickLabels.js +2 -2
- package/dist/axes/tickLabels.js.map +2 -2
- package/dist/charts/annotations.d.ts +9 -3
- package/dist/charts/annotations.d.ts.map +1 -1
- package/dist/charts/annotations.js +82 -27
- package/dist/charts/annotations.js.map +2 -2
- package/dist/charts/area.d.ts +37 -1
- package/dist/charts/area.d.ts.map +1 -1
- package/dist/charts/area.js +35 -17
- package/dist/charts/area.js.map +2 -2
- package/dist/charts/bar.d.ts +53 -0
- package/dist/charts/bar.d.ts.map +1 -1
- package/dist/charts/bar.js +117 -83
- package/dist/charts/bar.js.map +2 -2
- package/dist/charts/box.d.ts +31 -0
- package/dist/charts/box.d.ts.map +1 -1
- package/dist/charts/box.js +93 -70
- package/dist/charts/box.js.map +2 -2
- package/dist/charts/bubbleMap.d.ts +20 -0
- package/dist/charts/bubbleMap.d.ts.map +1 -0
- package/dist/charts/bubbleMap.js +951 -0
- package/dist/charts/bubbleMap.js.map +7 -0
- package/dist/charts/bullet.d.ts.map +1 -1
- package/dist/charts/bullet.js +69 -51
- package/dist/charts/bullet.js.map +2 -2
- package/dist/charts/calendarHeatmap.d.ts.map +1 -1
- package/dist/charts/calendarHeatmap.js +56 -19
- package/dist/charts/calendarHeatmap.js.map +2 -2
- package/dist/charts/candlestick.d.ts +40 -0
- package/dist/charts/candlestick.d.ts.map +1 -0
- package/dist/charts/candlestick.js +325 -0
- package/dist/charts/candlestick.js.map +7 -0
- package/dist/charts/choropleth.d.ts.map +1 -1
- package/dist/charts/choropleth.js +46 -67
- package/dist/charts/choropleth.js.map +2 -2
- package/dist/charts/combo.d.ts.map +1 -1
- package/dist/charts/combo.js +127 -27
- package/dist/charts/combo.js.map +3 -3
- package/dist/charts/dumbbell.d.ts.map +1 -1
- package/dist/charts/dumbbell.js +100 -31
- package/dist/charts/dumbbell.js.map +2 -2
- package/dist/charts/funnel.d.ts.map +1 -1
- package/dist/charts/funnel.js +93 -28
- package/dist/charts/funnel.js.map +3 -3
- package/dist/charts/gantt.d.ts +22 -0
- package/dist/charts/gantt.d.ts.map +1 -0
- package/dist/charts/gantt.js +564 -0
- package/dist/charts/gantt.js.map +7 -0
- package/dist/charts/gauge.d.ts.map +1 -1
- package/dist/charts/gauge.js +30 -4
- package/dist/charts/gauge.js.map +2 -2
- package/dist/charts/geo.d.ts +87 -0
- package/dist/charts/geo.d.ts.map +1 -0
- package/dist/charts/geo.js +140 -0
- package/dist/charts/geo.js.map +7 -0
- package/dist/charts/geometry.d.ts +20 -0
- package/dist/charts/geometry.d.ts.map +1 -0
- package/dist/charts/geometry.js +25 -0
- package/dist/charts/geometry.js.map +7 -0
- package/dist/charts/heatmap.d.ts.map +1 -1
- package/dist/charts/heatmap.js +58 -49
- package/dist/charts/heatmap.js.map +2 -2
- package/dist/charts/histogram.d.ts +1 -1
- package/dist/charts/histogram.d.ts.map +1 -1
- package/dist/charts/histogram.js +49 -31
- package/dist/charts/histogram.js.map +2 -2
- package/dist/charts/index.d.ts +35 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +12 -0
- package/dist/charts/index.js.map +2 -2
- package/dist/charts/legibility.d.ts +38 -0
- package/dist/charts/legibility.d.ts.map +1 -0
- package/dist/charts/legibility.js +72 -0
- package/dist/charts/legibility.js.map +7 -0
- package/dist/charts/line.d.ts +39 -1
- package/dist/charts/line.d.ts.map +1 -1
- package/dist/charts/line.js +48 -16
- package/dist/charts/line.js.map +2 -2
- package/dist/charts/matrix.d.ts +2 -1
- package/dist/charts/matrix.d.ts.map +1 -1
- package/dist/charts/matrix.js +481 -319
- package/dist/charts/matrix.js.map +3 -3
- package/dist/charts/morphFrame.d.ts +83 -0
- package/dist/charts/morphFrame.d.ts.map +1 -0
- package/dist/charts/morphFrame.js +128 -0
- package/dist/charts/morphFrame.js.map +7 -0
- package/dist/charts/pie.d.ts.map +1 -1
- package/dist/charts/pie.js +89 -26
- package/dist/charts/pie.js.map +2 -2
- package/dist/charts/pieState.d.ts +27 -0
- package/dist/charts/pieState.d.ts.map +1 -0
- package/dist/charts/pieState.js +55 -0
- package/dist/charts/pieState.js.map +7 -0
- package/dist/charts/radar.d.ts +62 -0
- package/dist/charts/radar.d.ts.map +1 -0
- package/dist/charts/radar.js +912 -0
- package/dist/charts/radar.js.map +7 -0
- package/dist/charts/radialBar.d.ts +60 -0
- package/dist/charts/radialBar.d.ts.map +1 -0
- package/dist/charts/radialBar.js +708 -0
- package/dist/charts/radialBar.js.map +7 -0
- package/dist/charts/sankey.d.ts.map +1 -1
- package/dist/charts/sankey.js +223 -57
- package/dist/charts/sankey.js.map +3 -3
- package/dist/charts/scatter.d.ts +31 -0
- package/dist/charts/scatter.d.ts.map +1 -1
- package/dist/charts/scatter.js +48 -12
- package/dist/charts/scatter.js.map +2 -2
- package/dist/charts/slope.d.ts.map +1 -1
- package/dist/charts/slope.js +55 -3
- package/dist/charts/slope.js.map +2 -2
- package/dist/charts/sunburst.d.ts +14 -0
- package/dist/charts/sunburst.d.ts.map +1 -0
- package/dist/charts/sunburst.js +885 -0
- package/dist/charts/sunburst.js.map +7 -0
- package/dist/charts/table.d.ts +2 -1
- package/dist/charts/table.d.ts.map +1 -1
- package/dist/charts/table.js +214 -224
- package/dist/charts/table.js.map +3 -3
- package/dist/charts/tableView/canvas.d.ts +16 -1
- package/dist/charts/tableView/canvas.d.ts.map +1 -1
- package/dist/charts/tableView/canvas.js +361 -252
- package/dist/charts/tableView/canvas.js.map +3 -3
- package/dist/charts/tableView/conditional.d.ts +66 -40
- package/dist/charts/tableView/conditional.d.ts.map +1 -1
- package/dist/charts/tableView/conditional.js +163 -256
- package/dist/charts/tableView/conditional.js.map +3 -3
- package/dist/charts/tableView/dom.d.ts +26 -2
- package/dist/charts/tableView/dom.d.ts.map +1 -1
- package/dist/charts/tableView/dom.js +609 -269
- package/dist/charts/tableView/dom.js.map +3 -3
- package/dist/charts/tableView/layout.d.ts +22 -0
- package/dist/charts/tableView/layout.d.ts.map +1 -0
- package/dist/charts/tableView/layout.js +246 -0
- package/dist/charts/tableView/layout.js.map +7 -0
- package/dist/charts/tableView/sketch.d.ts +3 -2
- package/dist/charts/tableView/sketch.d.ts.map +1 -1
- package/dist/charts/tableView/sketch.js +2 -2
- package/dist/charts/tableView/sketch.js.map +2 -2
- package/dist/charts/tableView/sketchBar.d.ts +7 -0
- package/dist/charts/tableView/sketchBar.d.ts.map +1 -0
- package/dist/charts/tableView/sketchBar.js +32 -0
- package/dist/charts/tableView/sketchBar.js.map +7 -0
- package/dist/charts/tableView/sort.d.ts +9 -0
- package/dist/charts/tableView/sort.d.ts.map +1 -0
- package/dist/charts/tableView/sort.js +70 -0
- package/dist/charts/tableView/sort.js.map +7 -0
- package/dist/charts/tableView/sparkline.d.ts +30 -0
- package/dist/charts/tableView/sparkline.d.ts.map +1 -0
- package/dist/charts/tableView/sparkline.js +63 -0
- package/dist/charts/tableView/sparkline.js.map +7 -0
- package/dist/charts/tableView/style.d.ts +67 -0
- package/dist/charts/tableView/style.d.ts.map +1 -0
- package/dist/charts/tableView/style.js +131 -0
- package/dist/charts/tableView/style.js.map +7 -0
- package/dist/charts/tableView/types.d.ts +69 -46
- package/dist/charts/tableView/types.d.ts.map +1 -1
- package/dist/charts/tableView/types.js +22 -87
- package/dist/charts/tableView/types.js.map +2 -2
- package/dist/charts/tableView.d.ts +10 -5
- package/dist/charts/tableView.d.ts.map +1 -1
- package/dist/charts/tableView.js +12 -8
- package/dist/charts/tableView.js.map +2 -2
- package/dist/charts/treemap.d.ts.map +1 -1
- package/dist/charts/treemap.js +177 -68
- package/dist/charts/treemap.js.map +3 -3
- package/dist/charts/trendline.d.ts +13 -5
- package/dist/charts/trendline.d.ts.map +1 -1
- package/dist/charts/trendline.js +205 -56
- package/dist/charts/trendline.js.map +2 -2
- package/dist/charts/waterfall.d.ts.map +1 -1
- package/dist/charts/waterfall.js +76 -5
- package/dist/charts/waterfall.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interaction/cartesian.d.ts +4 -1
- package/dist/interaction/cartesian.d.ts.map +1 -1
- package/dist/interaction/cartesian.js +104 -34
- package/dist/interaction/cartesian.js.map +2 -2
- package/dist/interaction/controller.d.ts +29 -1
- package/dist/interaction/controller.d.ts.map +1 -1
- package/dist/interaction/controller.js +131 -8
- package/dist/interaction/controller.js.map +2 -2
- package/dist/interaction/focus.d.ts +23 -0
- package/dist/interaction/focus.d.ts.map +1 -0
- package/dist/interaction/focus.js +65 -0
- package/dist/interaction/focus.js.map +7 -0
- package/dist/interaction/tooltip.d.ts +6 -0
- package/dist/interaction/tooltip.d.ts.map +1 -1
- package/dist/interaction/tooltip.js +41 -16
- package/dist/interaction/tooltip.js.map +2 -2
- package/dist/interaction/types.d.ts +19 -0
- package/dist/interaction/types.d.ts.map +1 -1
- package/dist/interaction/veil.d.ts +25 -0
- package/dist/interaction/veil.d.ts.map +1 -0
- package/dist/interaction/veil.js +35 -0
- package/dist/interaction/veil.js.map +7 -0
- package/dist/pivot/pivot.d.ts +18 -0
- package/dist/pivot/pivot.d.ts.map +1 -1
- package/dist/pivot/pivot.js +46 -34
- package/dist/pivot/pivot.js.map +2 -2
- package/dist/render/chromeMotion.d.ts +65 -0
- package/dist/render/chromeMotion.d.ts.map +1 -0
- package/dist/render/chromeMotion.js +79 -0
- package/dist/render/chromeMotion.js.map +7 -0
- package/dist/render/pathSample.d.ts +24 -0
- package/dist/render/pathSample.d.ts.map +1 -0
- package/dist/render/pathSample.js +76 -0
- package/dist/render/pathSample.js.map +7 -0
- package/dist/render/transient.d.ts +18 -0
- package/dist/render/transient.d.ts.map +1 -0
- package/dist/render/transient.js +19 -0
- package/dist/render/transient.js.map +7 -0
- package/dist/runtime/candlestick.d.ts +112 -0
- package/dist/runtime/candlestick.d.ts.map +1 -0
- package/dist/runtime/candlestick.js +531 -0
- package/dist/runtime/candlestick.js.map +7 -0
- package/dist/runtime/cartesian.d.ts +14 -3
- package/dist/runtime/cartesian.d.ts.map +1 -1
- package/dist/runtime/cartesian.js.map +2 -2
- package/dist/runtime/chartAnimation.d.ts +54 -7
- package/dist/runtime/chartAnimation.d.ts.map +1 -1
- package/dist/runtime/chartAnimation.js +146 -28
- package/dist/runtime/chartAnimation.js.map +2 -2
- package/dist/runtime/chartRuntime.d.ts +42 -0
- package/dist/runtime/chartRuntime.d.ts.map +1 -1
- package/dist/runtime/chartRuntime.js +196 -30
- package/dist/runtime/chartRuntime.js.map +2 -2
- package/dist/runtime/dashboardDom.d.ts.map +1 -1
- package/dist/runtime/dashboardDom.js +45 -0
- package/dist/runtime/dashboardDom.js.map +2 -2
- package/dist/runtime/facet.d.ts +1 -1
- package/dist/runtime/facet.d.ts.map +1 -1
- package/dist/runtime/gantt.d.ts +137 -0
- package/dist/runtime/gantt.d.ts.map +1 -0
- package/dist/runtime/gantt.js +647 -0
- package/dist/runtime/gantt.js.map +7 -0
- package/dist/runtime/morph.d.ts +33 -0
- package/dist/runtime/morph.d.ts.map +1 -0
- package/dist/runtime/morph.js +332 -0
- package/dist/runtime/morph.js.map +7 -0
- package/dist/runtime/radar.d.ts +75 -0
- package/dist/runtime/radar.d.ts.map +1 -0
- package/dist/runtime/radar.js +201 -0
- package/dist/runtime/radar.js.map +7 -0
- package/dist/runtime/radialBar.d.ts +81 -0
- package/dist/runtime/radialBar.d.ts.map +1 -0
- package/dist/runtime/radialBar.js +125 -0
- package/dist/runtime/radialBar.js.map +7 -0
- package/dist/runtime/report/constants.d.ts +2 -2
- package/dist/runtime/report/constants.d.ts.map +1 -1
- package/dist/runtime/runtimeShared.d.ts +3 -3
- package/dist/runtime/runtimeShared.d.ts.map +1 -1
- package/dist/runtime/sunburst.d.ts +74 -0
- package/dist/runtime/sunburst.d.ts.map +1 -0
- package/dist/runtime/sunburst.js +150 -0
- package/dist/runtime/sunburst.js.map +7 -0
- package/dist/runtime/wire.d.ts.map +1 -1
- package/dist/runtime/wire.js +3 -1
- package/dist/runtime/wire.js.map +2 -2
- package/dist/shape/arc.d.ts +15 -2
- package/dist/shape/arc.d.ts.map +1 -1
- package/dist/shape/arc.js +204 -32
- package/dist/shape/arc.js.map +2 -2
- package/dist/spec/chartDefinitions.d.ts +6 -0
- package/dist/spec/chartDefinitions.d.ts.map +1 -1
- package/dist/spec/chartDefinitions.js +7 -1
- package/dist/spec/chartDefinitions.js.map +2 -2
- package/dist/spec/templates.d.ts.map +1 -1
- package/dist/spec/templates.js +177 -2
- package/dist/spec/templates.js.map +2 -2
- package/dist/spec/types.d.ts +258 -6
- package/dist/spec/types.d.ts.map +1 -1
- package/dist/spec/types.js +6 -0
- package/dist/spec/types.js.map +2 -2
- package/dist/spec/validate/charts.js +147 -15
- package/dist/spec/validate/charts.js.map +2 -2
- package/dist/spec/validate/common.d.ts +6 -0
- package/dist/spec/validate/common.d.ts.map +1 -1
- package/dist/spec/validate/overlays.js +2 -2
- package/dist/spec/validate/overlays.js.map +2 -2
- package/dist/spec/validate.data.d.ts.map +1 -1
- package/dist/spec/validate.data.js +8 -3
- package/dist/spec/validate.data.js.map +2 -2
- package/package.json +1 -1
package/dist/charts/box.js
CHANGED
|
@@ -87,82 +87,76 @@ function computeBoxes(model) {
|
|
|
87
87
|
});
|
|
88
88
|
return geoms.length ? { geoms, showOutliers } : null;
|
|
89
89
|
}
|
|
90
|
-
function drawBoxWhiskers(ctx,
|
|
90
|
+
function drawBoxWhiskers(ctx, mark, top, bottom, capHalf) {
|
|
91
91
|
ctx.beginPath();
|
|
92
|
-
ctx.moveTo(
|
|
93
|
-
ctx.lineTo(
|
|
94
|
-
ctx.moveTo(
|
|
95
|
-
ctx.lineTo(
|
|
96
|
-
ctx.moveTo(
|
|
97
|
-
ctx.lineTo(
|
|
98
|
-
ctx.moveTo(
|
|
99
|
-
ctx.lineTo(
|
|
92
|
+
ctx.moveTo(mark.cx, mark.yHi);
|
|
93
|
+
ctx.lineTo(mark.cx, top);
|
|
94
|
+
ctx.moveTo(mark.cx, bottom);
|
|
95
|
+
ctx.lineTo(mark.cx, mark.yLo);
|
|
96
|
+
ctx.moveTo(mark.cx - capHalf, mark.yHi);
|
|
97
|
+
ctx.lineTo(mark.cx + capHalf, mark.yHi);
|
|
98
|
+
ctx.moveTo(mark.cx - capHalf, mark.yLo);
|
|
99
|
+
ctx.lineTo(mark.cx + capHalf, mark.yLo);
|
|
100
100
|
ctx.stroke();
|
|
101
101
|
}
|
|
102
|
-
function drawBoxBody(ctx,
|
|
102
|
+
function drawBoxBody(ctx, mark, top, height) {
|
|
103
|
+
const left = mark.cx - mark.boxW / 2;
|
|
103
104
|
ctx.beginPath();
|
|
104
|
-
roundedRect(ctx,
|
|
105
|
-
ctx.fillStyle = withAlpha(
|
|
105
|
+
roundedRect(ctx, left, top, mark.boxW, height, Math.min(3, mark.boxW / 4));
|
|
106
|
+
ctx.fillStyle = withAlpha(mark.color, 0.16);
|
|
106
107
|
ctx.fill();
|
|
107
108
|
ctx.stroke();
|
|
108
109
|
ctx.beginPath();
|
|
109
|
-
ctx.moveTo(
|
|
110
|
-
ctx.lineTo(
|
|
110
|
+
ctx.moveTo(left, mark.yMed);
|
|
111
|
+
ctx.lineTo(mark.cx + mark.boxW / 2, mark.yMed);
|
|
111
112
|
ctx.lineWidth = 2;
|
|
112
113
|
ctx.stroke();
|
|
113
114
|
}
|
|
114
|
-
function drawBoxOutliers(ctx,
|
|
115
|
-
ctx.fillStyle = withAlpha(
|
|
116
|
-
for (const
|
|
115
|
+
function drawBoxOutliers(ctx, mark) {
|
|
116
|
+
ctx.fillStyle = withAlpha(mark.color, 0.6);
|
|
117
|
+
for (const y of mark.outliers) {
|
|
117
118
|
ctx.beginPath();
|
|
118
|
-
ctx.arc(
|
|
119
|
+
ctx.arc(mark.cx, y, 1.9, 0, Math.PI * 2);
|
|
119
120
|
ctx.fill();
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
function drawOneBoxSketch(pen,
|
|
123
|
-
const { cx,
|
|
124
|
-
|
|
125
|
-
pen.polyline([{ x: cx, y:
|
|
126
|
-
pen.polyline([{ x: cx
|
|
127
|
-
pen.polyline([{ x: cx - capHalf, y:
|
|
128
|
-
pen.
|
|
123
|
+
function drawOneBoxSketch(pen, mark, showOutliers, top, bottom, h, capHalf) {
|
|
124
|
+
const { cx, boxW, color } = mark;
|
|
125
|
+
const left = cx - boxW / 2;
|
|
126
|
+
pen.polyline([{ x: cx, y: mark.yHi }, { x: cx, y: top }], { stroke: color });
|
|
127
|
+
pen.polyline([{ x: cx, y: bottom }, { x: cx, y: mark.yLo }], { stroke: color });
|
|
128
|
+
pen.polyline([{ x: cx - capHalf, y: mark.yHi }, { x: cx + capHalf, y: mark.yHi }], { stroke: color });
|
|
129
|
+
pen.polyline([{ x: cx - capHalf, y: mark.yLo }, { x: cx + capHalf, y: mark.yLo }], { stroke: color });
|
|
130
|
+
pen.rect(left, top, boxW, h, {
|
|
129
131
|
stroke: color,
|
|
130
132
|
fill: color,
|
|
131
133
|
fillStyle: "solid",
|
|
132
134
|
fillAlpha: 0.16
|
|
133
135
|
});
|
|
134
|
-
pen.polyline([{ x: left, y:
|
|
135
|
-
if (showOutliers &&
|
|
136
|
-
for (const
|
|
137
|
-
pen.circle(cx,
|
|
136
|
+
pen.polyline([{ x: left, y: mark.yMed }, { x: cx + boxW / 2, y: mark.yMed }], { stroke: color, strokeWidth: 2 });
|
|
137
|
+
if (showOutliers && mark.outliers.length) {
|
|
138
|
+
for (const y of mark.outliers) {
|
|
139
|
+
pen.circle(cx, y, 1.9, { fill: withAlpha(color, 0.6) });
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
|
-
function drawOneBox(ctx,
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
const yQ1 = yPix(stats.q1);
|
|
146
|
-
const yQ3 = yPix(stats.q3);
|
|
147
|
-
const yMed = yPix(stats.median);
|
|
148
|
-
const yLo = yPix(stats.min);
|
|
149
|
-
const yHi = yPix(stats.max);
|
|
150
|
-
const top = Math.min(yQ1, yQ3);
|
|
151
|
-
const bottom = Math.max(yQ1, yQ3);
|
|
143
|
+
function drawOneBox(ctx, mark, showOutliers, pen) {
|
|
144
|
+
const capHalf = mark.boxW * 0.28;
|
|
145
|
+
const top = Math.min(mark.yQ1, mark.yQ3);
|
|
146
|
+
const bottom = Math.max(mark.yQ1, mark.yQ3);
|
|
152
147
|
const h = Math.max(1, bottom - top);
|
|
153
|
-
const y = { q1: yQ1, q3: yQ3, med: yMed, lo: yLo, hi: yHi, top, bottom, h };
|
|
154
148
|
if (pen) {
|
|
155
|
-
drawOneBoxSketch(pen,
|
|
149
|
+
drawOneBoxSketch(pen, mark, showOutliers, top, bottom, h, capHalf);
|
|
156
150
|
return;
|
|
157
151
|
}
|
|
158
152
|
ctx.save();
|
|
159
|
-
ctx.strokeStyle = color;
|
|
153
|
+
ctx.strokeStyle = mark.color;
|
|
160
154
|
ctx.lineWidth = 1.5;
|
|
161
155
|
ctx.lineCap = "round";
|
|
162
|
-
drawBoxWhiskers(ctx,
|
|
163
|
-
drawBoxBody(ctx,
|
|
164
|
-
if (showOutliers &&
|
|
165
|
-
drawBoxOutliers(ctx,
|
|
156
|
+
drawBoxWhiskers(ctx, mark, top, bottom, capHalf);
|
|
157
|
+
drawBoxBody(ctx, mark, top, h);
|
|
158
|
+
if (showOutliers && mark.outliers.length) {
|
|
159
|
+
drawBoxOutliers(ctx, mark);
|
|
166
160
|
}
|
|
167
161
|
ctx.restore();
|
|
168
162
|
}
|
|
@@ -179,50 +173,65 @@ function hitsBoxGeom(model, geom, showOutliers, px, py) {
|
|
|
179
173
|
(o) => Math.abs(px - geom.cx) <= 6 && Math.abs(py - model.y.pixel(o)) <= 6
|
|
180
174
|
);
|
|
181
175
|
}
|
|
182
|
-
function
|
|
183
|
-
surface.evidence?.begin("aggregate");
|
|
184
|
-
surface.evidence?.data(0, "aggregate");
|
|
176
|
+
function layoutBoxes(model) {
|
|
185
177
|
const layout = computeBoxes(model);
|
|
186
|
-
if (!layout) return;
|
|
178
|
+
if (!layout) return null;
|
|
179
|
+
const emphasis = model.emphasis ?? null;
|
|
180
|
+
const y = (v) => model.y.pixel(v);
|
|
181
|
+
const marks = layout.geoms.map((geom) => ({
|
|
182
|
+
key: geom.key,
|
|
183
|
+
category: toKey(geom.xValue),
|
|
184
|
+
seriesKey: geom.seriesValue === void 0 ? void 0 : toKey(geom.seriesValue),
|
|
185
|
+
color: geom.color,
|
|
186
|
+
cx: geom.cx,
|
|
187
|
+
boxW: geom.boxW,
|
|
188
|
+
yQ1: y(geom.stats.q1),
|
|
189
|
+
yQ3: y(geom.stats.q3),
|
|
190
|
+
yMed: y(geom.stats.median),
|
|
191
|
+
yLo: y(geom.stats.min),
|
|
192
|
+
yHi: y(geom.stats.max),
|
|
193
|
+
outliers: geom.stats.outliers.map(y),
|
|
194
|
+
alpha: emphasis ? emphasis.match(boxProbe(model, geom)) ? 1 : emphasis.dim : 1,
|
|
195
|
+
count: geom.stats.count
|
|
196
|
+
}));
|
|
197
|
+
return { kind: "box", marks, showOutliers: layout.showOutliers };
|
|
198
|
+
}
|
|
199
|
+
function paintBoxes(surface, model, geometry) {
|
|
187
200
|
const ctx = surface.marks.ctx;
|
|
188
201
|
const { plot } = model;
|
|
189
|
-
const emphasis = model.emphasis ?? null;
|
|
190
202
|
const pen = model.sketch ? new RoughPen(ctx, model.sketch) : null;
|
|
191
|
-
surface.evidence?.data(
|
|
192
|
-
layout.geoms.reduce((n, g) => n + g.stats.count, 0),
|
|
193
|
-
"aggregate"
|
|
194
|
-
);
|
|
195
203
|
ctx.save();
|
|
196
204
|
ctx.beginPath();
|
|
197
205
|
ctx.rect(plot.x, plot.y - 2, plot.width, plot.height + 4);
|
|
198
206
|
ctx.clip();
|
|
199
|
-
for (const
|
|
200
|
-
const alpha =
|
|
207
|
+
for (const mark of geometry.marks) {
|
|
208
|
+
const alpha = mark.alpha;
|
|
201
209
|
const prev = ctx.globalAlpha;
|
|
202
210
|
if (alpha !== 1) ctx.globalAlpha = alpha;
|
|
203
|
-
drawOneBox(ctx,
|
|
211
|
+
drawOneBox(ctx, mark, geometry.showOutliers, pen);
|
|
212
|
+
const top = Math.min(mark.yHi, mark.yLo);
|
|
204
213
|
surface.evidence?.mark(
|
|
205
214
|
"box",
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
Math.max(1,
|
|
210
|
-
|
|
215
|
+
mark.cx - mark.boxW / 2,
|
|
216
|
+
top - 1,
|
|
217
|
+
mark.boxW,
|
|
218
|
+
Math.max(1, Math.max(mark.yHi, mark.yLo) - top) + 2,
|
|
219
|
+
mark.color,
|
|
211
220
|
alpha,
|
|
212
221
|
plot,
|
|
213
222
|
1,
|
|
214
223
|
void 0,
|
|
215
224
|
alpha < 1
|
|
216
225
|
);
|
|
217
|
-
if (
|
|
218
|
-
for (const
|
|
226
|
+
if (geometry.showOutliers)
|
|
227
|
+
for (const y of mark.outliers) {
|
|
219
228
|
surface.evidence?.mark(
|
|
220
229
|
"point",
|
|
221
|
-
|
|
222
|
-
|
|
230
|
+
mark.cx - 1.9,
|
|
231
|
+
y - 1.9,
|
|
223
232
|
3.8,
|
|
224
233
|
3.8,
|
|
225
|
-
|
|
234
|
+
mark.color,
|
|
226
235
|
alpha * 0.6,
|
|
227
236
|
plot,
|
|
228
237
|
1,
|
|
@@ -234,6 +243,18 @@ function drawBox(surface, model) {
|
|
|
234
243
|
}
|
|
235
244
|
ctx.restore();
|
|
236
245
|
}
|
|
246
|
+
function drawBox(surface, model) {
|
|
247
|
+
surface.evidence?.begin("aggregate");
|
|
248
|
+
surface.evidence?.data(0, "aggregate");
|
|
249
|
+
const geometry = layoutBoxes(model);
|
|
250
|
+
model.geometry = geometry ?? void 0;
|
|
251
|
+
if (!geometry) return;
|
|
252
|
+
surface.evidence?.data(
|
|
253
|
+
geometry.marks.reduce((n, mark) => n + mark.count, 0),
|
|
254
|
+
"aggregate"
|
|
255
|
+
);
|
|
256
|
+
paintBoxes(surface, model, geometry);
|
|
257
|
+
}
|
|
237
258
|
function buildBoxInteraction(model) {
|
|
238
259
|
const spec = model.spec;
|
|
239
260
|
const tt = spec.tooltip;
|
|
@@ -298,6 +319,8 @@ export {
|
|
|
298
319
|
buildBoxInteraction,
|
|
299
320
|
computeBoxes,
|
|
300
321
|
computeStats,
|
|
301
|
-
drawBox
|
|
322
|
+
drawBox,
|
|
323
|
+
layoutBoxes,
|
|
324
|
+
paintBoxes
|
|
302
325
|
};
|
|
303
326
|
//# sourceMappingURL=box.js.map
|
package/dist/charts/box.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/charts/box.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Surface } from '../render/surface';\nimport type { CartesianModel } from '../runtime/cartesian';\nimport type { BoxSpec } from '../spec/types';\nimport type { Datum } from '../types';\nimport { withAlpha } from '../color';\nimport { formatValue } from '../format';\nimport { roundedRect } from '../shape';\nimport { RoughPen } from '../rough';\nimport { accessor, toKey, toNumber } from '../util/data';\nimport { quantileSorted } from '../util/math';\nimport type { InteractionModel, TooltipRow } from '../interaction/types';\n\nexport interface BoxStats {\n min: number;\n q1: number;\n median: number;\n q3: number;\n max: number;\n outliers: number[];\n count: number;\n}\n\nexport interface BoxGeom {\n key: string;\n title: string;\n color: string;\n /** Raw x-category value backing this box (for selection identity). */\n xValue: unknown;\n /** Raw series value, or undefined for single-series box plots. */\n seriesValue: unknown;\n cx: number;\n boxW: number;\n left: number;\n right: number;\n /** Vertical hit extent (whisker top to whisker bottom in px). */\n top: number;\n bottom: number;\n stats: BoxStats;\n}\n\nexport interface BoxLayout {\n geoms: BoxGeom[];\n showOutliers: boolean;\n}\n\n/** Type-7 (linear interpolation) quantile of a pre-sorted ascending array. */\nexport function computeStats(values: number[], whisker: 'tukey' | 'minMax'): BoxStats | null {\n const sorted = values.filter((v) => Number.isFinite(v)).sort((a, b) => a - b);\n if (sorted.length === 0) return null;\n const q1 = quantileSorted(sorted, 0.25);\n const median = quantileSorted(sorted, 0.5);\n const q3 = quantileSorted(sorted, 0.75);\n const dataMin = sorted[0];\n const dataMax = sorted[sorted.length - 1];\n const outliers: number[] = [];\n let lo = dataMin;\n let hi = dataMax;\n\n if (whisker === 'tukey') {\n const iqr = q3 - q1;\n const fenceLo = q1 - 1.5 * iqr;\n const fenceHi = q3 + 1.5 * iqr;\n let wLo = Infinity;\n let wHi = -Infinity;\n for (const v of sorted) {\n if (v < fenceLo || v > fenceHi) {\n outliers.push(v);\n continue;\n }\n if (v < wLo) wLo = v;\n if (v > wHi) wHi = v;\n }\n lo = wLo === Infinity ? q1 : wLo;\n hi = wHi === -Infinity ? q3 : wHi;\n }\n\n return { min: lo, q1, median, q3, max: hi, outliers, count: sorted.length };\n}\n\n/** Resolve per-category (and per-series) box geometry without drawing. */\nexport function computeBoxes(model: CartesianModel): BoxLayout | null {\n const spec = model.spec as BoxSpec;\n if (model.x.kind !== 'band' || model.x.bandwidth <= 0 || model.series.length === 0) return null;\n\n const whisker: 'tukey' | 'minMax' = spec.whisker === 'minMax' ? 'minMax' : 'tukey';\n const showOutliers = spec.outliers !== false && whisker === 'tukey';\n const readX = accessor(model.x.field);\n const readY = accessor(model.y.field ?? '');\n const seriesCount = model.series.length;\n const bandWidth = model.x.bandwidth;\n const subWidth = bandWidth / seriesCount;\n const gap = seriesCount > 1 ? Math.min(8, subWidth * 0.18) : 0;\n const boxW = Math.max(3, Math.min(subWidth - gap, 64));\n const grouped = seriesCount > 1;\n const yPix = (v: number): number => model.y.pixel(v);\n const geoms: BoxGeom[] = [];\n\n model.series.forEach((series, seriesIndex) => {\n const groups = new Map<string, { value: unknown; vals: number[] }>();\n for (const row of series.rows) {\n const xv = readX(row);\n const y = toNumber(readY(row));\n if (!Number.isFinite(y)) continue;\n const k = toKey(xv);\n let g = groups.get(k);\n if (!g) {\n g = { value: xv, vals: [] };\n groups.set(k, g);\n }\n g.vals.push(y);\n }\n\n for (const [k, g] of groups) {\n const cxRaw = model.x.pixel(g.value);\n if (cxRaw == null) continue;\n const stats = computeStats(g.vals, whisker);\n if (!stats) continue;\n const cx = cxRaw - bandWidth / 2 + (seriesIndex + 0.5) * subWidth;\n geoms.push({\n key: grouped ? `${k}\\u0000${series.key}` : k,\n title: grouped ? `${k} \u00B7 ${series.label}` : k,\n color: series.color,\n xValue: g.value,\n seriesValue: grouped ? series.value : undefined,\n cx,\n boxW,\n left: cx - boxW / 2,\n right: cx + boxW / 2,\n top: Math.min(yPix(stats.max), yPix(stats.min)),\n bottom: Math.max(yPix(stats.max), yPix(stats.min)),\n stats,\n });\n }\n });\n\n return geoms.length ? { geoms, showOutliers } : null;\n}\n\nfunction drawBoxWhiskers(ctx: CanvasRenderingContext2D, geom: BoxGeom, yLo: number, yHi: number, top: number, bottom: number, capHalf: number): void {\n ctx.beginPath();\n ctx.moveTo(geom.cx, yHi);\n ctx.lineTo(geom.cx, top);\n ctx.moveTo(geom.cx, bottom);\n ctx.lineTo(geom.cx, yLo);\n ctx.moveTo(geom.cx - capHalf, yHi);\n ctx.lineTo(geom.cx + capHalf, yHi);\n ctx.moveTo(geom.cx - capHalf, yLo);\n ctx.lineTo(geom.cx + capHalf, yLo);\n ctx.stroke();\n}\n\nfunction drawBoxBody(ctx: CanvasRenderingContext2D, geom: BoxGeom, top: number, height: number, yMed: number): void {\n ctx.beginPath();\n roundedRect(ctx, geom.left, top, geom.boxW, height, Math.min(3, geom.boxW / 4));\n ctx.fillStyle = withAlpha(geom.color, 0.16);\n ctx.fill();\n ctx.stroke();\n\n ctx.beginPath();\n ctx.moveTo(geom.left, yMed);\n ctx.lineTo(geom.right, yMed);\n ctx.lineWidth = 2;\n ctx.stroke();\n}\n\nfunction drawBoxOutliers(ctx: CanvasRenderingContext2D, model: CartesianModel, geom: BoxGeom): void {\n ctx.fillStyle = withAlpha(geom.color, 0.6);\n for (const o of geom.stats.outliers) {\n ctx.beginPath();\n ctx.arc(geom.cx, model.y.pixel(o), 1.9, 0, Math.PI * 2);\n ctx.fill();\n }\n}\n\nfunction drawOneBoxSketch(\n pen: RoughPen,\n model: CartesianModel,\n geom: BoxGeom,\n showOutliers: boolean,\n y: { q1: number; q3: number; med: number; lo: number; hi: number; top: number; bottom: number; h: number },\n capHalf: number,\n): void {\n const { cx, left, right, boxW, stats, color } = geom;\n pen.polyline([{ x: cx, y: y.hi }, { x: cx, y: y.top }], { stroke: color });\n pen.polyline([{ x: cx, y: y.bottom }, { x: cx, y: y.lo }], { stroke: color });\n pen.polyline([{ x: cx - capHalf, y: y.hi }, { x: cx + capHalf, y: y.hi }], { stroke: color });\n pen.polyline([{ x: cx - capHalf, y: y.lo }, { x: cx + capHalf, y: y.lo }], { stroke: color });\n pen.rect(left, y.top, boxW, y.h, {\n stroke: color,\n fill: color,\n fillStyle: 'solid',\n fillAlpha: 0.16,\n });\n pen.polyline([{ x: left, y: y.med }, { x: right, y: y.med }], { stroke: color, strokeWidth: 2 });\n if (showOutliers && stats.outliers.length) {\n for (const o of stats.outliers) {\n pen.circle(cx, model.y.pixel(o), 1.9, { fill: withAlpha(color, 0.6) });\n }\n }\n}\n\nfunction drawOneBox(\n ctx: CanvasRenderingContext2D,\n model: CartesianModel,\n geom: BoxGeom,\n showOutliers: boolean,\n pen: RoughPen | null,\n): void {\n const yPix = (v: number): number => model.y.pixel(v);\n const { boxW, stats, color } = geom;\n const capHalf = boxW * 0.28;\n const yQ1 = yPix(stats.q1);\n const yQ3 = yPix(stats.q3);\n const yMed = yPix(stats.median);\n const yLo = yPix(stats.min);\n const yHi = yPix(stats.max);\n const top = Math.min(yQ1, yQ3);\n const bottom = Math.max(yQ1, yQ3);\n const h = Math.max(1, bottom - top);\n const y = { q1: yQ1, q3: yQ3, med: yMed, lo: yLo, hi: yHi, top, bottom, h };\n\n if (pen) {\n drawOneBoxSketch(pen, model, geom, showOutliers, y, capHalf);\n return;\n }\n\n ctx.save();\n ctx.strokeStyle = color;\n ctx.lineWidth = 1.5;\n ctx.lineCap = 'round';\n\n drawBoxWhiskers(ctx, geom, yLo, yHi, top, bottom, capHalf);\n drawBoxBody(ctx, geom, top, h, yMed);\n\n if (showOutliers && stats.outliers.length) {\n drawBoxOutliers(ctx, model, geom);\n }\n\n ctx.restore();\n}\n\n/** Build the synthetic row a box represents, for emphasis/selection matching. */\nfunction boxProbe(model: CartesianModel, geom: BoxGeom): Datum {\n const probe: Datum = { [model.x.field]: geom.xValue };\n if (model.seriesField) probe[model.seriesField] = geom.seriesValue;\n return probe;\n}\n\nfunction hitsBoxGeom(\n model: CartesianModel,\n geom: BoxGeom,\n showOutliers: boolean,\n px: number,\n py: number,\n): boolean {\n const inWhiskerExtent =\n px >= geom.left - 4 && px <= geom.right + 4 && py >= geom.top - 6 && py <= geom.bottom + 6;\n if (inWhiskerExtent) return true;\n if (!showOutliers || geom.stats.outliers.length === 0) return false;\n return geom.stats.outliers.some(\n (o) => Math.abs(px - geom.cx) <= 6 && Math.abs(py - model.y.pixel(o)) <= 6,\n );\n}\n\nexport function drawBox(surface: Surface, model: CartesianModel): void {\n surface.evidence?.begin('aggregate');\n surface.evidence?.data(0, 'aggregate');\n const layout = computeBoxes(model);\n if (!layout) return;\n const ctx = surface.marks.ctx;\n const { plot } = model;\n const emphasis = model.emphasis ?? null;\n const pen = model.sketch ? new RoughPen(ctx, model.sketch) : null;\n surface.evidence?.data(\n layout.geoms.reduce((n, g) => n + g.stats.count, 0),\n 'aggregate',\n );\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(plot.x, plot.y - 2, plot.width, plot.height + 4);\n ctx.clip();\n for (const geom of layout.geoms) {\n const alpha = emphasis ? (emphasis.match(boxProbe(model, geom)) ? 1 : emphasis.dim) : 1;\n const prev = ctx.globalAlpha;\n if (alpha !== 1) ctx.globalAlpha = alpha;\n drawOneBox(ctx, model, geom, layout.showOutliers, pen);\n surface.evidence?.mark(\n 'box',\n geom.left,\n geom.top - 1,\n geom.boxW,\n Math.max(1, geom.bottom - geom.top) + 2,\n geom.color,\n alpha,\n plot,\n 1,\n undefined,\n alpha < 1,\n );\n if (layout.showOutliers)\n for (const outlier of geom.stats.outliers) {\n surface.evidence?.mark(\n 'point',\n geom.cx - 1.9,\n model.y.pixel(outlier) - 1.9,\n 3.8,\n 3.8,\n geom.color,\n alpha * 0.6,\n plot,\n 1,\n undefined,\n alpha < 1,\n );\n }\n if (alpha !== 1) ctx.globalAlpha = prev;\n }\n ctx.restore();\n}\n\n/** Box-plot interaction (the runtime uses this instead of the generic cartesian one). */\nexport function buildBoxInteraction(model: CartesianModel): InteractionModel | void {\n const spec = model.spec as BoxSpec;\n const tt = spec.tooltip;\n if (tt === false || (tt && typeof tt === 'object' && tt.show === false)) return;\n const layout = computeBoxes(model);\n if (!layout) return;\n const { geoms, showOutliers } = layout;\n const fmt = (v: number): string => formatValue(v, spec.encoding.y.format);\n\n return {\n region: model.plot,\n hitTest: (px, py) => {\n const hit = geoms.find((g) => hitsBoxGeom(model, g, showOutliers, px, py));\n if (!hit) return null;\n const s = hit.stats;\n const rows: TooltipRow[] = [\n { label: 'Max', value: fmt(s.max) },\n { swatch: hit.color, label: 'Q3', value: fmt(s.q3) },\n { label: 'Median', value: fmt(s.median) },\n { swatch: hit.color, label: 'Q1', value: fmt(s.q1) },\n { label: 'Min', value: fmt(s.min) },\n { label: 'n', value: String(s.count), muted: true },\n ];\n if (showOutliers && s.outliers.length) {\n rows.push({ label: 'Outliers', value: String(s.outliers.length), muted: true });\n }\n return {\n key: hit.key,\n anchorX: hit.cx,\n anchorY: hit.top,\n content: { title: hit.title, rows },\n draw: (ictx) => {\n const top = Math.min(model.y.pixel(hit.stats.q1), model.y.pixel(hit.stats.q3));\n const h = Math.max(\n 1,\n Math.abs(model.y.pixel(hit.stats.q1) - model.y.pixel(hit.stats.q3)),\n );\n ictx.save();\n ictx.strokeStyle = hit.color;\n ictx.lineWidth = 2;\n ictx.beginPath();\n roundedRect(ictx, hit.left, top, hit.boxW, h, Math.min(3, hit.boxW / 4));\n ictx.stroke();\n ictx.restore();\n },\n };\n },\n pick: (px, py) => {\n const hit = geoms.find((g) => hitsBoxGeom(model, g, showOutliers, px, py));\n if (!hit) return null;\n if (model.series.length > 1 && model.seriesField && hit.seriesValue !== undefined) {\n return {\n kind: 'point',\n fields: [model.x.field, model.seriesField],\n tuples: [[hit.xValue, hit.seriesValue]],\n };\n }\n return { kind: 'point', fields: [model.x.field], tuples: [[hit.xValue]] };\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAIA,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,UAAU,OAAO,gBAAgB;AAC1C,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import type { Surface } from '../render/surface';\nimport type { CartesianModel } from '../runtime/cartesian';\nimport type { BoxSpec } from '../spec/types';\nimport type { Datum } from '../types';\nimport { withAlpha } from '../color';\nimport { formatValue } from '../format';\nimport { roundedRect } from '../shape';\nimport { RoughPen } from '../rough';\nimport { accessor, toKey, toNumber } from '../util/data';\nimport { quantileSorted } from '../util/math';\nimport type { InteractionModel, TooltipRow } from '../interaction/types';\n\nexport interface BoxStats {\n min: number;\n q1: number;\n median: number;\n q3: number;\n max: number;\n outliers: number[];\n count: number;\n}\n\nexport interface BoxGeom {\n key: string;\n title: string;\n color: string;\n /** Raw x-category value backing this box (for selection identity). */\n xValue: unknown;\n /** Raw series value, or undefined for single-series box plots. */\n seriesValue: unknown;\n cx: number;\n boxW: number;\n left: number;\n right: number;\n /** Vertical hit extent (whisker top to whisker bottom in px). */\n top: number;\n bottom: number;\n stats: BoxStats;\n}\n\nexport interface BoxLayout {\n geoms: BoxGeom[];\n showOutliers: boolean;\n}\n\n/** One box as drawn: pixel-space whiskers, quartiles and outliers. */\nexport interface BoxMark {\n key: string;\n /** Category key (x) and series key, for hover focus subsets. */\n category: string;\n seriesKey?: string;\n color: string;\n cx: number;\n boxW: number;\n yQ1: number;\n yQ3: number;\n yMed: number;\n yLo: number;\n yHi: number;\n /** Outlier centers (px). */\n outliers: number[];\n /** Opacity: the highlight's dim, times any morph fade. */\n alpha: number;\n /** Observations summarized (render evidence). */\n count: number;\n}\n\n/** A box plot's resolved marks \u2014 what {@link paintBoxes} draws and update morphs tween. */\nexport interface BoxGeometry {\n kind: 'box';\n marks: BoxMark[];\n showOutliers: boolean;\n}\n\n/** Type-7 (linear interpolation) quantile of a pre-sorted ascending array. */\nexport function computeStats(values: number[], whisker: 'tukey' | 'minMax'): BoxStats | null {\n const sorted = values.filter((v) => Number.isFinite(v)).sort((a, b) => a - b);\n if (sorted.length === 0) return null;\n const q1 = quantileSorted(sorted, 0.25);\n const median = quantileSorted(sorted, 0.5);\n const q3 = quantileSorted(sorted, 0.75);\n const dataMin = sorted[0];\n const dataMax = sorted[sorted.length - 1];\n const outliers: number[] = [];\n let lo = dataMin;\n let hi = dataMax;\n\n if (whisker === 'tukey') {\n const iqr = q3 - q1;\n const fenceLo = q1 - 1.5 * iqr;\n const fenceHi = q3 + 1.5 * iqr;\n let wLo = Infinity;\n let wHi = -Infinity;\n for (const v of sorted) {\n if (v < fenceLo || v > fenceHi) {\n outliers.push(v);\n continue;\n }\n if (v < wLo) wLo = v;\n if (v > wHi) wHi = v;\n }\n lo = wLo === Infinity ? q1 : wLo;\n hi = wHi === -Infinity ? q3 : wHi;\n }\n\n return { min: lo, q1, median, q3, max: hi, outliers, count: sorted.length };\n}\n\n/** Resolve per-category (and per-series) box geometry without drawing. */\nexport function computeBoxes(model: CartesianModel): BoxLayout | null {\n const spec = model.spec as BoxSpec;\n if (model.x.kind !== 'band' || model.x.bandwidth <= 0 || model.series.length === 0) return null;\n\n const whisker: 'tukey' | 'minMax' = spec.whisker === 'minMax' ? 'minMax' : 'tukey';\n const showOutliers = spec.outliers !== false && whisker === 'tukey';\n const readX = accessor(model.x.field);\n const readY = accessor(model.y.field ?? '');\n const seriesCount = model.series.length;\n const bandWidth = model.x.bandwidth;\n const subWidth = bandWidth / seriesCount;\n const gap = seriesCount > 1 ? Math.min(8, subWidth * 0.18) : 0;\n const boxW = Math.max(3, Math.min(subWidth - gap, 64));\n const grouped = seriesCount > 1;\n const yPix = (v: number): number => model.y.pixel(v);\n const geoms: BoxGeom[] = [];\n\n model.series.forEach((series, seriesIndex) => {\n const groups = new Map<string, { value: unknown; vals: number[] }>();\n for (const row of series.rows) {\n const xv = readX(row);\n const y = toNumber(readY(row));\n if (!Number.isFinite(y)) continue;\n const k = toKey(xv);\n let g = groups.get(k);\n if (!g) {\n g = { value: xv, vals: [] };\n groups.set(k, g);\n }\n g.vals.push(y);\n }\n\n for (const [k, g] of groups) {\n const cxRaw = model.x.pixel(g.value);\n if (cxRaw == null) continue;\n const stats = computeStats(g.vals, whisker);\n if (!stats) continue;\n const cx = cxRaw - bandWidth / 2 + (seriesIndex + 0.5) * subWidth;\n geoms.push({\n key: grouped ? `${k}\\u0000${series.key}` : k,\n title: grouped ? `${k} \u00B7 ${series.label}` : k,\n color: series.color,\n xValue: g.value,\n seriesValue: grouped ? series.value : undefined,\n cx,\n boxW,\n left: cx - boxW / 2,\n right: cx + boxW / 2,\n top: Math.min(yPix(stats.max), yPix(stats.min)),\n bottom: Math.max(yPix(stats.max), yPix(stats.min)),\n stats,\n });\n }\n });\n\n return geoms.length ? { geoms, showOutliers } : null;\n}\n\nfunction drawBoxWhiskers(ctx: CanvasRenderingContext2D, mark: BoxMark, top: number, bottom: number, capHalf: number): void {\n ctx.beginPath();\n ctx.moveTo(mark.cx, mark.yHi);\n ctx.lineTo(mark.cx, top);\n ctx.moveTo(mark.cx, bottom);\n ctx.lineTo(mark.cx, mark.yLo);\n ctx.moveTo(mark.cx - capHalf, mark.yHi);\n ctx.lineTo(mark.cx + capHalf, mark.yHi);\n ctx.moveTo(mark.cx - capHalf, mark.yLo);\n ctx.lineTo(mark.cx + capHalf, mark.yLo);\n ctx.stroke();\n}\n\nfunction drawBoxBody(ctx: CanvasRenderingContext2D, mark: BoxMark, top: number, height: number): void {\n const left = mark.cx - mark.boxW / 2;\n ctx.beginPath();\n roundedRect(ctx, left, top, mark.boxW, height, Math.min(3, mark.boxW / 4));\n ctx.fillStyle = withAlpha(mark.color, 0.16);\n ctx.fill();\n ctx.stroke();\n\n ctx.beginPath();\n ctx.moveTo(left, mark.yMed);\n ctx.lineTo(mark.cx + mark.boxW / 2, mark.yMed);\n ctx.lineWidth = 2;\n ctx.stroke();\n}\n\nfunction drawBoxOutliers(ctx: CanvasRenderingContext2D, mark: BoxMark): void {\n ctx.fillStyle = withAlpha(mark.color, 0.6);\n for (const y of mark.outliers) {\n ctx.beginPath();\n ctx.arc(mark.cx, y, 1.9, 0, Math.PI * 2);\n ctx.fill();\n }\n}\n\nfunction drawOneBoxSketch(pen: RoughPen, mark: BoxMark, showOutliers: boolean, top: number, bottom: number, h: number, capHalf: number): void {\n const { cx, boxW, color } = mark;\n const left = cx - boxW / 2;\n pen.polyline([{ x: cx, y: mark.yHi }, { x: cx, y: top }], { stroke: color });\n pen.polyline([{ x: cx, y: bottom }, { x: cx, y: mark.yLo }], { stroke: color });\n pen.polyline([{ x: cx - capHalf, y: mark.yHi }, { x: cx + capHalf, y: mark.yHi }], { stroke: color });\n pen.polyline([{ x: cx - capHalf, y: mark.yLo }, { x: cx + capHalf, y: mark.yLo }], { stroke: color });\n pen.rect(left, top, boxW, h, {\n stroke: color,\n fill: color,\n fillStyle: 'solid',\n fillAlpha: 0.16,\n });\n pen.polyline([{ x: left, y: mark.yMed }, { x: cx + boxW / 2, y: mark.yMed }], { stroke: color, strokeWidth: 2 });\n if (showOutliers && mark.outliers.length) {\n for (const y of mark.outliers) {\n pen.circle(cx, y, 1.9, { fill: withAlpha(color, 0.6) });\n }\n }\n}\n\nfunction drawOneBox(ctx: CanvasRenderingContext2D, mark: BoxMark, showOutliers: boolean, pen: RoughPen | null): void {\n const capHalf = mark.boxW * 0.28;\n const top = Math.min(mark.yQ1, mark.yQ3);\n const bottom = Math.max(mark.yQ1, mark.yQ3);\n const h = Math.max(1, bottom - top);\n\n if (pen) {\n drawOneBoxSketch(pen, mark, showOutliers, top, bottom, h, capHalf);\n return;\n }\n\n ctx.save();\n ctx.strokeStyle = mark.color;\n ctx.lineWidth = 1.5;\n ctx.lineCap = 'round';\n\n drawBoxWhiskers(ctx, mark, top, bottom, capHalf);\n drawBoxBody(ctx, mark, top, h);\n\n if (showOutliers && mark.outliers.length) {\n drawBoxOutliers(ctx, mark);\n }\n\n ctx.restore();\n}\n\n/** Build the synthetic row a box represents, for emphasis/selection matching. */\nfunction boxProbe(model: CartesianModel, geom: BoxGeom): Datum {\n const probe: Datum = { [model.x.field]: geom.xValue };\n if (model.seriesField) probe[model.seriesField] = geom.seriesValue;\n return probe;\n}\n\nfunction hitsBoxGeom(\n model: CartesianModel,\n geom: BoxGeom,\n showOutliers: boolean,\n px: number,\n py: number,\n): boolean {\n const inWhiskerExtent =\n px >= geom.left - 4 && px <= geom.right + 4 && py >= geom.top - 6 && py <= geom.bottom + 6;\n if (inWhiskerExtent) return true;\n if (!showOutliers || geom.stats.outliers.length === 0) return false;\n return geom.stats.outliers.some(\n (o) => Math.abs(px - geom.cx) <= 6 && Math.abs(py - model.y.pixel(o)) <= 6,\n );\n}\n\n/** Resolve the boxes' pixel geometry (including highlight dimming) without drawing. */\nexport function layoutBoxes(model: CartesianModel): BoxGeometry | null {\n const layout = computeBoxes(model);\n if (!layout) return null;\n const emphasis = model.emphasis ?? null;\n const y = (v: number): number => model.y.pixel(v);\n const marks = layout.geoms.map((geom): BoxMark => ({\n key: geom.key,\n category: toKey(geom.xValue),\n seriesKey: geom.seriesValue === undefined ? undefined : toKey(geom.seriesValue),\n color: geom.color,\n cx: geom.cx,\n boxW: geom.boxW,\n yQ1: y(geom.stats.q1),\n yQ3: y(geom.stats.q3),\n yMed: y(geom.stats.median),\n yLo: y(geom.stats.min),\n yHi: y(geom.stats.max),\n outliers: geom.stats.outliers.map(y),\n alpha: emphasis ? (emphasis.match(boxProbe(model, geom)) ? 1 : emphasis.dim) : 1,\n count: geom.stats.count,\n }));\n return { kind: 'box', marks, showOutliers: layout.showOutliers };\n}\n\n/** Paint box geometry (clipped to the plot), recording evidence for each box and outlier. */\nexport function paintBoxes(surface: Surface, model: CartesianModel, geometry: BoxGeometry): void {\n const ctx = surface.marks.ctx;\n const { plot } = model;\n const pen = model.sketch ? new RoughPen(ctx, model.sketch) : null;\n ctx.save();\n ctx.beginPath();\n ctx.rect(plot.x, plot.y - 2, plot.width, plot.height + 4);\n ctx.clip();\n for (const mark of geometry.marks) {\n const alpha = mark.alpha;\n const prev = ctx.globalAlpha;\n if (alpha !== 1) ctx.globalAlpha = alpha;\n drawOneBox(ctx, mark, geometry.showOutliers, pen);\n const top = Math.min(mark.yHi, mark.yLo);\n surface.evidence?.mark(\n 'box',\n mark.cx - mark.boxW / 2,\n top - 1,\n mark.boxW,\n Math.max(1, Math.max(mark.yHi, mark.yLo) - top) + 2,\n mark.color,\n alpha,\n plot,\n 1,\n undefined,\n alpha < 1,\n );\n if (geometry.showOutliers)\n for (const y of mark.outliers) {\n surface.evidence?.mark(\n 'point',\n mark.cx - 1.9,\n y - 1.9,\n 3.8,\n 3.8,\n mark.color,\n alpha * 0.6,\n plot,\n 1,\n undefined,\n alpha < 1,\n );\n }\n if (alpha !== 1) ctx.globalAlpha = prev;\n }\n ctx.restore();\n}\n\nexport function drawBox(surface: Surface, model: CartesianModel): void {\n surface.evidence?.begin('aggregate');\n surface.evidence?.data(0, 'aggregate');\n const geometry = layoutBoxes(model);\n model.geometry = geometry ?? undefined;\n if (!geometry) return;\n surface.evidence?.data(\n geometry.marks.reduce((n, mark) => n + mark.count, 0),\n 'aggregate',\n );\n paintBoxes(surface, model, geometry);\n}\n\n/** Box-plot interaction (the runtime uses this instead of the generic cartesian one). */\nexport function buildBoxInteraction(model: CartesianModel): InteractionModel | void {\n const spec = model.spec as BoxSpec;\n const tt = spec.tooltip;\n if (tt === false || (tt && typeof tt === 'object' && tt.show === false)) return;\n const layout = computeBoxes(model);\n if (!layout) return;\n const { geoms, showOutliers } = layout;\n const fmt = (v: number): string => formatValue(v, spec.encoding.y.format);\n\n return {\n region: model.plot,\n hitTest: (px, py) => {\n const hit = geoms.find((g) => hitsBoxGeom(model, g, showOutliers, px, py));\n if (!hit) return null;\n const s = hit.stats;\n const rows: TooltipRow[] = [\n { label: 'Max', value: fmt(s.max) },\n { swatch: hit.color, label: 'Q3', value: fmt(s.q3) },\n { label: 'Median', value: fmt(s.median) },\n { swatch: hit.color, label: 'Q1', value: fmt(s.q1) },\n { label: 'Min', value: fmt(s.min) },\n { label: 'n', value: String(s.count), muted: true },\n ];\n if (showOutliers && s.outliers.length) {\n rows.push({ label: 'Outliers', value: String(s.outliers.length), muted: true });\n }\n return {\n key: hit.key,\n anchorX: hit.cx,\n anchorY: hit.top,\n content: { title: hit.title, rows },\n draw: (ictx) => {\n const top = Math.min(model.y.pixel(hit.stats.q1), model.y.pixel(hit.stats.q3));\n const h = Math.max(\n 1,\n Math.abs(model.y.pixel(hit.stats.q1) - model.y.pixel(hit.stats.q3)),\n );\n ictx.save();\n ictx.strokeStyle = hit.color;\n ictx.lineWidth = 2;\n ictx.beginPath();\n roundedRect(ictx, hit.left, top, hit.boxW, h, Math.min(3, hit.boxW / 4));\n ictx.stroke();\n ictx.restore();\n },\n };\n },\n pick: (px, py) => {\n const hit = geoms.find((g) => hitsBoxGeom(model, g, showOutliers, px, py));\n if (!hit) return null;\n if (model.series.length > 1 && model.seriesField && hit.seriesValue !== undefined) {\n return {\n kind: 'point',\n fields: [model.x.field, model.seriesField],\n tuples: [[hit.xValue, hit.seriesValue]],\n };\n }\n return { kind: 'point', fields: [model.x.field], tuples: [[hit.xValue]] };\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bubble map — one circle per row at its longitude/latitude, its area ∝ `size`,
|
|
3
|
+
* colored by an optional numeric (sequential ramp) or categorical (palette)
|
|
4
|
+
* field, over an optional GeoJSON basemap.
|
|
5
|
+
*
|
|
6
|
+
* With a basemap the projection is fitted to it, so the map stays put as data
|
|
7
|
+
* changes; without one it is fitted to the bubbles. Rows that can't be placed
|
|
8
|
+
* (non-finite or out-of-range coordinates, non-finite sizes, or — over a
|
|
9
|
+
* basemap — positions outside the map) are counted as omitted, never guessed.
|
|
10
|
+
* Negative sizes can't be drawn as area, so their location is marked by a
|
|
11
|
+
* hollow ring instead of a sized disc.
|
|
12
|
+
*/
|
|
13
|
+
import type { Surface } from '../render/surface.js';
|
|
14
|
+
import type { ChartSpec } from '../spec/types.js';
|
|
15
|
+
import type { ThemeTokens } from '../theme/index.js';
|
|
16
|
+
import type { Size } from '../types.js';
|
|
17
|
+
import type { InteractionModel } from '../interaction/types.js';
|
|
18
|
+
import type { RenderContext } from './index.js';
|
|
19
|
+
export declare function drawBubbleMap(surface: Surface, spec: ChartSpec, tokens: ThemeTokens, size: Size, context?: RenderContext): InteractionModel | void;
|
|
20
|
+
//# sourceMappingURL=bubbleMap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bubbleMap.d.ts","sourceRoot":"","sources":["../../src/charts/bubbleMap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAMjD,OAAO,KAAK,EAAiB,SAAS,EAAuC,MAAM,eAAe,CAAC;AACnG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAqB,IAAI,EAAE,MAAM,UAAU,CAAC;AAExD,OAAO,KAAK,EAAE,gBAAgB,EAA8B,MAAM,sBAAsB,CAAC;AAUzF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AA27B7C,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,GAAG,IAAI,CA6JzB"}
|