diff --git a/src/plot.js b/src/plot.js
index 2d3795fc175..e041e11a145 100644
--- a/src/plot.js
+++ b/src/plot.js
@@ -17,6 +17,7 @@ import {innerDimensions, outerDimensions} from "./scales.js";
import {position, registry as scaleRegistry} from "./scales/index.js";
import {applyInlineStyles, maybeClassName} from "./style.js";
import {initializer} from "./transforms/basic.js";
+import {centroidChannels} from "./transforms/centroid.js";
import {consumeWarnings, warn} from "./warnings.js";
export function plot(options = {}) {
@@ -502,8 +503,18 @@ function maybeMarkFacet(mark, topFacetState, options) {
}
function derive(mark, options = {}) {
- return initializer({...options, x: null, y: null}, (data, facets, channels, scales, dimensions, context) => {
- return context.getMarkState(mark);
+ return initializer({...options, x: null, y: null}, (da, f, c, s, di, context) => {
+ let {
+ data,
+ facets,
+ channels: {geometry, x, y, ...channels}
+ } = context.getMarkState(mark);
+ if (geometry && !x && !y) {
+ const {projection} = context;
+ ({x, y} = centroidChannels(data, (d) => d, projection));
+ if (projection == null) (x.scale = "x"), (y.scale = "y");
+ }
+ return {data, facets, channels: {...channels, ...(x && {x}), ...(y && {y})}};
});
}
diff --git a/src/transforms/centroid.js b/src/transforms/centroid.js
index 6be53a1fc08..b7183d26913 100644
--- a/src/transforms/centroid.js
+++ b/src/transforms/centroid.js
@@ -2,17 +2,23 @@ import {geoCentroid as GeoCentroid, geoPath} from "d3";
import {identity, valueof} from "../options.js";
import {initializer} from "./basic.js";
-export function centroid({geometry = identity, ...options} = {}) {
+export function centroid({geometry, ...options} = {}) {
// Suppress defaults for x and y since they will be computed by the initializer.
- return initializer({...options, x: null, y: null}, (data, facets, channels, scales, dimensions, {projection}) => {
- const G = valueof(data, geometry);
- const n = G.length;
- const X = new Float64Array(n);
- const Y = new Float64Array(n);
- const path = geoPath(projection);
- for (let i = 0; i < n; ++i) [X[i], Y[i]] = path.centroid(G[i]);
- return {data, facets, channels: {x: {value: X, source: null}, y: {value: Y, source: null}}};
- });
+ return initializer({...options, x: null, y: null}, (data, facets, channels, scales, dimensions, {projection}) => ({
+ data,
+ facets,
+ channels: {...channels, ...centroidChannels(data, geometry, projection)}
+ }));
+}
+
+export function centroidChannels(data, geometry = identity, projection) {
+ const G = valueof(data, geometry);
+ const n = G.length;
+ const X = new Float64Array(n);
+ const Y = new Float64Array(n);
+ const path = geoPath(projection);
+ for (let i = 0; i < n; ++i) [X[i], Y[i]] = path.centroid(G[i]);
+ return {x: {value: X, source: null}, y: {value: Y, source: null}};
}
export function geoCentroid({geometry = identity, ...options} = {}) {
diff --git a/test/output/tipGeoRaw.svg b/test/output/tipGeoRaw.svg
new file mode 100644
index 00000000000..7cff8309172
--- /dev/null
+++ b/test/output/tipGeoRaw.svg
@@ -0,0 +1,3170 @@
+
\ No newline at end of file
diff --git a/test/plots/tip.ts b/test/plots/tip.ts
index 55e005dc209..7165c33a6a2 100644
--- a/test/plots/tip.ts
+++ b/test/plots/tip.ts
@@ -100,6 +100,15 @@ export async function tipDotFilter() {
});
}
+export async function tipGeoRaw() {
+ const counties = await d3.json("data/us-counties-10m.json").then((us) => feature(us, us.objects.counties));
+ counties.features = counties.features.filter((d) => {
+ const [x, y] = d3.geoCentroid(d);
+ return x > -126 && x < -68 && y > 25 && y < 49;
+ });
+ return Plot.geo(counties, {title: (d) => d.properties.name, tip: true}).plot();
+}
+
export async function tipGeoCentroid() {
const [[counties, countymesh]] = await Promise.all([
d3