以不同方式缩放 SVG 文件的不同部分
Scale different parts of SVG file differently
我需要一个可变高度的 svg 图形,用于带有锯齿边缘的票证。顶部和底部部分应缩放以保持固定的纵横比,而中间部分应拉伸以适应容器的大小。
这张图片应该是说明性的
我发现 this jsFiddle 几乎可以水平而不是垂直地做我想做的事情,但我对 viewbox 的了解还不够深,无法理解正在发生的事情并根据我的需要对其进行调整。我刚刚弄乱了我的文件。
目前我的svg文件非常简单;顶部路径,底部路径和中间的矩形。它看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="464px" height="464px" viewBox="0 0 464 464" enable-background="new 0 0 464 464" xml:space="preserve">
<path fill="#FFF100" d="M432.846,10.522c-5.755,0.057-10.466-4.562-10.522-10.316c-0.001-0.069-0.001-0.137,0-0.206h-20.839
c0.057,5.754-4.563,10.465-10.316,10.522c-5.755,0.057-10.466-4.562-10.522-10.316c0-0.069,0-0.137,0-0.206h-20.843
c0.058,5.754-4.561,10.465-10.315,10.522S339.021,5.96,338.965,0.206c0-0.069,0-0.137,0-0.206h-20.836
c0.057,5.754-4.562,10.465-10.316,10.522c-5.754,0.057-10.465-4.562-10.522-10.316c0-0.069,0-0.137,0-0.206h-20.437
c0,24.772-20.082,44.853-44.854,44.853c-24.771,0-44.853-20.081-44.853-44.853H166.71c0.056,5.754-4.562,10.465-10.317,10.522
c-5.754,0.057-10.465-4.562-10.521-10.316c-0.001-0.069-0.001-0.137,0-0.206h-20.839c0.098,5.754-4.486,10.498-10.24,10.596
c-5.754,0.099-10.498-4.486-10.596-10.24c-0.002-0.119-0.002-0.238,0-0.356H83.355c0.057,5.754-4.563,10.465-10.317,10.522
S62.573,5.96,62.517,0.206c0-0.069,0-0.137,0-0.206H41.677c0.057,5.754-4.562,10.465-10.316,10.522
C25.607,10.579,20.896,5.96,20.839,0.206c-0.001-0.069-0.001-0.137,0-0.206H0v56h464V0h-20.839
C443.219,5.754,438.6,10.465,432.846,10.522z"/>
<path fill="#FFF100" d="M432.846,453.478c-5.755-0.056-10.466,4.563-10.522,10.317c-0.001,0.068-0.001,0.137,0,0.205h-20.839
c0.057-5.754-4.563-10.466-10.316-10.522c-5.755-0.056-10.466,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205h-20.843
c0.058-5.754-4.561-10.466-10.315-10.522c-5.755-0.056-10.466,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205h-20.836
c0.057-5.754-4.562-10.466-10.316-10.522c-5.754-0.056-10.465,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205h-20.437
c0-24.771-20.082-44.854-44.854-44.854c-24.771,0-44.853,20.082-44.853,44.854H166.71c0.056-5.754-4.562-10.466-10.317-10.522
c-5.754-0.056-10.465,4.563-10.521,10.317c-0.001,0.068-0.001,0.137,0,0.205h-20.839c0.098-5.754-4.487-10.498-10.24-10.597
c-5.754-0.098-10.498,4.486-10.596,10.24c-0.002,0.119-0.002,0.238,0,0.356H83.355c0.057-5.754-4.563-10.466-10.317-10.522
c-5.754-0.056-10.465,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205H41.677c0.057-5.754-4.562-10.466-10.316-10.522
c-5.754-0.056-10.465,4.563-10.521,10.317c-0.001,0.068-0.001,0.137,0,0.205H0v-56h464v56h-20.839
C443.219,458.246,438.6,453.534,432.846,453.478z"/>
<rect y="56" fill="#00AEEF" width="464" height="352"/>
</svg>
如果有人能帮助我,我会很高兴。
通常,您无法以不同于其他部分的方式缩放 SVG 的某些部分。但是,在一些简单的情况下(例如您链接到的铅笔图像),您可以巧妙地构建一个有效的情况。
铅笔的工作原理
首先为铅笔的三个部分定义一个 <symbol>
元素:末端、body 和尖头。
然后通过添加三个 child <svg>
元素来组合它们。后面是 body <symbol>
拉长了主 <svg>
的整个宽度。然后将两个端盖 <svg>
元素放在前面。每个端盖 <svg>
占据宽度的一半。但它们具有“preserveAspectRatio”属性,导致它们分别与左端和右端对齐。
如果我们把两端部分做成几乎完全半透明,你就可以看到是怎么回事了:
:checked~svg{
width:500px;
}
<input type="checkbox"/><br/>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="source">
<rect width="200" height="100" fill="yellow"/>
<circle cx="50" cy="50" r="40" fill="red"/>
<rect x="50" y="10" width="100" height="80" fill="orange"/>
<path d="M150,10L190,50 150,90z" fill="pink"/>
</g>
<symbol id="left" viewBox="0 0 50 100" preserveAspectRatio="none">
<use xlink:href="#source"/>
</symbol>
<symbol id="middle" viewBox="50 0 100 100" preserveAspectRatio="none">
<use xlink:href="#source"/>
</symbol>
<symbol id="right" viewBox="150 0 50 100" preserveAspectRatio="none">
<use xlink:href="#source"/>
</symbol>
</defs>
<svg viewBox="0 0 1 1" preserveAspectRatio="none">
<use xlink:href="#middle" width="1" height="1"/>
</svg>
<svg viewBox="0 0 1 2" preserveAspectRatio="xMinYMid">
<use xlink:href="#left" width="1" height="2" opacity="0.1"/>
</svg>
<svg viewBox="0 0 1 2" preserveAspectRatio="xMaxYMid">
<use xlink:href="#right" width="1" height="2" opacity="0.2"/>
</svg>
</svg>
您可以看到 body 是如何拉伸到整个宽度的,以及端盖是如何放置在末端以隐藏拉伸的 body。
这个技巧之所以有效,是因为铅笔有纯色背景(黄色)。但我假设你希望你的票的穿孔端是透明的,所以这个技巧对你不起作用。如果你同意它是白色的,那么它会。
对您来说可能更简单的是将三个部分堆叠在一起。
<svg> (the top of the ticket)
<div> (containing the ticket body contents)
<svg> (the bottom of the ticket)
再一次,如果你想用困难的方式做到这一点,你可以使用 JavaScript:
$("input#resize").on("click", function(){
if($("input#resize:checked").length){
scaleSvgBorder();
}
});
function scaleSvgBorder(){
if ($("svg#myFancyBorder").length && $("svg#myFancyBorder").height() > 0){
//first we need the ratio between the SVG grid and our beloved HTML pixels.
var svgRatio = $("svg#myFancyBorder").height() / $("svg#myFancyBorder").attr("viewBox").split(" ")[3];
//Next we need to figure out which scale to apply on the sides group inside our SVG.
//We do this by calculating the height we want the sides to be (in pixels), and divide it by the current height of the sides (in pixels).
var sidesCurrentHeightPx = $("svg#myFancyBorder #sides")[0].getBBox().height * svgRatio;
//Let's subtract the top & bottom of our border from the container height, in order to get the height we want the sides to be (in pixels).
var nonScalingPartsHeightPx = ($("svg#myFancyBorder #top")[0].getBBox().height + $("svg#myFancyBorder #bottom")[0].getBBox().height) * svgRatio;
var sidesTargetHeightPx = $("#container").height() - nonScalingPartsHeightPx;
//Finally, we have the scale ratio!
var scaleRatio = sidesTargetHeightPx / sidesCurrentHeightPx;
//We need to subtract the scaled top from the top for an additional sides translation transformation, since they will move, because SVG scales from 0, 0!
var scaledTopDifference = $("svg#myFancyBorder #top")[0].getBBox().height - ($("svg#myFancyBorder #top")[0].getBBox().height * scaleRatio);
//We need to subtract the scaled sides from the sides for the bottom translation, because SVG scales from 0, 0!
var scaledSidesDifference = $("svg#myFancyBorder #sides")[0].getBBox().height - ($("svg#myFancyBorder #sides")[0].getBBox().height * scaleRatio);
//Notice that we have to apply the scale ratio to the translation transformation if we place it AFTER the scale transformation!!!
$("svg#myFancyBorder #sides").attr("transform", "scale(1, " + scaleRatio + ") translate(0, " + (scaledTopDifference / scaleRatio) +")");
//* -1 because it has to move down.
$("svg#myFancyBorder #bottom").attr("transform", "translate(0, " + ( scaledSidesDifference * -1 ) +")");
//Let's stretch the viewbox to the height of the container too!
$("svg#myFancyBorder").attr('viewBox', "0 0 "+ $("svg#myFancyBorder").attr("viewBox").split(" ")[2] +" "+ ($("#container").height() / svgRatio) );
}
}
#container{
position: relative;
width: 200px;
height: 400px;
background-color: #cde
}
svg#myFancyBorder{
position: absolute;
width: 100%;
height: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" id="resize" /><label for="resize">Fit border to container</label>
<div id="container">
<!-- Notice that there's no width, height, x or y attribute, since we're trying to keep it simple. -->
<!-- Also notice that the viewBox HAS to start with '0 0' since this is the point where SVG images scale from! -->
<svg version="1.1" id="myFancyBorder" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 277.5 237.5">
<rect id="top" width="277.5" height="55"/>
<g id="sides">
<line fill="none" stroke="#000000" stroke-width="5" x1="2.5" y1="55" x2="2.5" y2="182.5"/>
<line fill="none" stroke="#000000" stroke-width="5" x1="275" y1="55" x2="275" y2="182.5"/>
</g>
<rect id="bottom" y="182.5" width="277.5" height="55"/>
</svg>
</div>
我需要一个可变高度的 svg 图形,用于带有锯齿边缘的票证。顶部和底部部分应缩放以保持固定的纵横比,而中间部分应拉伸以适应容器的大小。
这张图片应该是说明性的
我发现 this jsFiddle 几乎可以水平而不是垂直地做我想做的事情,但我对 viewbox 的了解还不够深,无法理解正在发生的事情并根据我的需要对其进行调整。我刚刚弄乱了我的文件。
目前我的svg文件非常简单;顶部路径,底部路径和中间的矩形。它看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="464px" height="464px" viewBox="0 0 464 464" enable-background="new 0 0 464 464" xml:space="preserve">
<path fill="#FFF100" d="M432.846,10.522c-5.755,0.057-10.466-4.562-10.522-10.316c-0.001-0.069-0.001-0.137,0-0.206h-20.839
c0.057,5.754-4.563,10.465-10.316,10.522c-5.755,0.057-10.466-4.562-10.522-10.316c0-0.069,0-0.137,0-0.206h-20.843
c0.058,5.754-4.561,10.465-10.315,10.522S339.021,5.96,338.965,0.206c0-0.069,0-0.137,0-0.206h-20.836
c0.057,5.754-4.562,10.465-10.316,10.522c-5.754,0.057-10.465-4.562-10.522-10.316c0-0.069,0-0.137,0-0.206h-20.437
c0,24.772-20.082,44.853-44.854,44.853c-24.771,0-44.853-20.081-44.853-44.853H166.71c0.056,5.754-4.562,10.465-10.317,10.522
c-5.754,0.057-10.465-4.562-10.521-10.316c-0.001-0.069-0.001-0.137,0-0.206h-20.839c0.098,5.754-4.486,10.498-10.24,10.596
c-5.754,0.099-10.498-4.486-10.596-10.24c-0.002-0.119-0.002-0.238,0-0.356H83.355c0.057,5.754-4.563,10.465-10.317,10.522
S62.573,5.96,62.517,0.206c0-0.069,0-0.137,0-0.206H41.677c0.057,5.754-4.562,10.465-10.316,10.522
C25.607,10.579,20.896,5.96,20.839,0.206c-0.001-0.069-0.001-0.137,0-0.206H0v56h464V0h-20.839
C443.219,5.754,438.6,10.465,432.846,10.522z"/>
<path fill="#FFF100" d="M432.846,453.478c-5.755-0.056-10.466,4.563-10.522,10.317c-0.001,0.068-0.001,0.137,0,0.205h-20.839
c0.057-5.754-4.563-10.466-10.316-10.522c-5.755-0.056-10.466,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205h-20.843
c0.058-5.754-4.561-10.466-10.315-10.522c-5.755-0.056-10.466,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205h-20.836
c0.057-5.754-4.562-10.466-10.316-10.522c-5.754-0.056-10.465,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205h-20.437
c0-24.771-20.082-44.854-44.854-44.854c-24.771,0-44.853,20.082-44.853,44.854H166.71c0.056-5.754-4.562-10.466-10.317-10.522
c-5.754-0.056-10.465,4.563-10.521,10.317c-0.001,0.068-0.001,0.137,0,0.205h-20.839c0.098-5.754-4.487-10.498-10.24-10.597
c-5.754-0.098-10.498,4.486-10.596,10.24c-0.002,0.119-0.002,0.238,0,0.356H83.355c0.057-5.754-4.563-10.466-10.317-10.522
c-5.754-0.056-10.465,4.563-10.522,10.317c0,0.068,0,0.137,0,0.205H41.677c0.057-5.754-4.562-10.466-10.316-10.522
c-5.754-0.056-10.465,4.563-10.521,10.317c-0.001,0.068-0.001,0.137,0,0.205H0v-56h464v56h-20.839
C443.219,458.246,438.6,453.534,432.846,453.478z"/>
<rect y="56" fill="#00AEEF" width="464" height="352"/>
</svg>
如果有人能帮助我,我会很高兴。
通常,您无法以不同于其他部分的方式缩放 SVG 的某些部分。但是,在一些简单的情况下(例如您链接到的铅笔图像),您可以巧妙地构建一个有效的情况。
铅笔的工作原理
首先为铅笔的三个部分定义一个 <symbol>
元素:末端、body 和尖头。
然后通过添加三个 child <svg>
元素来组合它们。后面是 body <symbol>
拉长了主 <svg>
的整个宽度。然后将两个端盖 <svg>
元素放在前面。每个端盖 <svg>
占据宽度的一半。但它们具有“preserveAspectRatio”属性,导致它们分别与左端和右端对齐。
如果我们把两端部分做成几乎完全半透明,你就可以看到是怎么回事了:
:checked~svg{
width:500px;
}
<input type="checkbox"/><br/>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="source">
<rect width="200" height="100" fill="yellow"/>
<circle cx="50" cy="50" r="40" fill="red"/>
<rect x="50" y="10" width="100" height="80" fill="orange"/>
<path d="M150,10L190,50 150,90z" fill="pink"/>
</g>
<symbol id="left" viewBox="0 0 50 100" preserveAspectRatio="none">
<use xlink:href="#source"/>
</symbol>
<symbol id="middle" viewBox="50 0 100 100" preserveAspectRatio="none">
<use xlink:href="#source"/>
</symbol>
<symbol id="right" viewBox="150 0 50 100" preserveAspectRatio="none">
<use xlink:href="#source"/>
</symbol>
</defs>
<svg viewBox="0 0 1 1" preserveAspectRatio="none">
<use xlink:href="#middle" width="1" height="1"/>
</svg>
<svg viewBox="0 0 1 2" preserveAspectRatio="xMinYMid">
<use xlink:href="#left" width="1" height="2" opacity="0.1"/>
</svg>
<svg viewBox="0 0 1 2" preserveAspectRatio="xMaxYMid">
<use xlink:href="#right" width="1" height="2" opacity="0.2"/>
</svg>
</svg>
您可以看到 body 是如何拉伸到整个宽度的,以及端盖是如何放置在末端以隐藏拉伸的 body。
这个技巧之所以有效,是因为铅笔有纯色背景(黄色)。但我假设你希望你的票的穿孔端是透明的,所以这个技巧对你不起作用。如果你同意它是白色的,那么它会。
对您来说可能更简单的是将三个部分堆叠在一起。
<svg> (the top of the ticket)
<div> (containing the ticket body contents)
<svg> (the bottom of the ticket)
再一次,如果你想用困难的方式做到这一点,你可以使用 JavaScript:
$("input#resize").on("click", function(){
if($("input#resize:checked").length){
scaleSvgBorder();
}
});
function scaleSvgBorder(){
if ($("svg#myFancyBorder").length && $("svg#myFancyBorder").height() > 0){
//first we need the ratio between the SVG grid and our beloved HTML pixels.
var svgRatio = $("svg#myFancyBorder").height() / $("svg#myFancyBorder").attr("viewBox").split(" ")[3];
//Next we need to figure out which scale to apply on the sides group inside our SVG.
//We do this by calculating the height we want the sides to be (in pixels), and divide it by the current height of the sides (in pixels).
var sidesCurrentHeightPx = $("svg#myFancyBorder #sides")[0].getBBox().height * svgRatio;
//Let's subtract the top & bottom of our border from the container height, in order to get the height we want the sides to be (in pixels).
var nonScalingPartsHeightPx = ($("svg#myFancyBorder #top")[0].getBBox().height + $("svg#myFancyBorder #bottom")[0].getBBox().height) * svgRatio;
var sidesTargetHeightPx = $("#container").height() - nonScalingPartsHeightPx;
//Finally, we have the scale ratio!
var scaleRatio = sidesTargetHeightPx / sidesCurrentHeightPx;
//We need to subtract the scaled top from the top for an additional sides translation transformation, since they will move, because SVG scales from 0, 0!
var scaledTopDifference = $("svg#myFancyBorder #top")[0].getBBox().height - ($("svg#myFancyBorder #top")[0].getBBox().height * scaleRatio);
//We need to subtract the scaled sides from the sides for the bottom translation, because SVG scales from 0, 0!
var scaledSidesDifference = $("svg#myFancyBorder #sides")[0].getBBox().height - ($("svg#myFancyBorder #sides")[0].getBBox().height * scaleRatio);
//Notice that we have to apply the scale ratio to the translation transformation if we place it AFTER the scale transformation!!!
$("svg#myFancyBorder #sides").attr("transform", "scale(1, " + scaleRatio + ") translate(0, " + (scaledTopDifference / scaleRatio) +")");
//* -1 because it has to move down.
$("svg#myFancyBorder #bottom").attr("transform", "translate(0, " + ( scaledSidesDifference * -1 ) +")");
//Let's stretch the viewbox to the height of the container too!
$("svg#myFancyBorder").attr('viewBox', "0 0 "+ $("svg#myFancyBorder").attr("viewBox").split(" ")[2] +" "+ ($("#container").height() / svgRatio) );
}
}
#container{
position: relative;
width: 200px;
height: 400px;
background-color: #cde
}
svg#myFancyBorder{
position: absolute;
width: 100%;
height: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="checkbox" id="resize" /><label for="resize">Fit border to container</label>
<div id="container">
<!-- Notice that there's no width, height, x or y attribute, since we're trying to keep it simple. -->
<!-- Also notice that the viewBox HAS to start with '0 0' since this is the point where SVG images scale from! -->
<svg version="1.1" id="myFancyBorder" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 277.5 237.5">
<rect id="top" width="277.5" height="55"/>
<g id="sides">
<line fill="none" stroke="#000000" stroke-width="5" x1="2.5" y1="55" x2="2.5" y2="182.5"/>
<line fill="none" stroke="#000000" stroke-width="5" x1="275" y1="55" x2="275" y2="182.5"/>
</g>
<rect id="bottom" y="182.5" width="277.5" height="55"/>
</svg>
</div>