-
Notifications
You must be signed in to change notification settings - Fork 185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arbitrary clip paths #1109
Comments
Maybe duplicate of #181. |
I have tried to add I would like to clip an image to a geo path: Plot.image(italy, {
x: (d) => d.properties.lon,
y: (d) => d.properties.lat,
width: (d) => d.properties.width,
height: (d) => d.properties.height,
preserveAspectRatio: "none",
src: (d) => d.properties.flag,
clipPath: (d) => `url(#iso-${d.id})`,
title: (d) => d.id
}) I have some tinkering going on here: https://observablehq.com/d/a8fe9e54cf07cb7a Any thoughts? |
see #1338 |
Here's a snippet that uses the new render transform:
see https://observablehq.com/d/d5d3052622043025 & https://observablehq.com/@fil/diy-live-map-of-air-quality-in-the-us |
That’s really nice @Fil. I bet we could package that up into something reusable. Perhaps a clip transform where you supply a geometry channel, and it uses the geo mark under the hood? |
We should consider using CSS clip-path instead of SVG, since it is now widely supported and much more convenient since you don’t need a globally unique identifier. |
clip-path + path is still very poorly supported: https://observablehq.com/d/bf434fc5675c8f13 |
Chrome doesn't seem to support view-box + polygon(coords)—which works under Safari and Firefox. Chromium bug reference: https://bugs.chromium.org/p/chromium/issues/detail?id=694218 Until this bug is resolved, we probably have to follow the classic route of adding a clipPath with a unique id and url(). An alternative possibility is to wrap the element we want to clip in a SVG element; but it seems more trouble than necessary, and only works for rectangles:
|
The Chrome bug has been fixed in 119 https://chromestatus.com/feature/5068167415595008 https://developer.chrome.com/blog/new-in-chrome-119 The tests in https://observablehq.com/@fil/clip-path-and-basic-shapes-1109 seem to work in all major browsers now, so we could use |
@Fil just helped me with an issue applying clip paths to a faceted Ridgeline plot: Here we used a style to cancel the return svg`<clipPath id=${encodeURI(i.fy)} style="transform: none">${
next(i, s, v, d, c).children[0]
}`; |
Maybe we could offer a Plot.geoClip render transform that you can pass GeoJSON and does this? Plot.plot({
projection: "albers",
color: {scheme: "YlGnBu"},
marks: [
Plot.density(walmarts, {
x: "longitude",
y: "latitude",
bandwidth: 10,
fill: "density",
render(index, scales, values, dimensions, context, next) {
const {document} = context;
const g = next(index, scales, values, dimensions, context);
const clipPath = document.createElementNS("http://www.w3.org/2000/svg", "clipPath");
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
const geoPath = d3.geoPath(context.projection);
path.setAttribute("d", geoPath(nation));
clipPath.setAttribute("id", "clip");
clipPath.appendChild(path);
context.ownerSVGElement.appendChild(clipPath);
g.setAttribute("clip-path", "url(#clip)");
return g;
}
}),
Plot.geo(statemesh, {strokeOpacity: 0.3}),
Plot.geo(nation),
Plot.dot(walmarts, {x: "longitude", y: "latitude", r: 1, fill: "currentColor"})
]
}) E.g., Plot.plot({
projection: "albers",
color: {scheme: "YlGnBu"},
marks: [
Plot.density(walmarts, Plot.geoClip(nation, {x: "longitude", y: "latitude", bandwidth: 10, fill: "density"})),
Plot.geo(statemesh, {strokeOpacity: 0.3}),
Plot.geo(nation),
Plot.dot(walmarts, {x: "longitude", y: "latitude", r: 1, fill: "currentColor"})
]
}) Alternatively, maybe this is what happens when the clip option is set to a GeoJSON object? Plot.plot({
projection: "albers",
color: {scheme: "YlGnBu"},
marks: [
Plot.density(walmarts, {x: "longitude", y: "latitude", bandwidth: 10, fill: "density", clip: nation}),
Plot.geo(statemesh, {strokeOpacity: 0.3}),
Plot.geo(nation),
Plot.dot(walmarts, {x: "longitude", y: "latitude", r: 1, fill: "currentColor"})
]
}) |
"the clip option is set to a GeoJSON object" would be fantastic |
As @jwoLondon remarks in https://observablehq.com/@fil/multiscale-density-spatial-interpolator#comment-451a923b320875f1, the technique with view-box doesn't work in Safari when the page is scaled 😠 |
It’d be nice to support arbitrary clip paths. I can implement one by wrapping a mark like so:
That should probably extend Mark, though? And it should generate a unique identifier rather than using “clip”.
Then I could have a function that creates a clipPath element like so:
Ref. https://observablehq.com/@mjbo/oklab-named-colors-wheel
The text was updated successfully, but these errors were encountered: