Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a SVG where everything scales except text

Tags:

svg

To illustrate the effect I'm after, say we scale the image vertically:

Before:

example 1

After:

example 2

Note the text doesn't distort. I'm looking for an easier alternative to drawing and positioning the elements manually each time the scale changes, particularly where the text stays the same dimensions, and I thought svg could pull this off...

like image 504
CrazyTim Avatar asked Sep 24 '12 04:09

CrazyTim


People also ask

How do I scale an SVG element?

Just set the viewBox on your <svg> , and set one of height or width to auto . The browser will adjust it so that the overall aspect ratio matches the viewBox .

Can SVG be stretched?

An SVG image with fixed dimensions will be treated just like a raster image of the same size. Note: If you are trying to stretch your SVG to a different aspect ratio with CSS—for example in order to stretch it over the page background—make sure your SVG includes preserveAspectRatio="none" .

Can SVG contain text?

The SVG <text> element draws a graphics element consisting of text. It's possible to apply a gradient, pattern, clipping path, mask, or filter to <text> , like any other SVG graphics element. If text is included in SVG not inside of a <text> element, it is not rendered.

How do I make SVG fit inside a div?

“In the SVG declaration after the doctype, simply remove the width and height attributes. This forces the browser to always fill the containing DIV or box with your SVG.”


1 Answers

Long time since this question has been made. I think that is not possible without JavaScript. If you do not have problems with the use of JavaScript, use this plugin. The plugin gets all svg elements with an specific class and creates on each element a transformation matrix:

This plugin requires that the svg has the viewBox option. It is a start point, you could adapt it to your needs ;)

(function($){
    
    var defaults = { class: "no-scale" };
    
    var methods = {
        
        //---Init method
        init: function(){
        
            //---Conform the settings
            var settings = $.extend({}, defaults);
            
            return this.each(function(index){
            
                //---Get the SVG
                var svg = $(this);
                
                //---Get the viewBox (svgRect)
                var viewBox = (svg[0].viewBox == undefined) ? false : svg[0].viewBox.animVal;
                
                //---Store the data
                svg.data({"viewBox": viewBox, settings: settings});

                //---Call to private function of resize elements
                private.updateSizes(svg);
            
            });
        
        },
        
        refresh: function(){
        
            return this.each(function(index){
            
                //---Get the SVG
                var svg = $(this);

                //---Call to private function of resize elements
                private.updateSizes(svg);
            
            });
        
        }
        
    };
    
    var private = {
    
       updateSizes: function(svg){
           
           //---Get the viewBox (svgRect)
           var viewBox = svg.data("viewBox");
           
           if(!viewBox) return;
       
           //---Get the settings
           var settings = svg.data("settings");
           
           //---Global scale
           var scalew = Math.round((svg.width() / viewBox.width) * 100) / 100;
           var scaleh = Math.round((svg.height() / viewBox.height) * 100) / 100;
           
           //---Get the resized elements
           var noScaleElements = svg.find("." + settings.class);
           
           noScaleElements.each(function(){
               
               var el = $(this);
               
               //---Set variables
               var sw = el.width();
               var sh = el.height();
               var sx = Math.round((1 / scalew) * 100) / 100;
               var sy = Math.round((1 / scaleh) * 100) / 100;
               var tx = Number( el.attr("x") ) * (1 - sx) + ((sw - sw * sx) / 2) * sx;
               var ty = Number( el.attr("y") ) * (1 - sy) + ((sh * sy - sh) / 2) * sy;
               
               var matrix = "matrix(" + sx + ",0,0," + sy + "," + tx + "," + ty + ")";
           
               $(this).attr("transform",  matrix);
           
           });
       
       }
    
    };
    
    $.fn.noScaleSVGElements = function(method){

        // Method calling logic
        if (methods[method] ) {
            
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
            
        } else if ( typeof method === 'object' || ! method ) {
            
            return methods.init.apply( this, arguments );
            
        } else {
            
            $.error( 'Method ' +  method + ' does not exist on jQuery.noScaleSVGElements' );
            
        }

    }
        
})(jQuery);

To use the plugin:

