Below is a polygon that is defined and then used, with the same linearGradient applied to both it and a line:
- The
polygonisused because there will be many similar lines. - The reason the arrow head uses the gradient fill is because it will be animated along the path of the
lineas the line draws, so the hope is that its fill changes as it moves by virtue ofgradientUnits="userSpaceOnUse". (I plan to use a derivation of this excellent technique.)
(The line will in fact be a more complex multi-angled polyline but this code simplifies things.)
This codepen demonstrates the visual outcome with some variants and notes.
.line {
fill: none;
stroke-width: 60px;
stroke: url(#grad);
}
.head-grad {
fill: url(#grad);
}
<svg viewBox="0 0 1600 200">
<defs>
<polygon id="head" points="0 0, 42 0, 92 50, 42 100, 0 100, 50 50, 0 0"/>
<linearGradient id="grad" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#901500"/>
<stop offset="0.9" stop-color="#eb7500"/>
</linearGradient>
</defs>
<line x1="1540" y1="100" y2="100"/>
<use href="#head" x="1490" y="50"/>
</svg>
Can anyone explain where I am going wrong, or if there is another approach better suited to having the arrow head’s fill match its relative position on the line?
CodePudding user response:
In this example I combine the line and the arrow in a mask. Both elements are white, so 100% transparent. The mask is used on a <rect> that has the gradient. I don't know if this will work in your context? The simple line could be replaced by any other shape like the polyline you talk about.
The animation can be applied to the mask. In the excellent technique I can see that there is a grab between the line and the arrow. With the mask you can avoid this.
<svg viewBox="0 0 1600 200">
<defs>
<polygon id="head" points="0 0, 42 0, 92 50, 42 100, 0 100, 50 50, 0 0"/>
<linearGradient id="grad" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#901500"/>
<stop offset="0.9" stop-color="#eb7500"/>
</linearGradient>
<mask id="m1">
<line x1="1540" y1="100" y2="100" stroke="white" stroke-width="60"/>
<use href="#head" x="1490" y="50" fill="white"/>
</mask>
</defs>
<rect width="1600" height="200" mask="url(#m1)" fill="url(#grad)"/>
</svg>
Update
In the next example I use a mask like the above and animate that. combining a motion path for the arrow head with an animation of the stroke-dasharray on the path.
<svg viewBox="0 0 180 180" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#901500" />
<stop offset="0.9" stop-color="#eb7500" />
</linearGradient>
<path id="curve" d="M 20 130 L 40 80 L 60 90 L 80 60 L 100 80 L 120 30 L 140 40 L 160 10" fill="none" pathLength="100" />
<mask id="m1">
<use href="#curve" stroke-dasharray="0 0" stroke="white" stroke-width="3">
<animate attributeName="stroke-dasharray" values="0 100;100 100" dur="6s" fill="freeze" />
</use>
<path d="M -3 -3 L -0.5 -3 L 3 0 L -0.5 3 L -3 3 L 0 0 Z" fill="white">
<animateMotion dur="6s" fill="freeze" rotate="auto">
<mpath href="#curve" />
</animateMotion>
</path>
</mask>
</defs>
<rect width="100%" height="100%" fill="url(#grad)" mask="url(#m1)" />
</svg>
CodePudding user response:
@chrwahl has kindly offered some answers, but as my arrowheads are being transformed along their paths with translate(x,y), I've ended up deploying gradientTransform="translate(-x,0)" on a linearGradient dedicated to each arrowhead.
The outcome is shown in this codepen.
Code excerpts, without accompanying JS, from that pen here:
.rarr__line {
fill: none;
stroke-width: 60px;
}
.rarr-bg {
fill: #901600;
}
.rarr-3 .rarr__line {
stroke: url(#rgrad-3l);
}
.rarr-3 .rarr__head {
fill: url(#rgrad-3h);
}
<svg viewBox="0 0 1600 900">
<defs>
<symbol id="rarr" viewbox="0 0 92 100">
<polygon points="0 0, 42 0, 92 50, 42 100, 0 100, 50 50, 0 0" />
</symbol>
<linearGradient id="rgrad-3l" y1="380" x2="1540" y2="380" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#901500"/>
<stop offset="1" stop-color="#eb7500"/>
</linearGradient>
<linearGradient id="rgrad-3h" y1="380" x2="1540" y2="380" gradientUnits="userSpaceOnUse" gradientTransform="translate(-1490,0)">
<stop offset="0" stop-color="#901500"/>
<stop offset="1" stop-color="#eb7500"/>
</linearGradient>
</defs>
<rect width="1600" height="900"/>
<g >
<polyline points="0 430, 1000 430, 1100 330, 1540 330" />
<use href="#rarr" viewbox="0 0 92 100" width="92" height="100" x="1490" y="280" data-grad="rgrad-3h" />
</g>
</svg>
