My question: Can svg <marker>
elements inherit color from the <line>
they are referenced on?
The background: I have a D3 graph that has different styled lines, and I want my lines to have arrows at the end.
So at the top of my <svg>
I have const defs = svg.append('defs');
and then further along I generate my defs using a generator function:
function makeDefs(defs: Selection<SVGDefsElement, unknown, null, undefined>, color: string, status: string) {
const markerSize = 3
const start = defs.append
.append('marker')
.attr('id', `arrow-start-${color}-${status}`)
.attr('viewBox', '-5 -10 20 20')
.attr('markerWidth', markerSize)
.attr('markerHeight', markerSize)
.attr('orient', 'auto-start-reverse');
start
.append('path')
.attr(
'd',
status === 'PUBLISHED' ? customPaths.arrowLarge : customPaths.arrowSmall
)
.attr('stroke', color)
.attr('fill', color);
}
And use it like so:
makeDefs(defs, 'red', 'DRAFT');
And then I add the markers to my lines with:
// d3 code to draw the lines etc
line.attr(
'marker-start',
(d) =>
`url(
#arrow-start-${d.color}-${d.status}
)`
);
This all works great, my arrows have lines. But my current setup feels burdensome and clunky. I have about 20 colors and 3 statuses. With my current setup that would be 60 different:
makeDefs(defs, 'one-of-20-colors', 'one-of-3-statues');
My understanding of markers
is that they can inherit color using the currentcolor
attribute. Currently my <defs>
sit up top underneath my main <svg>
so any color inherited is inherited directly from that top level svg which is not what I want. The issue in my case is my <line>
elements are the elements who's color I want to inherit, but according to the MDN docs <line>
s cannot have <defs>
as children, thus leaving me with the only option, of defining all my <defs>
up front all at once.
Is there a trick or some attribute I'm missing here?
Any way to pass color to my marker when doing:
line.attr(
'marker-start',
(d) =>
`url(
#arrow-start-${d.color}-${d.status}
)`
);
?
For what is is worth, I'm currently wrapping all my <line>
s in <g>
. I suppose I could wrap them in <svg>
s instead, and apply the fill
and stroke
there, and then define my <defs>
per svg container? I tried this briefly and swapping the <g>
for an <svg>
broke a lot, but I'm not even sure if it would work, or be better for that matter.