I need help interpreting the svg which generates this graph paper.
I think I understand the general idea behind the code:
there are 3 layers/groups being created, one of which has the original rectangle
translation and transform operations appear to be used to replicate this rectangle all over the canvas.
but I'm having a hard time understanding some details behind the svg code.
I also don't understand how the layers interact with each other.
Questions
How do you interpret the transform="matrix(0,1,-1,0,400,0)" operation?
Can you explain the implied for-loop that's in this svg code which copies the rectangles?
What does the path tag do in the context of this code?
I am trying to understand this svg code well enough so I can modify it for my own uses.
Thank you.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.0"
width="400"
height="400"
id="svg2180">
<defs
id="defs2182" />
<g
style="opacity:1;display:inline"
id="layer1">
<g
style="stroke:#a9a9a9;stroke-opacity:1"
id="g8191">
<path
d="M 20,0 L 20,400"
style="fill:none;fill-rule:evenodd;stroke:#a9a9a9;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path1872" />
<use
transform="translate(20,0)"
style="stroke:#a9a9a9;stroke-opacity:1"
id="use8185"
x="0"
y="0"
width="400"
height="400"
xlink:href="#path1872" />
<use
transform="translate(40,0)"
style="stroke:#a9a9a9;stroke-opacity:1"
id="use8187"
x="0"
y="0"
width="400"
height="400"
xlink:href="#path1872" />
<use
transform="translate(60,0)"
style="stroke:#a9a9a9;stroke-opacity:1"
id="use8189"
x="0"
y="0"
width="400"
height="400"
xlink:href="#path1872" />
</g>
<use
transform="translate(100,0)"
id="use8197"
x="0"
y="0"
width="400"
height="400"
xlink:href="#g8191" />
<use
transform="translate(200,0)"
id="use8199"
x="0"
y="0"
width="400"
height="400"
xlink:href="#g8191" />
<use
transform="translate(300,0)"
id="use8201"
x="0"
y="0"
width="400"
height="400"
xlink:href="#g8191" />
<use
transform="matrix(0,1,-1,0,400,0)"
id="use8203"
x="0"
y="0"
width="400"
height="400"
xlink:href="#g8191" />
<use
transform="translate(0,100)"
id="use8205"
x="0"
y="0"
width="400"
height="400"
xlink:href="#use8203" />
<use
transform="translate(0,200)"
id="use8207"
x="0"
y="0"
width="400"
height="400"
xlink:href="#use8203" />
<use
transform="translate(0,300)"
id="use8209"
x="0"
y="0"
width="400"
height="400"
xlink:href="#use8203" />
</g>
<g
style="display:inline"
id="layer2">
<g
style="stroke:#366;stroke-opacity:1"
id="g8225">
<path
d="M 100,0 L 100,400"
style="fill:none;fill-rule:evenodd;stroke:#366;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
id="path8215" />
<use
transform="translate(100,0)"
style="stroke:#366;stroke-opacity:1"
id="use8217"
x="0"
y="0"
width="400"
height="400"
xlink:href="#path8215" />
<use
transform="translate(200,0)"
style="stroke:#366;stroke-opacity:1"
id="use8219"
x="0"
y="0"
width="400"
height="400"
xlink:href="#path8215" />
</g>
<use
transform="matrix(0,1,-1,0,400,0)"
id="use8232"
x="0"
y="0"
width="400"
height="400"
xlink:href="#g8225" />
</g>
<g
id="layer3">
<rect
width="399"
height="399"
x="0.5"
y="0.5"
style="fill:none;stroke:#366;stroke-opacity:1"
id="rect10078" />
</g>
</svg>
Don't misinterpret the "layers" in this document. They aren't really about layering, they're about grouping.
How do you interpret the transform="matrix(0,1,-1,0,400,0)" operation?
That is a transformation matrix for an affine transform. It's a fancy way to combine rotation, skew, and translation into one function. They can be difficult to wrap one's mind around though, and I usually only see them used in code generated by a drawing application.
Can you explain the implied for-loop that's in this svg code which copies the rectangles?
In SVG, you can re-use any object that you have given an id to, using the <use .../> tag. This can be used as a sort of DRY, to keep repetition low in the code. In this case, a group of horizontal lines is created, then copies are made by referencing them with use tags. each use has it's own transform attribute to move it into place. Halfway down the list, the line group get rotated 90 degrees (using the transform matrix) and then copied across the image.
What does the path tag do in the context of this code?
It just draws the thick line. This could have been done with a line element, but drawing software output that, and it wasn't smart enough to replace it, I guess. Usually path elements are used for more complex shapes, since they support arcs and bezier curves.
Related
I want to define grouped shapes in the <def> section and display them via the <use> tag with the transformation-origin being the group's center. Following is a minimal example illustrating my issue:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
<defs>
<g id="triangle">
<path fill="green" d="m 24 0 l 24 41.569 l -48 0 z" />
<circle cx="24" cy="24" r="1" fill="red" />
<rect width="48" height="41.569" fill="purple" fill-opacity="20%" />
</g>
</defs>
<rect width="100" height="100" />
<rect fill="gray" x="100" width="100" height="100" />
<rect width="100" height="100" />
<rect fill="gray" y="100" width="100" height="100" />
<rect width="100" height="100" x="100" y="100" />
<use href="#triangle" transform-origin="50% 50%" transform="translate(100 100)" />
</svg>
As it is my understanding, the triangle should be centered in the background. But in actuality, the top left corner of the group is centered.
I have tested my example against the MDN transform-origin one. The MDN one works well in the same environment (Edge Browser & VSCode). This lets me believe I am missing some side effects of the used tags or attributes
Observed behavior
Expected behavior
A scale transform has a centre point i.e. a point that doesn't change position.
So does a rotation - there's a centre of rotation.
A translate transform does not, every location moves. There's therefore no origin so transform-origin does nothing.
I want to center the rect shape with something equivalent to
transform="translate(50% - 100,0)" for example:
<svg width="100%" height="100%" viewbox="0 0 100% 100%">
<g transform="translate(50% - 100,0)">
<rect width="200" height="100" fill="rgb(0,0,255)" />
</g>
</svg>
I can't find the right syntax.
You can use an inner <svg> element to do the percentage part via its x attribute then the rest with the <g> element as you already have.
I'm not sure what you intend with the viewBox but percentage values are not valid there. Looks like you just don't need that at all.
<svg width="100%" height="100%">
<svg x="50%" overflow="visible">
<g transform="translate(-100,0)">
<rect width="200" height="100" fill="rgb(0,0,255)" />
</g>
</svg>
</svg>
I need to apply mask to a different objects.
Mask should cover whole object (visible part of it). I put the mask inside one specific place, at the top of the page, changed maskContentUnits to objectBoundingBox, so it worked perfectly.
But then a problem appeared.
I made a fiddle to illustrate the problem: http://jsfiddle.net/8qdt7vjr/1/
<body>
<svg width="0" height="0">
<defs>
<mask id="mask1" maskContentUnits="objectBoundingBox">
<ellipse cx=".5" cy=".5" rx=".5" ry=".5" fill="white" />
</mask>
</defs>
</svg>
<svg class="svg" width="200" height="150" overflow="visible">
<rect x="-50" y="-50" width="350" height="250" fill="none" stroke="green" stroke-width="2" />
<svg id="zzz" x="0" y="0" width="100%" height="100%" overflow="visible" mask="url(#mask1)">
<rect x="-50" y="-50" width="350" height="250" fill="blue" fill-opacity=".3" />
</svg>
<rect width="100%" height="100%" fill="red" fill-opacity=".1" stroke="red" stroke-width="1" />
</svg>
</body>
In this fiddle i want to apply mask to svg element with id="zzz". But inside this element there is a rect element, that increases zzz's bounding box. In the fiddle it is rect, but in my project it is an image tag. zzz has overflow set to hidden (in the fiddle I changed it to visible, so it is easier to see the problem), so I have a specific portion of image visible inside zzz.
The real problem is that zzz's inner content increases zzz's bounding box.
In the fiddle I want ellipse mask to be inside red rectangle (visible zzz's area), but it is inside green rectangle (zzz's bounding box) instead.
So the main question is: is there any way to achieve this goal? Mask will be used by many elements with different sizes and content and I do not want to clone it.
Is there any way to do this without cloning mask inside each element?
Is there any way to reduce bounding box to visible area?
Is there any way to show a part of an image without expanding parent's bounding box?
Is there any other way to do this?
Is it something like this you try to achieve?
<body>
<svg width="0" height="0">
<defs>
<mask id="mask1" maskContentUnits="userSpaceOnUse">
<ellipse cx="100" cy="75" rx="100" ry="75" fill="white" />
</mask>
</defs>
</svg>
<svg class="svg" width="200" height="150" overflow="visible">
<rect x="-50" y="-50" width="350" height="250" fill="none" stroke="green" stroke-width="2" />
<svg id="zzz" x="0" y="0" width="100%" height="100%" overflow="visible" mask="url(#mask1)">
<rect x="-50" y="-50" width="350" height="250" fill="blue" fill-opacity=".3" />
</svg>
<rect width="100%" height="100%" fill="red" fill-opacity=".1" stroke="red" stroke-width="1" />
</svg>
</body>
Maybe using userSpaceOnUse instead of objectBoundingBox can help achieve what you want... In combination with nested svg elements you can define the userspace to use and with that the part the mask is applied to...
Until recently the following SVG code rendered correctly in Firefox (v25), how ever it doesn't any more (v33). All the other browsers I have tested (Chrome 33, Safari 6, IE 10).
http://jsfiddle.net/9btoveeL/
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="1000px" width="1000px" y="0px" x="0px" version="1.1">
<defs>
<clipPath id="clip1">
<rect height="100" width="10" y="0" x="0"/>
</clipPath>
<clipPath id="clip2">
<rect height="100" width="10" y="0" x="10"/>
</clipPath>
<clipPath id="clip3">
<rect height="100" width="10" y="0" x="20"/>
</clipPath>
<symbol id="fill_texture">
<g>
<rect height="10" width="10" x="0" y="0" fill="#ff0000"/>
<rect height="10" width="10" x="3" y="5" fill="#0ff000"/>
<rect height="10" width="10" x="6" y="10" fill="#0000ff"/>
<rect height="10" width="10" x="9" y="15" fill="#ffff00"/>
<rect height="10" width="10" x="12" y="20" fill="#ff00ff"/>
<rect height="10" width="10" x="15" y="25" fill="#00ffff"/>
</g>
</symbol>
</defs>
<g id="columns">
<use id="unclipped" xlink:href="#fill_texture" width="100" height="100" x="0" y="0"/>
<use id="slot1" xlink:href="#fill_texture" clip-path="url(#clip1)" x="50" y="0"/>
<use id="slot2" xlink:href="#fill_texture" clip-path="url(#clip2)" x="100" y="0"/>
<use id="slot3" xlink:href="#fill_texture" clip-path="url(#clip3)" x="150" y="0"/>
</g>
</svg>
What I'm attempting to do is slice a prepared symbol into three parts and then use those three parts wherever I like. In Firefox 33 it seems it is applying the clip at it's original location (0,0 or 0,10 in my example) while the other browsers and previous versions of Firefox apply the clip starting from the top left corner of the use element it is applied to.
If each clip path must be moved to match the location of the use instead of being treated as relative to it, I can't see how a clip could ever be reused in multiple elements.
The position of a clipping path is by default calculated in the user coordinate system of the object to which it is applied (clipPathUnits="userSpaceOnUse").
(You could set it to clipPathUnits="objectBoundingBox", but then you would have to redefine all the lengths of shapes within the clipping paths to be relative to the height and width of the shape being clipped.)
There is a simple solution to always get the effect you want: transform the coordinate system for the use elements. Instead of positioning them using x and y attributes, position them with a transform="translate(x,y)" attribute. That way, the coordinate system used to position the clipping path will move with them.
Here's your fiddle updated to show the change. It's repeated below as a stack snippet, and should work as expected in all browsers.
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"
xml:space="preserve" version="1.1"
height="100px" width="400px" y="0px" x="0px" >
<defs>
<clipPath id="clip1" >
<rect height="100" width="10" y="0" x="0"/>
</clipPath>
<clipPath id="clip2">
<rect height="100" width="10" y="0" x="10"/>
</clipPath>
<clipPath id="clip3">
<rect height="100" width="10" y="0" x="20"/>
</clipPath>
<symbol id="fill_texture">
<g>
<rect height="10" width="10" x="0" y="0" fill="#ff0000"/>
<rect height="10" width="10" x="3" y="5" fill="#0ff000"/>
<rect height="10" width="10" x="6" y="10" fill="#0000ff"/>
<rect height="10" width="10" x="9" y="15" fill="#ffff00"/>
<rect height="10" width="10" x="12" y="20" fill="#ff00ff"/>
<rect height="10" width="10" x="15" y="25" fill="#00ffff"/>
</g>
</symbol>
</defs>
<g id="columns">
<use id="unclipped" xlink:href="#fill_texture"
width="100" height="100" x="0" y="0"/>
<use id="slot1" xlink:href="#fill_texture" clip-path="url(#clip1)"
transform="translate(50,0)"/>
<use id="slot2" xlink:href="#fill_texture" clip-path="url(#clip2)"
transform="translate(100,0)"/>
<use id="slot3" xlink:href="#fill_texture" clip-path="url(#clip3)"
transform="translate(150,0)"/>
</g>
</svg>
So what should happen when you use x and y instead of transform? It is hard to say, because there is an inconsistency in the specifications.
The Firefox (v33) implementation makes sense from a logical application of the clipping path rules.
When you <use> a <symbol>, you create a new coordinate space for the content within the symbol, but the use element is still in the parent coordinate space. And since it is the use element that is being clipped, that is the coordinate that matters for matching with the clipping path. A use element with an x coordinate of 50 or more will always be outside the clipping paths you give, which don't extend past x=30.
But then, why do the other browsers position the clipping path origin at the <use> element's (x,y) point instead of at the origin of its coordinate system? It's because of the way the specifications define how x and y should be implemented: as an additional transformation added to a grouping element that also has all the other attributes and styles (including clip-path) that you specify on <use>.
According to the specs, the following code:
<use xlink:href="#content" clip-path="url(#clip)"
x="50" y="100" width="50" height="100" />
is supposed to be rendered (assuming "content" is a <symbol>) the same as:
<g clip-path="url(#clip)" transform="translate(50,100)">
<svg width="50" height="100" <!--viewBox and other attributes from the symbol--> >
<!-- graphics from symbol#content go here -->
</svg>
</g>
and under that representation, the clipping path should be translated to match the transform attribute.
However, that is completely different than what would happen if you used an <image> or <rect> instead of <use>, but with the exact same x, y, width, height and clip-path attributes. For these other elements, x and y only define positions within the parent coordinate system, not transformations of the coordinate system, so they do change the origin of the clipping path. Which is why I would call this an unfortunate inconsistency in the specifications.
I'm new to complex SVG and working on something and need help. I have a couple of SVG files that are already properly formatted with content.. lines, rectangles, text, etc. They are drawn with simple X=, Y=, X1=, Y1= and based on just whole numbers. The original SVG was designed for printing and the x/y positions were set based on printing at 300dpi.
So this exists with a couple SVG coming from other origins and I'm trying to merge into a new single SVG document. So, one of these elements, I need to put at position (x,y) based on either inches or centimeters (from what I've read so far), but I also need them to respect a specific size of... say 2 in tall, 3.4in wide.
Since the original SVG was based on just whole numbers and no orientation to "inches", what can I do.. or, how can it self-scale.
Without proper SVG syntax, here's basically some of the details.
SVG1 has an overall x/y rectangle area of 0,0 to 476,100
SVG2 has an overall x/y rectangle area of 0,0 to 273,24
The new SVG needs to be 4" by 6"
Ex: at position 1/4" down, 1" across from the top, I need to insert SVG1, and even though it is 476x100, it needs to be scaled into an area about 1/2" tall x 3" wide.
Similarly,
at position 2.8" down, 1.75" across, I need to insert SVG2, and its size needs to be about 2" tall, and 2.5" wide as a maximum area.
Scaled yes, but not to be skewed, they need to keep their original proportions and not clipped. If I can get the basic understanding, I can tweak the final dimensions, just don't know how to get the infrastructure of this working.
Thanks.
I finally got it after much playing around, just in case anyone is interested and relatively new with SVG as I am. As in the question, I had some pre-generated SVG output files that have their X,Y Height,Width settings all based on numeric value, with no context to inch, centimeter, etc. but my requirement was to fit into a given X inch by Y inch range.
So, I found out about "defs" tag, which is like declaring a variable that can later be used as a "put that thing HERE" within the later SVG body. At the TOP of the SVG, I was able to give the dimensions I needed. Then, by using the "g" tag for grouping, I am able to numerically position something to a given x,y position. Then, within that, I did another "g" to apply a scaling of the "variable" as declared in the "defs" section (as a "g" element can not have two "transform" tags within it).
What I came up with was something like below, and hope the detailed comments can help others in their research dealing with SVG.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Explicitly define the SVG window area as 4 inches by 6 inches -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="4in" height="6in" >
<!-- Add some styles, fonts etc for line drawing, labels and data -->
<style type="text/css" >
<![CDATA[
line.Black
{ stroke:RGB(0,0,0);
stroke-width:2;
}
text.Hdr
{
font-family: Arial;
font-size:x-small;
stroke: #000000;
stroke-width:.4;
}
text.Data
{
font-family: Courier New;
font-size:normal;
stroke: #000000;
stroke-width:.5;
}
]]>
</style>
<!-- all these "defs" are zero-based position for their own content
and will be speicifcally placed where needed via "g" tags.
The simple "id" name will be used as an "insert <something> here" -->
<defs>
<!-- Below will come from actual data from system
The "ID" is what becomes the "variable" that is later
used later in the SVG as the "put me here" -->
<g id="DataOneElement" >
<text class="Data">SOME TEXT DATA</text>
</g>
<!-- This partial linear barcode generated somewhere else
Notice these are just integer positions, and nothing
to do with specific "inches" measurements. Also, they
start at position 0,0 and go however large they need.
When applied with the "g" positioning, thats where it
starts, then gets scaled from there if needed bigger/smaller -->
<g id="DataPartialBarCode" >
<rect x="0" y="0" width="1" height="50" />
<rect x="4" y="0" width="1" height="50" />
<rect x="6" y="0" width="3" height="50" />
<rect x="10" y="0" width="3" height="50" />
<rect x="14" y="0" width="1" height="50" />
<rect x="16" y="0" width="3" height="50" />
<rect x="20" y="0" width="3" height="50" />
<rect x="24" y="0" width="1" height="50" />
<rect x="26" y="0" width="1" height="50" />
<rect x="30" y="0" width="1" height="50" />
<rect x="32" y="0" width="1" height="50" />
<rect x="34" y="0" width="1" height="50" />
<rect x="38" y="0" width="3" height="50" />
</g>
<!-- Actual data generated from AMS to populate these too.
Notice here too, the entire address starts as position 0,0 -->
<g id="SampleAddress" >
<text class="Data" x="0" y="0">Some Person's Name</text>
<text class="Data" x="0" y="17">First Address Line</text>
<text class="Data" x="0" y="30">Another Address</text>
<text class="Data" x="0" y="43">3rd Address line</text>
<text class="Data" x="0" y="56">And Testing for longer address content</text>
</g>
<!-- another bar code that will generated -->
<g id="AnotherBarCode" >
<rect x="0" y="0" width="1" height="70" />
<rect x="4" y="0" width="1" height="70" />
<rect x="6" y="0" width="3" height="70" />
<rect x="10" y="0" width="3" height="70" />
<rect x="14" y="0" width="1" height="70" />
<rect x="16" y="0" width="3" height="70" />
<rect x="20" y="0" width="1" height="70" />
<rect x="24" y="0" width="1" height="70" />
<rect x="26" y="0" width="1" height="70" />
<rect x="28" y="0" width="3" height="70" />
<rect x="32" y="0" width="1" height="70" />
<rect x="36" y="0" width="1" height="70" />
<rect x="38" y="0" width="3" height="70" />
<rect x="42" y="0" width="3" height="70" />
<rect x="46" y="0" width="1" height="70" />
</g>
</defs>
<!-- Now, starting the drawing of the SVG...
Border around entire box drawing area
Notice these are in specific INCH dimensions... -->
<line class="Black" x1="0in" y1="0in" x2="4in" y2="0in" />
<line class="Black" x1="0in" y1="0in" x2="0in" y2="6in" />
<line class="Black" x1="4in" y1="0in" x2="4in" y2="6in" />
<line class="Black" x1="0in" y1="6in" x2="4in" y2="6in" />
<!-- Translate is Across then Down from the top/left corner of SVG -->
<!-- Translate is NOT based on inch, cm, or other measurements
so you may have to tweak these numbers -->
<g transform="translate( 100 20 ) ">
<!-- Now, take whatever we are providing and scale it within the area.
In this case, scale the ENTIRE "g" object to 1.5 its original size -->
<g transform="scale(1.75)">
<!-- This is where the "defs" variable declaration comes
in, as looking at the "g" tag by the ID name -->
<use xlink:href="#DataOneElement" />
</g>
</g>
<!-- and now the partial barcode "defs" variable -->
<g transform="translate( 20 23 ) ">
<!-- In this case, scale the width by 115% and the height by 95% -->
<g transform="scale( 1.15 .95 )">
<use xlink:href="#DataPartialBarCode" />
</g>
</g>
<!-- Any other specific lines within the area -->
<line class="Black" x1="0in" y1=".8in" x2="4in" y2=".8in" />
<!-- Now, just insert the "defs" from above at a scale that will still be readable.
Cool thing, the entire address is considered a single element here. -->
<g transform="translate(20 97)">
<g transform="scale(.7)">
<use xlink:href="#SampleAddress" />
</g>
</g>
<!-- We can even show the address AGAIN, scaled differently elsewhere. -->
<g transform="translate(2 250)">
<g transform="scale(1.3)">
<use xlink:href="#SampleAddress" />
</g>
</g>
<!-- Another line and then barcode-->
<line class="Black" x1="0in" y1="1.55in" x2="4in" y2="1.55in" />
<g transform="translate( 175 175 ) ">
<!-- Scale this barcode 100% wide, but only 70% height -->
<g transform="scale(1 .7)">
<use xlink:href="#AnotherBarCode" />
</g>
</g>
</svg>