Minimal svg definition of a polygon with empty squares inside - svg

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.

Related

Styling SVG elements with stroke and globally-positioned pattern

Goal
I am trying to replicate this effect algorithmically:
This is for a project I am working on where I need to make stylised visualisations of different kinds of pizza. The image shows a Margherita (tomato base, mozzarella and basil on top).
The rules I need to adhere to:
each ‘layer’ consists of uniformly positioned objects with a stroke and filled with a pattern (that shares coordinates)
the layers need to cover lower layers
Means
To achieve the uniform distribution, I use Poisson-Disc sampling.
I chose SVG because I need the result to be visible in the browser and generate this server-side.
For efficiency and simplicity – as the viewing size will be smaller – I decided to reference one object with <use> elements and vary it only with rotations, as opposed to the sample.
Attempts
Every approach I tried reached a dead end:
Creating a <clipPath> filled with <use> elements for clipping the background.
This does not allow me to add a stroke around the clipped area, which I need. A workaround would be to use a feMorphology filter, but that seems like it’s going to be needlessly costly on the client. A second workaround seemed to be:
Grouping the elements and using that group twice: once in a <clipPath> for clipping the pattern background, once directly on the canvas with an added stroke.
This does not work as <g> elements are unsupported in web browsers due to completely arbitrary reasons (it does work in Inkscape, however, which I used for the proof-of-concept). A workaround would be to use two copies of all the <use> elements, but that would essentially double the file size.
Grouping the elements and applying a fill with SVG patterns.
This does not work as since we create the distribution using <use> elements, the pattern looks identical in every instance. Moreover, I cannot rotate the objects, as the pattern would get rotated too. A workaround would be not to use <use>, but that would create the same problem as in point 2.
Those approaches won't work because patterns are affected by any transforms applied to the same shape.
In the solution below, we create a whole layer of an ingredient (id="basil-layer"). Then use that layer to first draw the ingredient outlines (strokes). Then afterwards we use a mask, created from that same layer, to draw hatching on top of the outlines.
You'll need to duplicate this process for each of the ingredients.
More documentation of what's happening inside the code.
<svg width="600" height="400">
<defs>
<pattern id="diagonalHatch" patternUnits="userSpaceOnUse" viewBox="0 0 4 4" width="16" height="16">
<rect fill="black" width="4" height="4"/>
<path d="M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2"
style="stroke:green; stroke-width:0.5" />
</pattern>
<!-- Definition for a leaf of basil -->
<ellipse id="basil" cx="0" cy="0" rx="60" ry="30"/>
<!-- A layer of N pieces of basil -->
<g id="basil-layer">
<use xlink:href="#basil" transform="translate(300,200)"/>
<use xlink:href="#basil" transform="translate(400,150) rotate(45)"/>
<use xlink:href="#basil" transform="translate(450,200) rotate(110)"/>
</g>
<!-- A mask that consists of all the pieces of basil -->
<!-- The fill is white to keep the *insides* of the basil shape.
And we stroke with black so that this mask doesn't hide any of the
green stroke outline of the leaf, when use this mask to lay down
the hatch pattern on top of the drawn basil leaves. -->
<mask id="basil-layer-mask">
<use xlink:href="#basil-layer" fill="white" stroke="black" stroke-width="2"/>
</mask>
</defs>
<!-- Fill SVG with a black background -->
<rect width="100%" height="100%" fill="black"/>
<!-- Draw all the basil pieces with a black fill and a green outline -->
<use xlink:href="#basil-layer" fill="black" stroke="green" stroke-width="2"/>
<!-- Finally draw the basil layer hatching.
This is a whole-SVG sized rectangle of hatching masked by the basil layer mask -->
<rect width="100%" height="100%" fill="url(#diagonalHatch)" mask="url(#basil-layer-mask)"/>
</svg>

SVG path with transparent fill becomes grey with TCPDF

I have a number of SVG images being inserted into a PDF file using TCPDF. For example:
<path d="M0 100 L 80 100 L 40 27 L 0 100" stroke="black" fill="transparent" stroke-width="5" />
The problem is that TCPDF seems to turn any transparency to grey. How can I make it transparent? I cannot simply turn it to white as it is being placed on top of other data as well.
Many of the shapes are complex, utilizing bezier curves and stroke arrays so I need to use a path rather than lines, polygons, or polylines.
I think this might not be possible, but I have found a workaround. Rather than setting
fill="transparent"
I just use:
fill="none"
or
fill-opacity="0"
This seems to work fine. Both can be found on this page:
How to make an SVG element transparent (using SVGweb)

What's the difference in accessibility between having SVG inline or as an image?

