SVG scaled within SVG at specific location(s) - svg

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>

Related

(SVG) Transform origin of grouped path element is not getting applied

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.

SVG how to set max width for group

I have some SVG elements grouped together in a <g> element (exactly the barcode 1D, PHP generates a barcode).
<g
style="fill:#000000;stroke:none"
id="barcode1D"
transform="matrix(1.2083333,0,0,0.8247805,62.027778,573.54235)">
<rect
x="0"
y="0"
width="4"
height="30"
id="xyz" />
....
<rect
x="224"
y="0"
width="0"
height="30"
id="xyzn" /> </g>
The barcode is generated in various widths, lengths. How can I set the width permanently ?
Based on this example, I am asking for a hint. Thank you for your help in advance.
SVG g element does not have width and height attributes. Therefore, you can not set height and width on it.
You should use a foreignObject with a svg inside of it to do so.
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
<foreignObject id="G" width="300" height="200">
<svg>
<!-- Barcode here -->
<rect fill="black" stroke-width="2" height="112" width="84" y="55" x="55" stroke="#000000"/>
<circle fill="#FF0000" stroke="#000000" stroke-width="5" cx="155" cy="65" id="svg_7" r="50"/>
</svg>
</foreignObject>
</svg>

how to reuse a svg element and resize

I have a rectangle
<rect id="greenRect" fill="lightgreen" height="20" width="20"/>
Now I want to reuse the rect, but make it bigger
<use href="#greenRect" y="150" height="50" width="50"/>
The size (height/width) don't seem to get overwritten from the original <rect> element.
How would I achieve such a thing?
Solution 1: Wrap the rect in a <symbol> with a viewBox attribute.
<symbol id="greenRect" viewBox="0 0 20 20">
<rect fill="lightgreen" height="20" width="20"/>
</symbol>
<!-- symbols are not rendered, so if you want to see your original,
you have to also use it -->
<use href="#greenRect" height="20" width="20"/>
<use href="#greenRect" y="150" height="50" width="50"/>
Solution 2: scale and translate your rectangle
<rect id="greenRect" fill="lightgreen" height="20" width="20"/>
<!-- transformation are applied right-to-left -->
<use href="#greenRect" transform="translate(0 150) scale(2.5)"/>

svg mask and bounding box

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...

How to interpret graph-paper generating svg?

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.

Resources