Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/chart/chart.css
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,6 @@
fill: var(--text-2);
}

.gv-photo-frame {
clip-path: circle(50%);
}

.gv-photo-ring {
fill: none;
stroke: var(--border);
Expand Down
18 changes: 16 additions & 2 deletions src/chart/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ const NAME_TOP = PAD + PHOTO + 10 + 14; // baseline of the first name line
const NAME_LINE = 18.5;
/** Life dates are set at 13px regular; `measure` is the 15px medium name font. */
const LIFE_SCALE = 0.85;
/** Numbers the portraits' clip paths: each needs an id of its own. */
let clipCount = 0;

export interface RendererContext {
tree: LoadedTree;
Expand Down Expand Up @@ -404,7 +406,19 @@ export class GedviewRenderer extends CompositeRenderer implements Renderer {
// A shown photo opens the media viewer (pointer only: on the keyboard
// the card's portrait does it).
p.attr('data-photo', '');
const frame = p
// The circle is cut by a clip path on a group, not by CSS on the frame:
// Firefox lays CSS clip-path shapes out inside the frame's view box, so
// a crop away from the image's corner cut the whole photo away.
const r = PHOTO / 2;
const id = `gv-photo-clip-${++clipCount}`;
p.append('clipPath')
.attr('id', id)
.append('circle')
.attr('cx', r)
.attr('cy', r)
.attr('r', r);
const clipped = p.append('g').attr('clip-path', `url(#${id})`);
const frame = clipped
.append('svg')
.attr('class', 'gv-photo-frame')
.attr('width', PHOTO)
Expand Down Expand Up @@ -432,7 +446,7 @@ export class GedviewRenderer extends CompositeRenderer implements Renderer {
image.attr('width', PHOTO).attr('height', PHOTO);
}
image.on('error', () => {
frame.remove();
clipped.remove();
p.attr('data-photo', null);
});
}
Expand Down
9 changes: 9 additions & 0 deletions tests/e2e/photos.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ test('people with a photo show it on the chart, cropped, or their initials', asy
'viewBox',
'1 1 2 2',
);
// The circle is a clip path on a group around the frame: a CSS clip-path
// on the frame itself hides a cropped photo in Firefox.
await expect(annaPhoto.locator('g[clip-path] > .gv-photo-frame')).toHaveCount(
1,
);
await expect(annaPhoto.locator('.gv-photo-frame')).toHaveCSS(
'clip-path',
'none',
);
await expect(annaPhoto.locator('.gv-photo-ring')).toHaveClass(/gv-F/);
// The image failed: the initials stay.
await expect(petrPhoto.locator('.gv-photo-frame')).toHaveCount(0);
Expand Down
Loading