I am developing a web page trying to focus on accessibility, and created different graphics in SVG to go in it. After reading different sites online (1, 2, and 3), I included the <title> and <desc> tags, and added the attributes role and aria-labelledby to make the SVGs more accessible.
Some of those sources, seem to claim (directly or indirectly) that using SVG inline is better for accessibility; so I ran a few tests with NVDA to see the differences, but I fail to see any at first sight.
For example, using a simple SVG:
<svg width="100" height="100" viewBox="0 0 100 100" role="img" aria-labelledby="title desc">
<title id="title">Abstract Forms</title>
<desc id="desc">Red square containing a white circle containing a blue triangle pointing up.</desc>
<g stroke="none" stroke-width="0">
<rect x="0" y="0" width="100" height="100" fill="red" />
<circle cx="50" cy="50" r="40" fill="white" />
<path d="M 50,20 80,70 20,70 Z" fill="blue" />
</g>
</svg>
If I add it to the page like that, NVDA reads "Graphic. Abstract Forms. Red square containing a white circle containing a blue triangle pointing up."
And if I save it into a myImg.svg file, and add it to the page like this:
<img src="myImg.svg" alt="Red square containing a white circle containing a blue triangle pointing up" title="Abstract Forms" />
NVDA then reads "Graphic. Red square containing a white circle containing a blue triangle pointing up." (same thing as before, just not reading the title).
This may be an NVDA thing, and other screen readers may do it differently, but there doesn't seem to be any considerable difference between the two. At least not to claim that inlining the SVG is better for accessibility.
Then I thought it could be related to reading additional information; for example, if there was some text within the graphic. So I added a <text x="50" y="50" fill="black">Hello World</text> at the end of the SVG... but NVDA read the same thing as before; not even selecting the text it will read it (again I don't know if this is an NVDA thing and if other screen readers do it differently).
So my questions are: what are the differences between having SVG inline or as an image? And what are the benefits (for accessibility) of having the SVG inline?
You probably already self-answered your question.
Inline-svg is interpreted as part of the html webpage. So your svg title and description are interpreted as well and read by the screen reader.
When using an ‘img‘ tag to include the svg, the file is handled like an external file (like a jpg) and so only the ‘alt‘ attribute of the img tag (= the image description) is interpreted/read by the screen reader.
I have currently no source and can't test it a the moment, but I think there are also differences for links within the svg code: Links within inline svg are read by the screenreader, links within external svg files not.

Better way to position svg:polygon

The SVG elements <line>, <circle>, <rect>, <text> and , <image> allow for positioning by x and y based off of the view port. Furthermore they can also be relatively positioned. Is there any way to accomplish this for <polygon> than to wrap it in an <svg>? The closest substitute for <polygon>, <path>, also has this... issue.
Based on the excellent comment by #Michael Mullany I was able to find a solution to the issue. By putting the polygon or path in side a <defs> tag it can be used later on in a <use> tag. The <use> tag allows for setting of x and y attributes that function the same as the attributes of other simple shapes like <line>, <circle>, <rect>, <text>
http://jsbin.com/iqEkAsE/2
<svg width="100%" height="100%">
<defs >
<path id="Triangle"
d="M 1 1 L 200 1 L 100 200 z"
fill="orange"
stroke="black"
stroke-width="3" />
</defs>
<use x="33%" y="33%" xlink:href="#Triangle"/>
<use transform="scale(-1)" x="-66%" y="-66%" xlink:href="#Triangle"/>
</svg>
It would be nice to be able to scale the shape dynamically by setting the width and height property of the <use> to a percent but it can still be scaled with a transform.
Use transformations (translation, rotation, scale), that is the correct way to do it.
The other shapes allow you to use a point defined by x,y coordinates because that's just a part of the shape definition (i.e. how do you define a circle, you need the center point and the radius).
In theory you could position an element using its bounding box, however the bounding box is not "settable" (there is no setBBox method), there is only getBBox()

Avoid line between tiled SVG shapes

I am using multiple differently colored rectangles to build a SVG data visualization. This works great but sometimes background color bleeds through between the rectangles. I am browsing with Chrome but other browsers seem similarly affected.
http://jsfiddle.net/dVEPk/
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect x="10.5" y="10" height="100" width="100"
style="stroke:none; fill: #00cc00"/>
<rect x="110.5" y="10" height="100" width="100"
style="stroke:none; fill: #00cc00"/>
</svg>
In Chrome, if the x offset is an integer, the line is not visible.
I'm sure I can avoid lines by making rectangles a little larger than the space they have to occupy. But this seems like a hack: is there an SVG idiom or best practice to achieve perfectly tiled shapes without "grout"?
I'm also concerned by rendering performance because my visualizations can be very large (say 100MB XML .svg). I'd like to be able to give the renderer hints like "none of the shapes in this <g> are overlapping"?
This is antialiasing at work between the shape and the background. If you want to turn it off set shape-rendering="crispEdges" on the shapes. You can either set that on the rect elements or on the <svg> in which case the rect elements will inherit it.
You may be able to adjust the line's positions by adding 0.5 to the co-ordinates. See the cairo FAQ for more details on this.

Resources