Lines in SVG not the same size despite crispEdges - html
I have an SVG image that is being created and enhanced programatically. After creating it, it is drawn on a Canvas. However, the lines do not seem to have the same width, despite having the same value for stroke-width and the attribute shape-rendering set to crispEdges.
The coordinates are calculated in JavaScript (hence the weird numbers). However, some lines seem to be twice as thick as others (see example below). I don't understand why this happens or how I can fix it.
My best guess is that the calculations are not precise enough and the angle is not actually a perfect 45°, resulting in a thicker line. But when I calculate the slope by hand, it's 45°.
Setting shape-rendering to auto theoretically works, but the circumstances require the lines to be not smooth.
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="80" shape-rendering="crispEdges" stroke-linecap="square" stroke="rgb(0,0,0)" stroke-width="1">
<rect id="background" x="0" y="0" width="3201" height="1677" fill="rgb(255,255,255)" stroke-width="0"/>
<line x1="0.5" y1="71.5" x2="71.2106781186546" y2="0.7893218813452"/>
<line x1="71.2106781186546" y1="0.7893218813452" x2="141.9213562373093" y2="71.5"/>
<line x1="141.9213562373093" y1="71.5" x2="212.632034355964" y2="0.7893218813452"/>
<line x1="212.632034355964" y1="0.7893218813452" x2="283.3427124746186" y2="71.5"/>
</svg>
The purpose of the crispEdges attribute is to accentuate the contrast between edges in your picture, not to ensure that strokes are drawn with the same width.
You probably want to use geometricPrecision instead. However, if it's important to use crisp edges for some reason, try drawing your lines with the same gradients and with their start/end points aligned to the pixel grid (ideally, offset by 0.5 pixels).
Here's your SVG, with minor modifications to ensure the stroke width appears consistent:
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="80" shape-rendering="crispEdges" stroke-linecap="square" stroke="rgb(0,0,0)" stroke-width="1">
<rect id="background" x="0" y="0" width="300" height="80" fill="rgb(255,255,255)" stroke-width="0"/>
<line x1="0.5" y1="71.5" x2="71.5" y2="0.5"/>
<line x1="71.5" y1="0.5" x2="142.5" y2="71.5"/>
<line x1="142.5" y1="71.5" x2="213.5" y2="0.5"/>
<line x1="213.5" y1="0.5" x2="284.5" y2="71.5"/>
</svg>
Related
SVG: applying a filter on a path doesn't work in Chrome [duplicate]
I have the following SVG document: <svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 21 484" xmlns="http://www.w3.org/2000/svg"> <defs> <filter id="dropShadow"> <feDropShadow dx="4" dy="0" stdDeviation="4"></feDropShadow> </filter> </defs> <g id="Artboard" stroke-width="5" stroke="#FF0000" fill="#000000" stroke-linecap="round"> <path style="filter: url(#dropShadow)" d="M7.5,8.5 L7.5,471.5" id="path-1"></path> </g> </svg> In Firefox, when I open the SVG document, it simply shows a very thin (not 5 wide) vertical line. In Chrome, it doesn't show anything (nor does it in codepen, here: https://codepen.io/jwir3/pen/BJBqEK ). I'm not quite sure what I'm doing incorrectly here, but it has something to do with the filter, because, if I remove the filter: url(#dropShadow) from the path definition, the line shows up as expected.
You can't use objectBoundingBox units if your shape has no height or width. Keyword objectBoundingBox should not be used when the geometry of the applicable element has no width or no height, such as the case of a horizontal or vertical line, even when the line has actual thickness when viewed due to having a non-zero stroke width since stroke width is ignored for bounding box calculations. When the geometry of the applicable element has no width or height and objectBoundingBox is specified, then the given effect (e.g., a gradient or a filter) will be ignored. The default for filterUnits is objectBoundingBox units so you need to change that to userSpaceOnUse i.e. <svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 21 484" xmlns="http://www.w3.org/2000/svg"> <title>Line Drop Shadow</title> <description>A red line with 5px width thickness and round caps, having a drop-shadow. This highlights the regression documented in PURP-1017.</description> <defs> <filter id="dropShadow" filterUnits="userSpaceOnUse"> <feDropShadow dx="4" dy="0" stdDeviation="4"></feDropShadow> </filter> </defs> <g id="Artboard" stroke-width="5" stroke="#FF0000" fill="#000000" stroke-linecap="round"> <path style="filter: url(#dropShadow)" d="M7.5,8.5 L7.5,471.5" id="path-1"></path> </g> </svg>
When processing filters, different browsers process in different stroke. Chrome considers stroke as a value with a zero pixel, so it does not include it in the filter region. Therefore, to make the result look the same in different browsers, it is better to replace path with stroke-width ="5", a rectangle with a width of 5px withoutstroke (stroke="none") In addition, the default values for the filter area are: x =" - 10% "" y = "- 10%" `` width = "120%" `` height = "120%"- large blur sizes are usually truncated . By default, filterUnits = "objectBoundingBox" and therefore the values are specified in percentages. To make it easier to calculate the size of the filter region action, specify the value offilterUnits = "userSpaceOnUse" and then you can specify all dimensions for thefilter region` in pixels. <svg preserveAspectRatio="xMinYMin meet" width="100%" height="100%" viewBox="0 0 21 484" xmlns="http://www.w3.org/2000/svg" > <defs> <filter id="dropShadow" filterUnits = "userSpaceOnUse" x="4" y="0" width="12" height="472"> <feDropShadow dx="6" dy="4" stdDeviation="3"></feDropShadow> </filter> </defs> <g id="Artboard" fill="#FF0000" filter="url(#dropShadow)" > <!-- <path style="filter: url(#dropShadow)" d="M7.5,8.5 L7.5,471.5" id="path-1" stroke-width="5" ></path>--> <rect x="5" y="5" width="5" stroke="none" height="463" /> </g> </svg>
Swapping to userSpaceOnUse is the correct answer in most circumstances but has the following limitations: The filter effects region will apply from -10% to 120% of the canvas, rather than the bounding box of the element (using more memory and processing time) For large dynamic SVGs (such as created by d3) it can be hard to calculate the required filter x/y/width/height to ensure the filter applies to all elements. An alternate (less elegant) solution is to apply the filter to a <g> and use a hidden node within this to give the group the correct width or height: <svg xmlns="http://www.w3.org/2000/svg"> <defs> <filter id="dropShadow" width="20"> <feDropShadow dx="4" dy="0" stdDeviation="4"></feDropShadow> </filter> </defs> <g id="Artboard" style="filter: url(#dropShadow)"> <circle r="5" cx="0" cy="0" visibility="hidden"></circle> <path d="M10,10 L10,100" stroke-width="5" stroke="#FF0000" fill="#000000" stroke-linecap="round"></path> </g> </svg>
SVG clipping path scaling
I am currently trying to get an image with an SVG clipping path to scale with the browser (image needs to be 100% of browser width). I have read in several places that applying both clipPathUnits="objectBoundingBox" and transform="scale(0.01)" is the solution, however I am unable to get this to work. Whenever I apply those, the image disappears. No doubt something simple I'm missing? Codepen HTML <img id="preview-img" width="100%" src="http://www.menucool.com/slider/prod/image-slider-4.jpg" style="clip-path: url("#clipPolygon");" class="moving"> <svg width="0" height="0" > <clipPath id="clipPolygon" clipPathUnits="objectBoundingBox" transform="scale(0.01)"> <polygon id="poly1" points="317 343,966 254,964 -6,610 -5"> <animate id="poly1Anim" attributeName="points" dur="500ms" to="" fill="freeze" /> </polygon> </clipPath> </svg> If you remove the two attributes mentioned above, the image shows, however I require the image and path to scale with the browser.
Choosing the right scale: As clipPathUnits="userSpaceOnUse" uses the size of the original path (in absolute pixels) and clipPathUnits="objectBoundingBox" uses 0 to 1 as the coordinate system, the correct scale is scale(1/x, 1/y) So for a svg with coordinates meant for a 1280x800 px image, the correct scale would be: scale(0.00078125, 0.00125)
Turns out the solution was the simple case of adjusting the scale from 0.01 to 0.001! Updated working codepen <img id="preview-img" width="100%" src="http://www.menucool.com/slider/prod/image-slider-4.jpg" style="clip-path: url("#clipPolygon");" class="moving"> <svg width="0" height="0" > <clipPath id="clipPolygon" clipPathUnits="objectBoundingBox" transform="scale(0.001)"> <polygon id="poly1" points="317 543,966 254,964 -6,610 -5"> <animate id="poly1Anim" attributeName="points" dur="500ms" to="" fill="freeze" /> </polygon> </clipPath> </svg>
Adding a stroke to specific edges on SVG polygon
I'm trying to create a custom map marker shape using SVG (created in JS, but for the sake of simplicity I've used the actual HTML here). In this case, I've simply used a circle and a polygon element together to give the effect of a marker, below: <svg xmlns="http://www.w3.org/2000/svg" height="30" width="30"> <circle cx="15" cy="13" r="10" fill="#abcdef" /> <polygon points="5,15 25,15 15,30" fill="#abcdef" /> </svg> This is all well and good. However, I'd like to have a border around the outside of the shape, but if I try to add a stroke to the triangle, which forms the arrow of the marker, I get the line cutting through the circle, as shown: <svg xmlns="http://www.w3.org/2000/svg" height="30" width="30"> <circle cx="15" cy="13" r="10" fill="#abcdef" stroke="#595959" stroke-width="1" /> <polygon points="5,15 25,15 15,30" fill="#abcdef" stroke="#595959" stroke-width="1" /> </svg> I know there are probably many ways to achieve this effect, such as using the path tag, but my SVG knowledge isn't up to that level as of yet. Any pointers are appreciated.
<path> was my first idea. But while fiddling with the arc I got an even simpler idea: <svg xmlns="http://www.w3.org/2000/svg" height="30" width="30"> <circle cx="15" cy="13" r="11" fill="#595959" stroke="none"/> <polygon points="5,16 25,16 15,30" fill="#595959" stroke="none"/> <circle cx="15" cy="13" r="10" fill="#abcdef" stroke="none" /> <polygon points="6,15 24,15 15,28" fill="#abcdef" stroke="none"/> </svg> ...using <circle> and polygon twice, and with filling only. The first set is for the border – hence a little bit larger. The first set is covered by the second set for the actual filling.
svg not sharp, but blurry
For whatever reason these svg files, seems blurry, and not 100% sharp in all browsers. These are svg files, and are enclosed within elements that are scaled to pixels, in other words using px and not % - hence no browser bitmap errors. Any idea as to why this is happening? This is one of the svg files; <?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 361.5 192.5" style="enable-background:new 0 0 361.5 192.5;" xml:space="preserve"> <style type="text/css"> .st0{fill:none;} .st1{fill:#FC5500;} .st2{fill:#FFFFFF;} .st3{fill:#FB5500;} </style> <g> <path class="st0" d="M-9.4-6.3c126,0,252,0,378,0c0,68.7,0,137.3,0,206c-126,0-252,0-378,0C-9.4,131-9.4,62.4-9.4-6.3z"/> <path class="st1" d="M-0.2,112.1c0-8,0-15.9,0-24.4c112.3,0,224.3,0,336.7,0c0-29.4,0-58.4,0-87.7c8.4,0,16.4,0,25,0 c0,46.8,0,93.7,0,140.6c-2.4-0.3-2.5-2.5-3.2-4c-3.7-9-10.3-15-19.3-18.5c-15.2-6-31.2-6.7-47.2-5.5c-7.8,0.6-15.6,1.5-23.1,4.1 c-24.8,8.7-33.9,38-18.3,59.2c5.8,7.8,14.5,10.9,23.4,13.4c2,0.6,4.9-0.1,5.6,3.1c-13.9,0-27.9,0-41.8,0 c-8.1-5.7-14.1-13.6-21.4-20.2c-1.7-1.5-3.8-2.8-4.1-5.5c0.5-2.5,2.8-3.1,4.7-3.9c9.5-4.3,14.3-11.9,14.5-22.1 c0.2-10.1-4.8-17.3-13.9-21.8c-8.5-4.2-17.6-5.3-26.7-5.5c-20.8-0.4-41.6-0.1-62.5-0.1c-1.7,0-3.3,0-4.8,0.8 c-1.6,2.3-1.1,4.9-1.1,7.3c0,21.2,0,42.3,0,63.5c0,2.6,0.5,5.4-1.7,7.6c-32,0-64,0-96.1,0c-3.2-6.9-1.5-13.8-0.9-20.2 c3.1-2.6,6-2.3,8.8-2.3c12.7-0.1,25.3,0,38-0.1c7.8-0.1,15.3-1.6,22.2-5.3c17.8-9.6,18.8-33.3,1.7-44.3c-8.9-5.7-19.1-6.7-29.3-6.9 c-19.3-0.3-38.7,0.1-58-0.1C4.6,113.4,2,113.8-0.2,112.1z"/> <path class="st2" d="M120.6,192.5c0-26.6,0-53.3,0-80.7c29.5,1.5,58.7-2.6,87.6,2.2c13.5,2.2,24.2,9.5,24.9,25.1 c0.6,14.2-6.8,23.1-20.2,27c8.3,8.8,16.5,17.6,24.7,26.4c-11.2,0-22.5,0-33.7,0c-4-1.4-6-5-8.7-7.9c-12.1-13.2-6.6-11-23.7-11.2 c-5.5-0.1-10.9,0-16.4,0c-2,0-4-0.2-6,1c-1.5,3.5-0.5,7.4-0.8,11.1c-0.2,2.4,0.3,5-1.7,7.1C138,192.5,129.3,192.5,120.6,192.5z"/> <path class="st2" d="M203.8,0.7c-4.9,6.4-10,13.1-15.2,20c-18.4,0-36.7,0-55,0c-4.1,0-9-0.2-8.9,5.9c0,6.1,4.8,5.9,9,6 c16.8,0.2,33.7-0.4,50.5,0.6c12.5,0.7,22.4,6.1,22.6,20.9c0.2,14.6-7.3,24.7-22.5,25.3c-28.5,1.2-57.1,0.3-85.9,0.3 c5-6.5,10.1-13.2,15.3-20c19.3,0,38.4,0.1,57.6-0.1c4.4,0,11.3,1.9,11.3-5.3c0.1-7.7-7-5.4-11.6-5.5c-16.1-0.4-32.4,0.3-48.4-0.9 c-13-1-21.7-8.1-21.9-22.5c-0.2-14.9,8.5-23.6,22-24.3C149.5-0.2,176.6,0.7,203.8,0.7z"/> <path class="st2" d="M279.5,192.5c-31.5-9.3-41.2-22.1-36.9-48.9c2.8-17.6,15-26,31-29.7c18.9-4.4,38-4.4,57-0.2 c15.1,3.4,26.5,11.3,31,27c0,7.6,0,15.2,0,22.9c-2.8,16.5-15.6,27.1-34.6,28.6c-1,0.1-2-0.2-2.9,0.3 C309.1,192.5,294.3,192.5,279.5,192.5z"/> <path class="st2" d="M77.2,20.7c-17.1,0-33.9,0-51.1,0c0,3.2,0,6.3,0,9.8c20.5,0,41.1,0,62.9,0c-5.3,6.7-9.8,12.4-14.4,18.2 c-16.2,0-32.1,0-48.5,0c0,3.6,0,7,0,10.8c22,0,44.1,0,67.6,0c-5.9,7.7-11,14.5-16,21.1c-26,0-51.6,0-77.6,0C0,53.7,0,27,0,0 c30.7,0,61.4,0,93,0C87.6,7.1,82.5,13.8,77.2,20.7z"/> <path class="st2" d="M-0.2,112.1c25.3,0.1,50.6-0.4,75.9,0.7c20.2,0.9,32.8,13.2,32.7,29.5c-0.1,16.5-13.5,28.5-34.1,29.3 c-16.3,0.6-32.6,0.1-49.7,0.1c0,7.4,0,14.1,0,20.9c-8.1,0-16.3,0-24.8,0C-0.2,165.6-0.2,138.8-0.2,112.1z"/> <path class="st2" d="M233.3-0.2c18.6,0,37-0.5,55.3,0.1c21,0.7,34.6,13.1,34.6,30.5c0,17.4-13.8,29.5-35.4,30.1 c-15.1,0.5-30.3,0.1-45.9,0.1c0,6.7,0,13.1,0,19.8c-8.6,0-16.6,0-25,0c0-13.4,0-26.6,0-40.7c22.6,0,45.3,0,68.1,0 c5.2,0,10.8-0.6,12.4-6.2c2.6-9.1-3-12.6-11.1-12.7c-22.7-0.2-45.5-0.1-69.4-0.1C222.7,13.3,227.9,6.6,233.3-0.2z"/> <path class="st1" d="M146.7,192.5c0-6.8,0-13.6,0-20.8c13.2,0,26.1,0,39.7,0c5.6,6.6,11.6,13.7,17.6,20.8 C184.9,192.5,165.8,192.5,146.7,192.5z"/> <path class="st3" d="M323.9,192.5c17.1-3.7,32.3-9.9,37.6-29c0,9.5,0,18.9,0,29C349,192.5,336.4,192.5,323.9,192.5z"/> <path class="st3" d="M145.8,150.8c0-5.7,0-11.4,0-17.1c17.9,0,35.6-0.2,53.3,0.2c4.4,0.1,7.8,3.1,7.7,8.3c-0.1,6-4.5,8.4-9.3,8.5 C180.4,151,163.3,150.8,145.8,150.8z"/> <path class="st1" d="M302.2,173.1c-6-0.4-11.4-0.7-16.9-1.1c-12.8-1.1-18.4-8-18.1-20.9c0.3-12.7,7.6-17.4,19-18.6 c11.1-1.1,22.3-1.2,33.4,0.1c11.3,1.3,17.2,7.1,17.3,19c0.1,11.8-5,18.7-16.7,20C314.1,172.4,307.9,172.7,302.2,173.1z"/> <path class="st3" d="M25.1,133c15.6,0,30.9-0.2,46.2,0.1c5.6,0.1,11.1,1.8,11.2,8.7c0.2,7.1-5.2,9.3-11.1,9.4 c-15.3,0.3-30.6,0.1-46.3,0.1C25.1,145.5,25.1,139.6,25.1,133z"/> </g> </svg>
If you want your SVG to be at its sharpest, then design it so that its shapes - especially the horizontal and vertical parts of the shapes - are on pixel boundaries. For example, compare the following two examples: <svg width="50" height="50"> <rect x="9.5" y="9.5" width="31" height="31"/> </svg> <svg width="50" height="50"> <rect x="10" y="10" width="30" height="30"/> </svg> Here's what this looks like at 4X enlargement. Any time your shape passes through the middle of pixels, you will get grey pixels due to the anti-aliasing that 2D renderers use.
The response used a slightly modified code #Paul LeBeau You can use the SVG attribute - shape-rendering =" crispEdges " to disable browser anti-aliasing. https://developer.mozilla.org/ru/docs/Web/SVG/Attribute/shape-rendering crispEdges Indicates that the user agent shall attempt to emphasize the contrast between clean edges of artwork over rendering speed and geometric precision. To achieve crisp edges, the user agent might turn off anti-aliasing for all lines and curves or possibly just for straight lines which are close to vertical or horizontal. Also, the user agent might adjust line positions and line widths to align edges with device pixels. <svg width="50" height="50"> <rect x="9.5" y="9.5" width="31" height="31" shape-rendering="crispEdges"/> </svg> <svg width="50" height="50"> <rect x="10" y="10" width="30" height="30"/> </svg> The image is increased 4 times No gray pixels are observed. Update 2019 by comments There is no universal, 100% solution to the pixelation problem. Since the rendering depends on the installed operating system, its settings, the video card and which browser is used. You can use an integrated approach made up of all the answers of this topic: Use integer svg image coordinate values by answer #Paul LeBeau If you take a finished image with fractional values, you can process it with SVG optimizer Set the integer value of viewBox by answer #AKX Use the attribute shape-rendering ="crispEdges" If a design change is possible, avoid contrasting border colors. For example, use a dark gray color instead of a black and white combination or use shades of gray instead of a pure white background.
I tried the SVG on a page and it doesn't look really blurry to me. However, you could try editing the viewbox to have an integer size -- i.e. turn viewBox="0 0 361.5 192.5" into viewBox="0 0 362 193" -- that might make a difference.
it might be caused by use of borders and shadows in creation of the svg. I avoid those myself as they are sometimes blurry. Shadow if needed can be created as another path with transparency and offset.
SVG coordinates - mask & use & x/y attribute combined
I have a problem with SVG coordinates. I'm sure it's not a bug and it's probably explained somewhere in the documentation and therefore I don't question it. But for my needs I can't find other way to resolve the problem. Now to the point. TL;DR In SVG, this <mask id="myMask" x="0" y="0"> ... </mask> <use xlink:href="..." x="100" y="100" mask="#myMask"> changes the <use> x (or y) position together with the <mask> x (or y) position. I want to keep the <mask> in its place. Longer explanation Background In my web application I have a SVG path. I use it in multiple places so I decided to use the <use> element. Now, in some places I wanted to hide part of the path so I use <mask> element with a rectangle in it. There's also a situation where there is a stack of the same path placed one below another. To achieve this I used the y attribute for one of the <use> elements. The question Unfortunately, when I change the y coordinate of the <use> the <mask> attached to it also changes its y coordinate. The situation doesn't occur on <path> element nor other elements. Below is an example (for simplicity I used <rect> elements). Run the snippet to see four squares placed next to each other (two red and two yellow). The grey overlay represents the mask's boundaries. Squares will rather look like rectangles because they're cut in the half of their height by the <mask>. As you can see in the code, red squares are imported by <use> element and yellow ones are placed directly with <rect> element. Also the second and the fourth square are both moved 500 units downwards. My problem is clearly represented by the second square. It should be cut exactly like the fourth square but I need to do it the <use> way. <svg xmlns="http://www.w3.org/2000/svg" width="200px" height="100px" viewBox="0 0 4000 1000"> <defs> <rect id="svgRect" width="1000" height="1000"></rect> <mask id="svgIconMask10"> <rect x="0" y="0" width="4000" fill="#ffffff" height="500"></rect> </mask> </defs> <!-- Rectangle 1 --> <use xlink:href="#svgRect" y="0" fill="#E5584C" mask="url(#svgIconMask10)"></use> <!-- Rectangle 2 --> <use xlink:href="#svgRect" x="1000" y="300" fill="#E5584C" style="mask: url(#svgIconMask10);"></use> <!-- Rectangle 3 --> <rect x="2000" y="0" width="1000" height="1000" fill="#E5D24C" style="mask: url(#svgIconMask10);"></rect> <!-- Rectangle 4 --> <rect x="3000" y="300" width="1000" height="1000" fill="#E5D24C" style="mask: url(#svgIconMask10);"></rect> <!-- Mask area boundaries --> <rect fill="transparent" stroke="#000" stroke-width="6px" x="0" y="0" width="4000" height="500" /> </svg>
You can apply the mask to a <g /> element and have the <use /> positioned independently: <g style="mask: url(#svgIconMask10);"> <use xlink:href="#svgRect" x="1000" y="300" fill="#E5584C"></use> </g> http://jsfiddle.net/yb1q8dwh/