Search code examples
svgscale

SVG scaled within SVG at specific location(s)


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.


Solution

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