创建一个SVG图像,其中所有元素都可以缩放,但文本不会缩放。

14
为了演示我想要的效果,假设我们将图像垂直缩放:
之前:

example 1

之后:

example 2

请注意,文字不会失真。我正在寻找一个更简单的替代方法来在缩放发生变化时自动绘制和定位元素,特别是当文本保持相同尺寸时,我认为svg可以实现这一点...

1
如果你的SVG文件非常简单,也许拉伸功能可以使用(除了文本),但是你的线条可能也会变宽(这可以通过添加属性vector-effect="non-scaling-stroke"来解决)。 - Erik Dahlström
1
好的。所以主要问题是防止文本缩放。我也可以使用 vector-effect="non-scaling-text" 吗? - CrazyTim
嗯,看起来不是:http://www.w3.org/TR/SVGTiny12/painting.html#VectorEffectProperty - CrazyTim
1
我想我可以创建SVG,但不包括文本,并将描边设置为非比例缩放 - 这将解决一半的问题。然后,我只需要根据绘图的比例手动定位文本即可。 - CrazyTim
2
这在纯SVG中是完全可能的。请查看我的答案:https://dev59.com/x4jca4cB1Zd3GeqP2dj0#61139485 - Sheraff
1个回答

3

很久以前就有人提出了这个问题。我认为如果没有JavaScript是不可能做到的。如果您不介意使用JavaScript,可以使用此插件。该插件获取具有特定类别的所有svg元素,并在每个元素上创建一个变换矩阵:

此插件要求svg具有viewBox选项。这是一个起点,您可以根据自己的需要进行调整;)

(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);

使用插件的方法如下:
//---Code
$("#svg-element").noScaleSVGElements();

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

这是一个示例代码,改变窗口大小并查看结果:

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


你好!如何在控制台中删除注释?每次我调整窗口大小时,都会收到以下警告:Unexpected value matrix (0.57,0,0,0.57,NaN,38.7) parsing transform attribute. - Kuzma
1
嗨 @kuzma,代码似乎存在一个错误。你能否创建一个 Jsfiddfle 或 Codepen 来检查错误出现在哪里? - ElChiniNet
是的,这是代码中的一个错误。谢谢你的建议! - Kuzma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接