This question already has answers here:
SVG gradient for perfectly horizontal path
(2 answers)
SVG Line with Gradient Stroke Won't Display if vertical or horizontal
(3 answers)
stroke url not working in Edge and IE 11 SVG
(1 answer)
Closed 12 months ago.
I have a simple sankey diagram created with SVG:
The Codepen for the SVG is here:
https://codepen.io/pi3141592/pen/JjOQReV
The issue:
There should be a linear fill from node2 to node3, which is not appearing. This linear gradient is defined as gradient2, with the relevant path being:
<path class="link" d="M257.5,402.4375C371.25,402.4375 371.25,402.4375 485,402.4375" style="stroke: url("#gradient1"); stroke-width: 180;">
<title>node2 to node3</title>
</path>
Upon investigation, if I change the stroke from linear to solid, eg 'red', then the fill appears:
<path class="link" d="M257.5,402.4375C371.25,402.4375 371.25,402.4375 485,402.4375" style="stroke: red; stroke-width: 180;">
<title>node2 to node3</title>
</path>
I thought, maybe there's something wrong with the defs for the linear gradient, however, if I use one of the other defined gradients that are working (eg gradient0) then it still doesn't appear.
<path class="link" d="M257.5,402.4375C371.25,402.4375 371.25,402.4375 485,402.4375" style="stroke: url("#gradient1"); stroke-width: 180;">
<title>node2 to node3</title>
</path>
I'm baffled as to why the gradient fill won't work for this one particular path. I can't see what could be causing the issue, especially as other linear fills are working.
Related
I'm searching for the simplest definition in svg of a squared number '8', like in the figure below (black inside).
Ways that come to my mind are made of filling several polygons (minimal would be 1 black rectangle and 2 white squares). Is there a way to define it with a single command, specifying all the vertices?
Update: the purpose, BTW, is to create a font from svg files like this one.
You can overlap multiple paths in a single path element and using the fill-rule "evenodd" the intersecting areas will crop. like so:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
<path stroke-width="0" d="M20,20 h20 v35 h-20z M25,25 h10 v10 h-10z M25,40 h10 v10 h-10z" fill-rule="evenodd" />
</svg>
Here is a link that explains how it works.
TL;DR: I need to mask out a portion of one rectangle in SVG, based on the size and position of another existing rectangle, which will be changing dynamically. A Chrome bug is blocking the mask + use approach I tried. How can I do a mask or inverted clip path based on an existing shape?
Full Overview:
I'm using D3.js, and I am using the brush control to add a brush to a rectangle in an embedded SVG. By default, this adds some extra elements to the SVG, including a rect with class extent that shows the size of the brushed area.
Rather than have the brush extent be rendered as a semi-transparent overlay on top of the rectangle, as in most D3 examples, I am trying to "cut out" the extent from a semi-transparent overlay, so that the brush area shows the true color below. Per this question, I am trying to do this with a mask element, with a child use element referencing the extent. With some D3 magic, I now have a structure like this:
<svg width="100" height="100">
<g class="brush-layer inverted">
<defs>
<mask id="mask835">
<rect fill="#fff" width="100%" height="100%"></rect>
<use fill="#000" xlink:href="#extent848"></use>
</mask>
</defs>
<g class="brush" style="pointer-events: none;">
<rect class="overlay" mask="url(#mask835)" width="100%" height="17"></rect>
<rect class="extent" x="30" width="52" height="17" id="extent848"></rect>
</g>
</g>
</svg>
This works great... sort of. It turns out that there appears to be a tricky Chrome bug, which I've filed here, which prevents the mask from being applied if there's a #media query in the CSS. You can see the working version here and the failing version here (fails in Chrome, works in FF).
I need this to work in Chrome, and can't drop the #media query. I also need to make the use element work, because D3 will automatically resize the extent rectangle, and that's the shape I need to mask out.
So, how can I mask out a portion of one rect, based on another rect, without using the mask + use strategy above?
One possible workaround might be to use a custom clip-path, but it's probably not going to be as elegant. Some examples of how to do do this with clip-path can be found in this question.
I have been searching and was curious if any of you smart guys know how I can join two polylines into one polyline. I could simply create another polyline but would like to join them and I haven't found a polyline command that is like the Move to command in Paths.
I don't think there is something like that, maybe there are some ways to do that, but I don't think you can join two separate Polylines with some command. Maybe I'm wrong but I think that the easiest way is to join their points into one polyline tag.
Here is example
Separated polylines:
<svg>
<polyline points="0 0,100 0" style="stroke: black; stroke-width: 3; fill:none;"/>
<polyline points="100 10,100 100" style="stroke: black; stroke-width: 3;fill:none;"/>
</svg>
Мerged polylines:
<svg>
<polyline points="0 0,100 0 100 10,100 100" style="stroke:black; stroke-width:3;fill:none;"/>
</svg>
If you are looking to alter the inherent geometry of the lines the only solution is to use something that is called ''Boolean Operations''.
Boolean operations cannot be performed on lines, only on closed shapes that have an area. So if you actually have a rectangle that is lets say 300 x 1 in size it looks like a line and is available to be boolean-operated on.
There is a nice library I've used before called Javascript Clipper or Clipper in C++
In case this is a one time thing you need just use Inkscape or Illustrator (pathfinder window)
I want to have a rectangle that takes all the place in a SVG file. It should also have a border (3px stroke width). The size of the graphic should be easy changeable (by changing attributes "width" and "height" of the "svg" node). I came up with following construction:
<svg width="150" height="35" >
<g>
<rect
id="rect6648"
style="fill:#ffffff; fill-opacity:1; stroke:#000000; stroke-width:3;"
x="0"
y="0"
width="100%"
height="100%" />
</g>
</svg>
But it produces following image with dirty border:
I need something like this:
Is it possible at all? As mentioned before it must work for any size of the graphic.
Thanks in advance!
Alas, no, at least not with purely declarative SVG. The stroke on a shape is painted on both sides of the geometric line that defines that shape (in your case, there's 1.5 on either side). Because of that, it will get clipped for a shape that fills the whole viewbox.
In which context are you using this? You should be able to script it: get the size of the viewbow, on rect set x and y to stroke-width/2, width to width - stroke-width and height to height - stroke-width. If in a dynamic context you will need to detect resizes, but that's often possible.
You need to place the ractangle at half pixel coordinates like x="0.5" y="0.5", then the borders won't be blurry. Also add vector-effect:non-scaling-stroke to the rectangle's CSS to be sure that the border is always 3px wide regardless of zoom level.
I would like to be able to set the stroke-width on an SVG element to be "pixel-aware", that is always be 1px wide regardless of the current scaling transformations applied. I am aware that this may well be impossible, since the whole point of SVG is to be pixel independent.
Context follows:
I have an SVG element with its viewBox and preserveAspectRatio attributes set. It looks something like this
<svg version="1.1" baseProfile="full"
viewBox="-100 -100 200 200" preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg" >
</svg>
This means that when I scale that element, the actual shapes inside it scale accordingly (so far so good).
As you can see, I have set up the viewBox so that the origin is in the center. I would like to draw an x- and a y-axis within that element, which I do thus:
<line x1="-1000" x2="1000" y1="0" y2="0" />
Again, this works fine. Ideally, though, this axis would always be only 1px wide. I have no interest in the axes getting fatter when i scale the parent svg element.
So am I screwed?
You can use the vector-effect property set to non-scaling-stroke, see the docs. Another way is to use transform(ref).
That will work in browsers that support those parts from SVG Tiny 1.2, for example Opera 10. The fallback includes writing a small script to do the same, basically inverting the CTM and applying it on the elements that shouldn't scale.
If you want sharper lines you can also disable antialiasing (shape-rendering=optimizeSpeed or shape-rendering=crispEdges) and/or play with the positioning.
Here is a more concise answer based on Erik's answer to help you get started quickly.
<div style="background: blue; width: 100%; height: 130px;">
<svg xml:id="root" viewBox="0 0 100 100" width="100%" height="100%" preserveAspectRatio="none">
<rect xml:id="r" vector-effect="non-scaling-stroke" x="0" y="0" width="100" height="100" fill="none" stroke="#88CE02"
stroke-linecap="square" stroke-width="10" stroke-miterlimit="30"/>
</svg>
</div>
Adding the vector-effect="non-scaling-stroke" to the SVG rect makes the border size (or stroke size) fixed.