diff --git a/src/plot.js b/src/plot.js
index 7eab7d0811..5aa5545c4c 100644
--- a/src/plot.js
+++ b/src/plot.js
@@ -14,7 +14,7 @@ import {arrayify, map, yes, maybeIntervalTransform, subarray} from "./options.js
import {createProjection, getGeometryChannels, hasProjection} from "./projection.js";
import {createScales, createScaleFunctions, autoScaleRange, exposeScales} from "./scales.js";
import {innerDimensions, outerDimensions} from "./scales.js";
-import {position, registry as scaleRegistry} from "./scales/index.js";
+import {isPosition, registry as scaleRegistry} from "./scales/index.js";
import {applyInlineStyles, maybeClassName} from "./style.js";
import {initializer} from "./transforms/basic.js";
import {consumeWarnings, warn} from "./warnings.js";
@@ -201,7 +201,7 @@ export function plot(options = {}) {
// channels as-is rather than creating new scales, and assume that
// they already have the scale’s transform applied, if any (e.g., when
// generating ticks for the axis mark).
- if (scale != null && scaleRegistry.get(scale) !== position) {
+ if (scale != null && !isPosition(scaleRegistry.get(scale))) {
applyScaleTransform(channel, options);
newByScale.add(scale);
}
diff --git a/src/scales/index.js b/src/scales/index.js
index a152db0ef8..2e624a709a 100644
--- a/src/scales/index.js
+++ b/src/scales/index.js
@@ -23,6 +23,7 @@ export const opacity = Symbol("opacity");
export const symbol = Symbol("symbol");
// There isn’t really a projection scale; this represents x and y for geometry.
+// This is used to denote channels that should be projected.
export const projection = Symbol("projection");
// TODO Rather than hard-coding the list of known scale names, collect the names
@@ -40,3 +41,7 @@ export const registry = new Map([
["length", length],
["projection", projection]
]);
+
+export function isPosition(kind) {
+ return kind === position || kind === projection;
+}
diff --git a/src/transforms/centroid.js b/src/transforms/centroid.js
index 6be53a1fc0..b832775164 100644
--- a/src/transforms/centroid.js
+++ b/src/transforms/centroid.js
@@ -11,7 +11,14 @@ export function centroid({geometry = identity, ...options} = {}) {
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 {
+ data,
+ facets,
+ channels: {
+ x: {value: X, scale: projection == null ? "x" : null, source: null},
+ y: {value: Y, scale: projection == null ? "y" : null, source: null}
+ }
+ };
});
}
diff --git a/test/output/tipGeoNoProjection.svg b/test/output/tipGeoNoProjection.svg
new file mode 100644
index 0000000000..7cff830917
--- /dev/null
+++ b/test/output/tipGeoNoProjection.svg
@@ -0,0 +1,3170 @@
+
\ No newline at end of file
diff --git a/test/output/tipGeoProjection.svg b/test/output/tipGeoProjection.svg
new file mode 100644
index 0000000000..761e0d81b7
--- /dev/null
+++ b/test/output/tipGeoProjection.svg
@@ -0,0 +1,3126 @@
+
\ No newline at end of file
diff --git a/test/plots/tip.ts b/test/plots/tip.ts
index 55e005dc20..9b49f06b2a 100644
--- a/test/plots/tip.ts
+++ b/test/plots/tip.ts
@@ -100,6 +100,24 @@ export async function tipDotFilter() {
});
}
+export async function tipGeoNoProjection() {
+ 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, Plot.centroid({title: (d) => d.properties.name, tip: true})).plot();
+}
+
+export async function tipGeoProjection() {
+ 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, Plot.centroid({title: (d) => d.properties.name, tip: true})).plot({projection: "albers"});
+}
+
export async function tipGeoCentroid() {
const [[counties, countymesh]] = await Promise.all([
d3