//---Code
$("#svg-element").noScaleSVGElements();

//---Call this method every time that the sizes need to be recalculated
$("#svg-element").noScaleSVGElements("refresh");

Here you have a snippet, change the window size and check the result:

//---Plugin jQuery
(function($){
    
    var defaults = { class: "no-scale" };
    
    var methods = {
        
        //---Init method
        init: function(){
        
            //---Conform the settings
            var settings = $.extend({}, defaults);
            
            return this.each(function(index){
            
                //---Get the SVG
                var svg = $(this);
                
                //---Get the viewBox (svgRect)
                var viewBox = (svg[0].viewBox == undefined) ? false : svg[0].viewBox.animVal;
                
                //---Store the data
                svg.data({"viewBox": viewBox, settings: settings});

                //---Call to private function of resize elements
                private.updateSizes(svg);
            
            });
        
        },
        
        refresh: function(){
        
            return this.each(function(index){
            
                //---Get the SVG
                var svg = $(this);

                //---Call to private function of resize elements
                private.updateSizes(svg);
            
            });
        
        }
        
    };
    
    var private = {
    
       updateSizes: function(svg){
           
           //---Get the viewBox (svgRect)
           var viewBox = svg.data("viewBox");
           
           if(!viewBox) return;
       
           //---Get the settings
           var settings = svg.data("settings");
           
           //---Global scale
           var scalew = Math.round((svg.width() / viewBox.width) * 100) / 100;
           var scaleh = Math.round((svg.height() / viewBox.height) * 100) / 100;
           
           //---Get the resized elements
           var noScaleElements = svg.find("." + settings.class);
           
           noScaleElements.each(function(){
               
               var el = $(this);
               
               //---Set variables
               var sw = el.width();
               var sh = el.height();
               var sx = Math.round((1 / scalew) * 100) / 100;
               var sy = Math.round((1 / scaleh) * 100) / 100;
               var tx = Number( el.attr("x") ) * (1 - sx) + ((sw - sw * sx) / 2) * sx;
               var ty = Number( el.attr("y") ) * (1 - sy) + ((sh * sy - sh) / 2) * sy;
               
               var matrix = "matrix(" + sx + ",0,0," + sy + "," + tx + "," + ty + ")";
           
               el.attr("transform",  matrix);
           
           });
       
       }
    
    };
    
    $.fn.noScaleSVGElements = function(method){

        // Method calling logic
        if (methods[method] ) {
            
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
            
        } else if ( typeof method === 'object' || ! method ) {
            
            return methods.init.apply( this, arguments );
            
        } else {
            
            $.error( 'Method ' +  method + ' does not exist on jQuery.noScaleSVGElements' );
            
        }

    }
    
})(jQuery);

//---Code
$("#container svg").noScaleSVGElements();

$(window).resize(function(){

    $("#container svg").noScaleSVGElements("refresh");

});
html, body{
    height: 100%;
}
body{
    margin: 0;
    padding: 0;
}
#container {
    width: 100%;
    height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
    <svg x="0px" y="0px" width="100%" height="100%" viewBox="0 0 150 150" preserveAspectRatio="none">
    <polyline fill="#FFFFFF" stroke="#231F20" stroke-width="1.2241" stroke-miterlimit="10" points="29.333,11.223 136.223,11.223 
        136.223,138.777 29.333,138.777 " vector-effect="non-scaling-stroke"/>
    <line fill="none" stroke="#231F20" stroke-width="1.2241" stroke-miterlimit="10" x1="135.447" y1="75" x2="30.109" y2="75" vector-effect="non-scaling-stroke"/>
    <text class="no-scale" x="5.1113" y="14.7451" font-family="'MyriadPro-Regular'" font-size="12">100</text>
    <text class="no-scale" x="5.1113" y="78.5215" font-family="'MyriadPro-Regular'" font-size="12">50</text>
    <text class="no-scale" x="5.1113" y="142.2988" font-family="'MyriadPro-Regular'" font-size="12">0</text>
</svg>
</div>
like image 116
ElChiniNet Avatar answered Oct 30 '22 04:10

ElChiniNet