diff --git a/src/style.js b/src/style.js
index f984750bf4..94e4742ee0 100644
--- a/src/style.js
+++ b/src/style.js
@@ -1,4 +1,4 @@
-import {geoPath, group, namespaces} from "d3";
+import {geoPath, group, namespaces, select} from "d3";
import {create} from "./context.js";
import {defined, nonempty} from "./defined.js";
import {formatDefault} from "./format.js";
@@ -302,43 +302,25 @@ export function* groupIndex(I, position, mark, channels) {
}
}
-// TODO avoid creating a new clip-path each time?
// Note: may mutate selection.node!
function applyClip(selection, mark, dimensions, context) {
let clipUrl;
const {clip = context.clip} = mark;
switch (clip) {
case "frame": {
- const {width, height, marginLeft, marginRight, marginTop, marginBottom} = dimensions;
- const id = getClipId();
- clipUrl = `url(#${id})`;
- selection = create("svg:g", context)
- .call((g) =>
- g
- .append("svg:clipPath")
- .attr("id", id)
- .append("rect")
- .attr("x", marginLeft)
- .attr("y", marginTop)
- .attr("width", width - marginRight - marginLeft)
- .attr("height", height - marginTop - marginBottom)
- )
- .each(function () {
- this.appendChild(selection.node());
- selection.node = () => this; // Note: mutation!
- });
+ // Wrap the G element with another (untransformed) G element, applying the
+ // clip to the parent G element so that the clip path is not affected by
+ // the mark’s transform. To simplify the adoption of this fix, mutate the
+ // passed-in selection.node to return the parent G element.
+ selection = create("svg:g", context).each(function () {
+ this.appendChild(selection.node());
+ selection.node = () => this; // Note: mutation!
+ });
+ clipUrl = getFrameClip(context, dimensions);
break;
}
case "sphere": {
- const {projection} = context;
- if (!projection) throw new Error(`the "sphere" clip option requires a projection`);
- const id = getClipId();
- clipUrl = `url(#${id})`;
- selection
- .append("clipPath")
- .attr("id", id)
- .append("path")
- .attr("d", geoPath(projection)({type: "Sphere"}));
+ clipUrl = getProjectionClip(context);
break;
}
}
@@ -351,6 +333,35 @@ function applyClip(selection, mark, dimensions, context) {
applyAttr(selection, "clip-path", clipUrl);
}
+function memoizeClip(clip) {
+ const cache = new WeakMap();
+ return (context, dimensions) => {
+ let url = cache.get(context);
+ if (!url) {
+ const id = getClipId();
+ select(context.ownerSVGElement).append("clipPath").attr("id", id).call(clip, context, dimensions);
+ cache.set(context, (url = `url(#${id})`));
+ }
+ return url;
+ };
+}
+
+const getFrameClip = memoizeClip((clipPath, context, dimensions) => {
+ const {width, height, marginLeft, marginRight, marginTop, marginBottom} = dimensions;
+ clipPath
+ .append("rect")
+ .attr("x", marginLeft)
+ .attr("y", marginTop)
+ .attr("width", width - marginRight - marginLeft)
+ .attr("height", height - marginTop - marginBottom);
+});
+
+const getProjectionClip = memoizeClip((clipPath, context) => {
+ const {projection} = context;
+ if (!projection) throw new Error(`the "sphere" clip option requires a projection`);
+ clipPath.append("path").attr("d", geoPath(projection)({type: "Sphere"}));
+});
+
// Note: may mutate selection.node!
export function applyIndirectStyles(selection, mark, dimensions, context) {
applyClip(selection, mark, dimensions, context);
diff --git a/test/output/aaplBollingerCandlestick.svg b/test/output/aaplBollingerCandlestick.svg
index 1115051552..b8a7f75915 100644
--- a/test/output/aaplBollingerCandlestick.svg
+++ b/test/output/aaplBollingerCandlestick.svg
@@ -74,18 +74,15 @@
May
Jun
+
+
+
-
-
-
-
-
-
-
+
@@ -1349,10 +1346,7 @@
-
-
-
-
+
diff --git a/test/output/aaplCloseClip.svg b/test/output/aaplCloseClip.svg
index 8e4130019d..61820798db 100644
--- a/test/output/aaplCloseClip.svg
+++ b/test/output/aaplCloseClip.svg
@@ -82,18 +82,15 @@
22
29
+
+
+
-
-
-
-
-
-
-
+
diff --git a/test/output/armadillo.svg b/test/output/armadillo.svg
index 035971352f..4c9e4ee088 100644
--- a/test/output/armadillo.svg
+++ b/test/output/armadillo.svg
@@ -13,16 +13,13 @@
white-space: pre;
}
+
+
+
-
-
-
-
-
-
-
+
diff --git a/test/output/bandClip.svg b/test/output/bandClip.svg
index 53a7ae4069..8d481ce295 100644
--- a/test/output/bandClip.svg
+++ b/test/output/bandClip.svg
@@ -34,10 +34,10 @@
C
+
+
+
-
-
-
A
B
diff --git a/test/output/bandClip2.svg b/test/output/bandClip2.svg
index a72fafc75e..06d376c3bc 100644
--- a/test/output/bandClip2.svg
+++ b/test/output/bandClip2.svg
@@ -82,10 +82,10 @@
+
+
+
-
-
-
diff --git a/test/output/contourVapor.svg b/test/output/contourVapor.svg
index 338dbdd68d..34f7b908d2 100644
--- a/test/output/contourVapor.svg
+++ b/test/output/contourVapor.svg
@@ -13,10 +13,10 @@
white-space: pre;
}
+
+
+
-
-
-
diff --git a/test/output/differenceFilterX.svg b/test/output/differenceFilterX.svg
index 50b08ac5aa..42528783f9 100644
--- a/test/output/differenceFilterX.svg
+++ b/test/output/differenceFilterX.svg
@@ -63,10 +63,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceFilterY1.svg b/test/output/differenceFilterY1.svg
index 24212d85e7..d0f047f8e9 100644
--- a/test/output/differenceFilterY1.svg
+++ b/test/output/differenceFilterY1.svg
@@ -63,10 +63,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceFilterY2.svg b/test/output/differenceFilterY2.svg
index 7b018f1ff5..5fa3d1a60d 100644
--- a/test/output/differenceFilterY2.svg
+++ b/test/output/differenceFilterY2.svg
@@ -63,10 +63,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceX.svg b/test/output/differenceX.svg
index a6fe21f02c..427afb43dc 100644
--- a/test/output/differenceX.svg
+++ b/test/output/differenceX.svg
@@ -91,10 +91,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceY.svg b/test/output/differenceY.svg
index 7ae5005cd0..0ae2fbf577 100644
--- a/test/output/differenceY.svg
+++ b/test/output/differenceY.svg
@@ -66,10 +66,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceY1.svg b/test/output/differenceY1.svg
index f79da91dd6..151c7955ca 100644
--- a/test/output/differenceY1.svg
+++ b/test/output/differenceY1.svg
@@ -72,10 +72,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYClip.svg b/test/output/differenceYClip.svg
index f258e6c8ff..2fa0ea6368 100644
--- a/test/output/differenceYClip.svg
+++ b/test/output/differenceYClip.svg
@@ -54,10 +54,10 @@
1980
2000
+
+
+
-
-
-
@@ -65,21 +65,15 @@
-
-
-
-
+
-
+
-
+
-
-
-
-
+
diff --git a/test/output/differenceYClipVariable.svg b/test/output/differenceYClipVariable.svg
index 32956f81ec..6e179dcfaa 100644
--- a/test/output/differenceYClipVariable.svg
+++ b/test/output/differenceYClipVariable.svg
@@ -54,10 +54,10 @@
2017
2018
+
+
+
-
-
-
@@ -85,21 +85,15 @@
-
-
-
-
+
-
+
-
+
-
-
-
-
+
diff --git a/test/output/differenceYConstant.svg b/test/output/differenceYConstant.svg
index 163b607c61..60b6fa086e 100644
--- a/test/output/differenceYConstant.svg
+++ b/test/output/differenceYConstant.svg
@@ -74,10 +74,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYCurve.svg b/test/output/differenceYCurve.svg
index c873427c9b..7140e341e3 100644
--- a/test/output/differenceYCurve.svg
+++ b/test/output/differenceYCurve.svg
@@ -80,10 +80,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYNegative.svg b/test/output/differenceYNegative.svg
index 3317d2a59a..8607b76012 100644
--- a/test/output/differenceYNegative.svg
+++ b/test/output/differenceYNegative.svg
@@ -60,10 +60,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYOrdinal.svg b/test/output/differenceYOrdinal.svg
index 4e514a601e..a3c8e33098 100644
--- a/test/output/differenceYOrdinal.svg
+++ b/test/output/differenceYOrdinal.svg
@@ -55,10 +55,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYOrdinalFlip.svg b/test/output/differenceYOrdinalFlip.svg
index ad221b90c9..369d5d630d 100644
--- a/test/output/differenceYOrdinalFlip.svg
+++ b/test/output/differenceYOrdinalFlip.svg
@@ -55,10 +55,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYRandom.svg b/test/output/differenceYRandom.svg
index 600ada5961..b14e35f8f2 100644
--- a/test/output/differenceYRandom.svg
+++ b/test/output/differenceYRandom.svg
@@ -59,10 +59,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYReverse.svg b/test/output/differenceYReverse.svg
index 98efbb5721..f21f52f7e0 100644
--- a/test/output/differenceYReverse.svg
+++ b/test/output/differenceYReverse.svg
@@ -66,10 +66,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYVariable.svg b/test/output/differenceYVariable.svg
index 319ee6fc64..36c5964185 100644
--- a/test/output/differenceYVariable.svg
+++ b/test/output/differenceYVariable.svg
@@ -86,10 +86,10 @@
+
+
+
-
-
-
diff --git a/test/output/differenceYZero.svg b/test/output/differenceYZero.svg
index afdf98ffc5..14db8a3f92 100644
--- a/test/output/differenceYZero.svg
+++ b/test/output/differenceYZero.svg
@@ -66,10 +66,10 @@
+
+
+
-
-
-
diff --git a/test/output/hexbin.svg b/test/output/hexbin.svg
index 293342cceb..a2a2505ea3 100644
--- a/test/output/hexbin.svg
+++ b/test/output/hexbin.svg
@@ -69,10 +69,10 @@
culmen_depth_mm →
+
+
+
-
-
-
diff --git a/test/output/hexbinFillX.svg b/test/output/hexbinFillX.svg
index bfb1a75523..fd80f6f95d 100644
--- a/test/output/hexbinFillX.svg
+++ b/test/output/hexbinFillX.svg
@@ -69,10 +69,10 @@
culmen_depth_mm →
+
+
+
-
-
-
diff --git a/test/output/hexbinIdentityReduce.svg b/test/output/hexbinIdentityReduce.svg
index 9ce724ec63..df736b9267 100644
--- a/test/output/hexbinIdentityReduce.svg
+++ b/test/output/hexbinIdentityReduce.svg
@@ -73,10 +73,10 @@
culmen_length_mm →
+
+
+
-
-
-
diff --git a/test/output/hexbinR.html b/test/output/hexbinR.html
index a4f8fd0414..5ade25928a 100644
--- a/test/output/hexbinR.html
+++ b/test/output/hexbinR.html
@@ -127,27 +127,21 @@
+
+
+
-
-
-
-
-
-
-
+
-
-
-
-
+
diff --git a/test/output/hexbinText.svg b/test/output/hexbinText.svg
index 2cd15de0a3..e91aee982e 100644
--- a/test/output/hexbinText.svg
+++ b/test/output/hexbinText.svg
@@ -93,27 +93,21 @@
+
+
+
-
-
-
-
-
-
-
+
-
-
-
-
+
diff --git a/test/output/hexbinZ.html b/test/output/hexbinZ.html
index 9833c76a21..747c7a9d86 100644
--- a/test/output/hexbinZ.html
+++ b/test/output/hexbinZ.html
@@ -84,10 +84,10 @@
culmen_length_mm →
+
+
+
-
-
-
diff --git a/test/output/hexbinZNull.svg b/test/output/hexbinZNull.svg
index aacf31426f..1ad7df392c 100644
--- a/test/output/hexbinZNull.svg
+++ b/test/output/hexbinZNull.svg
@@ -69,10 +69,10 @@
culmen_depth_mm →
+
+
+
-
-
-
diff --git a/test/output/penguinDensityFill.html b/test/output/penguinDensityFill.html
index 584f9a2c49..95b5d98908 100644
--- a/test/output/penguinDensityFill.html
+++ b/test/output/penguinDensityFill.html
@@ -119,11 +119,11 @@
flipper_length_mm →
+
+
+
-
-
-
@@ -136,10 +136,7 @@
-
-
-
-
+
@@ -152,10 +149,7 @@
-
-
-
-
+
diff --git a/test/output/penguinDensityZ.html b/test/output/penguinDensityZ.html
index bebdd3b075..14edf652dc 100644
--- a/test/output/penguinDensityZ.html
+++ b/test/output/penguinDensityZ.html
@@ -118,11 +118,11 @@
flipper_length_mm →
+
+
+
-
-
-
Adelie
Adelie
@@ -144,10 +144,7 @@
Gentoo
-
-
-
-
+
Adelie
Adelie
@@ -169,10 +166,7 @@
Chinstrap
-
-
-
-
+
Adelie
Adelie
diff --git a/test/output/projectionClipBerghaus.svg b/test/output/projectionClipBerghaus.svg
index 98cba53328..426da50ca4 100644
--- a/test/output/projectionClipBerghaus.svg
+++ b/test/output/projectionClipBerghaus.svg
@@ -13,16 +13,13 @@
white-space: pre;
}
+
+
+
-
-
-
-
-
-
-
+
diff --git a/test/output/rasterVaporEqualEarth.svg b/test/output/rasterVaporEqualEarth.svg
index 0361454e91..fad8839548 100644
--- a/test/output/rasterVaporEqualEarth.svg
+++ b/test/output/rasterVaporEqualEarth.svg
@@ -13,10 +13,10 @@
white-space: pre;
}
+
+
+
-
-
-
diff --git a/test/output/rasterVaporEqualEarthBarycentric.svg b/test/output/rasterVaporEqualEarthBarycentric.svg
index 71241174cd..a5ba2acced 100644
--- a/test/output/rasterVaporEqualEarthBarycentric.svg
+++ b/test/output/rasterVaporEqualEarthBarycentric.svg
@@ -13,10 +13,10 @@
white-space: pre;
}
+
+
+
-
-
-
diff --git a/test/output/roundedRectNegativeX.html b/test/output/roundedRectNegativeX.html
index 04bfce0cab..c254ffa29c 100644
--- a/test/output/roundedRectNegativeX.html
+++ b/test/output/roundedRectNegativeX.html
@@ -102,10 +102,10 @@
Frequency →
+
+
+
-
-
-
diff --git a/test/output/roundedRectNegativeY.html b/test/output/roundedRectNegativeY.html
index bacbed2611..26a42c24c7 100644
--- a/test/output/roundedRectNegativeY.html
+++ b/test/output/roundedRectNegativeY.html
@@ -98,10 +98,10 @@
weight →
+
+
+
-
-
-
diff --git a/test/output/roundedRectNegativeY1.html b/test/output/roundedRectNegativeY1.html
index 3962f3291c..5f78ede10c 100644
--- a/test/output/roundedRectNegativeY1.html
+++ b/test/output/roundedRectNegativeY1.html
@@ -98,10 +98,10 @@
weight →
+
+
+
-
-
-
diff --git a/test/output/trafficHorizon.html b/test/output/trafficHorizon.html
index 16feeac2f5..6a17ffe575 100644
--- a/test/output/trafficHorizon.html
+++ b/test/output/trafficHorizon.html
@@ -50,1531 +50,964 @@
white-space: pre;
}
+
+
+
-
-
-
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
diff --git a/test/output/usStateCapitalsVoronoi.svg b/test/output/usStateCapitalsVoronoi.svg
index c34eef764b..3b77b8a4ec 100644
--- a/test/output/usStateCapitalsVoronoi.svg
+++ b/test/output/usStateCapitalsVoronoi.svg
@@ -66,17 +66,16 @@
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/test/output/usStateCentroidVoronoi.svg b/test/output/usStateCentroidVoronoi.svg
index cc0ca4df88..9d4b20f061 100644
--- a/test/output/usStateCentroidVoronoi.svg
+++ b/test/output/usStateCentroidVoronoi.svg
@@ -67,17 +67,16 @@
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/test/output/usStateGeoCentroidVoronoi.svg b/test/output/usStateGeoCentroidVoronoi.svg
index 2ad229543d..ef0a73c090 100644
--- a/test/output/usStateGeoCentroidVoronoi.svg
+++ b/test/output/usStateGeoCentroidVoronoi.svg
@@ -67,17 +67,16 @@
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/test/output/youngAdults.html b/test/output/youngAdults.html
index f15b78b8a6..630224b643 100644
--- a/test/output/youngAdults.html
+++ b/test/output/youngAdults.html
@@ -386,51 +386,39 @@ …by age and sex. Data: Eurostat
+
+
+
-
-
-
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+