SVG的viewBox與preserveAspectRatio屬性

svg的座標系

svg採用相似canvas的座標系統,以左上角爲0,0原點,從左往右計算x值,從上到下計算y值。這個和HTML中標示位置的方法相同。
咱們來看一個例子javascript

<svg width="400" height="200" viewBox="0 0 200 50" style="border:1px solid greenyellow">
   <rect with="150" height="150" x="10" y="10" fill="#008d46"/>
</svg>

svg中的「像素pixels」

在絕大多數狀況下SVG文檔中的一個像素對應輸出設備上的一個像素(例如顯示屏幕上)
由於SVG是一個可無極縮放的矢量圖形繪製標記語言。其作大的特色是在任意大小的顯示設備上均可以不失精度的表現原始圖形。SVG就有關於absolute unit和user unit的說法-在定義大小是不明確指定單位
沒有特別的說明,一個user unit等於一個屏幕單位(一個像素),能夠給經過設置viewBox屬性的方法改變默認的狀況,能夠放大或縮小對應的值
例如
<svg width="100" height="100">
定義了一個100px_*_100px的svg canvas,這裏一個user unit等於一個屏幕像素
咱們再來看一個例子css

<svg width="200" height="200" viewBox="0 0 100 100">html

這裏的svg在寬度上一個userunit爲2個屏幕像素,高度上一個userunit爲2個屏幕像素。也就是說整個以viewBox爲參考系定義的svg圖像需在寬度和高度上各放大2倍顯示到svg viewport上java

viewBox與viewPort關係

那麼這裏就有一個原始視圖窗口和當前須要顯示的目標視圖窗口之間的映射關係的問題。這裏的原始視圖就是viewBox所設置的視圖窗口,而目標視圖窗口就是viewport。一個原則原始視圖要求鋪滿viewport的大小,viewBox屬性值格式爲 (min-x,min-y,width,height),須要說明的時width和height並非表示viewBox的實際的寬度和高度,這個是指在min-x和min-y都爲0的狀況西下成立,viewBox的實際獨寬度爲minx-x+width,高度爲min-y+heightjquery

<svg width="400" height="200" viewBox="0 0 200 100" style="border:1px solid greenyellow">
   <rect with="100" height="100" x="0" y="0" fill="#008d46"/>
</svg>

以上面的svg爲例canvas

  • viewport的大小就是400200的矩形區域,具體的座標位置以svg元素所在的頁面的的位置。以HTML頁面爲參考系svg

  • viewBox的大小就是200500的矩形區域,位置座標爲(0,0)以viewBox爲參考系ui

  • 由於viewBox的寬高比爲2,viewport的寬高比也爲2,那麼放大2倍後viewBox恰好鋪滿viewport:),
    (咱們就能夠認爲0.5個userunit對應一個屏幕像素)spa

  • 以viewBox爲參考系的svg下的graphic elements也等同的放大2倍,也就是如今看到的綠色的矩形大小爲200_*_200
    圖片描述code

可是實際不少SVG的viewBox的寬高比和viewport的寬高比是不一樣有差別的。那麼在不一樣的狀況下viewBox和viewport怎麼處理?viewBox的4個參數到底有什麼做用?viewBox比viewport區域大能夠嗎?SVG是怎麼處理的呢?可就要和下面的preserveAspectRatio屬性值相關了

preserveAspectRatio的屬性

preserveAspetRation屬性是和viewBox屬性配合使用的。viewBox屬性值能夠指明graphic element是否能夠等比例縮放(寬高比相同的狀況下)以擴展到viewport指定的大小區域中。
preserveAspetRation屬性指出瞭如何縮放及若是對齊viewBox到viewport上

若是沒有指定viewBox屬性,那麼此屬性是會被忽略的
先在這裏聲明一點,它的默認值爲xMidYMid meet。

那麼xMid、YMid、meet都是些什麼樣的值,幹嗎用的?就要從preserveAspetRation的可選值講起
preserveAspectRation的值爲[defer]<align>[meetOrSlice]-以可選的defer開始+<align>+可選的meet或者Slice。

  • defer這個值只在image元素中有效表示只在img顯示出來後才計算使用preserveAspectRation屬性,對於其它元素就忽略這個值了

  • 在講<align>以前,有必要說明下[meetOrSlice]候選值,默認值爲meet

    • meet viewBox保持縮放比;整個viewBox在viewport中可見;在知足前2個約束條件的基礎上,儘量的放大viewBox。當viewport的寬高比和viewBox的寬高比不匹配時,取寬高縮放比中較小的那個注意這裏說的是viewBox的縮放而不是圖形

    • slice 修剪 viewBox保持縮放比;整個viewport區域被viewBox覆蓋;在知足籤個約束條件的基礎上,儘量的縮小viewBox。當viewport的寬高比和viewBox的寬高比不匹配時,取寬高縮放比中較大的那個

  • <align>在viewBox的寬高比和viewport的寬高比不匹配的狀況,它的值必須是如下其中一個

    • none

      不強制進行等比例縮放,那麼viewBox旗下的graphicelements就以viewBox和viewport實際的寬高比來縮放圖形,儘可能把寬度和高度擴展到這個viewport上。一個後果就是圖形比例會失真
      <svg width="400" height="200" viewBox="0 0 200 50" preserveAspectRation="none" style="border:1px solid greenyellow">
      <rect with="100" height="100" x="0" y="0" fill="#008d46"/>
      </svg>

      clipboard.png

咱們能夠看到rect的實際的寬度變爲200,而高度邊變爲400。這個和viewBox和viewPort的寬高比是相符合的,寬度放大2被,高度放大4倍
咱們把viewBox和viewport的寬高換一下

<svg width="200" height="50"  preserveAspectRatio="none" viewBox="0 0 400 200" style="border:1px solid greenyellow">
<rect width="100" height="100" x="0" y="0" fill="#008d46" />
</svg>

那麼看到的結果爲
clipboard.png

rect的寬度縮小2倍,寬度縮小4倍,原始的正方形變成了長方形

  • xMinYMin 強制等比例縮放,viewBox的min-x座標值和viewport的最左邊的x對齊。viewBox的min-y座標和viewport的最左邊的y座標對齊,
    一樣以上面svg爲例,黑色邊框矩形表示viewport,粉色矩形表示viewBox,淡綠色矩形表示rect圖形元素。必須先按meet或slice計算肯定放大或縮小比例,viewBox中的數值按縮放後再執行對齊

圖片描述

  • xMidYMin 強制等比例縮放,viewBox的x中點和viewport的x中點對齊,viewBox的min-y和viewport的最上邊y值對齊。

圖片描述

  • xMaxYMin 強制等比例縮放,viewBox的min-x+width和viewport最右邊x值對齊,viewBox的min-y和viewport的最上邊y值對齊

    圖片描述

  • xMinYMid 強制等比例縮放,viewBox的min-x和viewport的最左邊x對齊,viewBox的y的中點和viewport的中點對齊

    圖片描述

  • xMidYMid 強制等比例縮放,viewBox的x中點和viewport的x中點對齊,viewBox的y中點和viewport的中點對齊。是默認配置。meet值決定了svg的縮放比爲0.25(寬度上的縮放比爲0.5,高度山的縮放比爲0.25)。viewBox的x中點座標爲(50+400*0.5)*0.25=62.5,viewport的x中點座標爲200*0.5=100;viewBox的y中點座標爲(50+200*0.5)*0.25=37.5,viewport的y中點座標爲50*0.5=25;那麼viewBox的x座標爲100-62.5=37.5,y座標爲25-37.5=-12.5,viewBox的寬度爲(50+400)*0.25=112.5 高度爲(50+200)*0.25=62.5。其它屬性值也使相似,你能夠運行附上的代碼來查看效果。
    最終效果以下:

    圖片描述

  • xMaxYMid 強制等比例縮放,viewBox的min-x+width和viewport的最右邊的x對齊,viewBox的y中點和viewport的y中點對齊

    圖片描述

  • xMinYMax 強制等比例縮放,viewBox的min-x和viewport最左邊的x對齊,viewBox的min-y+height和viewport最下邊的y值對齊

    圖片描述

  • xMidYMax 強制等比例縮放,viewBox的x中點和viewport的x中點對齊,viewBox的min-y+height和viewport最下邊的y值對齊
    圖片描述

  • xMaxYMax 強制等比例縮放,viewBox的min-x+width和viewport的最右邊x對齊,viewBox的min-y+height和viewport最下邊的y值對齊

clipboard.png

附上代碼

能看到完成的定位過程

<!DOCTYPE html>
<html>
<head>
    <title>HTML/SVG Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script src="script/jquery-2.1.3.min.js"></script>
    <script type="text/javascript">
        $(document).ready(function() {
            $("button.ts").click(function() {
                console.log('trigger select');
                var XaspectRatio=$('input[name=VP_width]').val()/$('input[name=VB_width]').val();
                var YaspectRatio=$('input[name=VP_height]').val()/$('input[name=VB_height]').val();


                var aspectRatio=Math.min(XaspectRatio,YaspectRatio);
                var preserveAspectRatioSetting=$('input[name=xAlignType]:checked').val()+''+$('input[name=YAlignType]:checked').val();

                var meetOrSlice=$('input[name=meetOrSlice]:checked').val();
                if(meetOrSlice==='meet'){
                    aspectRatio=Math.min(XaspectRatio,YaspectRatio);
                }else{
                    aspectRatio=Math.max(XaspectRatio,YaspectRatio);
                }
                console.log("meetOrSlice:"+meetOrSlice);
                var viewBoxX=$('input[name=VB_x]').val()*aspectRatio;
                var viewBoxY=$('input[name=VB_y]').val()*aspectRatio;

                var viewBoxWidth=$('input[name=VB_width]').val()*aspectRatio;
                var viewBoxHeight=$('input[name=VB_height]').val()*aspectRatio;

                var viewBoxxMid=viewBoxX+(viewBoxWidth)*0.5;
                var viewBoxYMid=viewBoxY+(viewBoxHeight)*0.5;
                var viewBoxxMax=(viewBoxX+viewBoxWidth);
                var viewBoxYMax=(viewBoxY+viewBoxHeight);

                var viewportX=0;
                var viewportY=0;
                var viewportWidth=$('input[name=VP_width]').val()*1;
                var viewportHeight=$('input[name=VP_height]').val()*1;
                var viewportxMid=viewportX+(viewportWidth)*0.5;
                var viewportYMid=viewportY+(viewportHeight)*0.5;
                var viewportxMax=(viewportX+viewportWidth)*1;
                var viewportYMax=(viewportY+viewportHeight)*1;



                var rectWidth=$('input[name=rect_width]').val()*aspectRatio;
                var rectHeight=$('input[name=rect_height]').val()*aspectRatio;
                var rectX=$('input[name=rect_x]').val()*aspectRatio;
                var rectY=$('input[name=rect_y]').val()*aspectRatio;


                console.log(viewBoxX+' '+viewBoxWidth+' '+viewBoxYMid);
                console.log(preserveAspectRatioSetting);
                console.log(viewportYMax+' '+viewBoxYMax);

                switch(preserveAspectRatioSetting){
                    case 'xMinYMin':
                        viewBoxX=viewportX-viewBoxX;
                        viewBoxY=viewportY-viewBoxY;
                        break;
                    case 'xMinYMid':
                        viewBoxX=viewportX-viewBoxX;
                        viewBoxY=viewportYMid-viewBoxYMid;
                        break;
                    case 'xMinYMax':
                        viewBoxX=viewportX-viewBoxX;
                        viewBoxY=viewportYMax-viewBoxYMax;

                        break;
                    case 'xMidYMin':
                        viewBoxX=viewportxMid-viewBoxxMid;
                        viewBoxY=viewportY-viewBoxY;

                        break;
                    case 'xMidYMid':
                        viewBoxX=viewportxMid-viewBoxxMid;
                        viewBoxY=viewportYMid-viewBoxYMid;
                        break;
                    case 'xMidYMax':
                        viewBoxX=viewportxMid-viewBoxxMid;
                        viewBoxY=viewportYMax-viewBoxYMax;
                        break;
                    case 'xMaxYMin':
                        viewBoxX=viewportxMax-viewBoxxMax;
                        viewBoxY=viewportY-viewBoxY;
                        break;
                    case 'xMaxYMid':
                        viewBoxX=viewportxMax-viewBoxxMax;
                        viewBoxY=viewportYMid-viewBoxYMid;
                        break;
                    case 'xMaxYMax':
                        viewBoxX=viewportxMax-viewBoxxMax;
                        viewBoxY=viewportYMax-viewBoxYMax;
                        break;
                    default:
                        viewBoxX=viewportX-viewBoxX;
                        viewBoxY=viewportY-viewBoxY;
                        //xMidYMid
                }

                $('div#svg').css({
                    width:$('input[name=VP_width]').val(),
                    height:$('input[name=VP_height]').val(),
                    "margin-left":"0px",
                    "margin-right":"0px"
                });

                $('div#viewBox').css({
                    width:($('input[name=VB_width]').val()*1+$('input[name=VB_x]').val()*1)*aspectRatio,
                    height:($('input[name=VB_height]').val()*1+$('input[name=VB_y]').val()*1)*aspectRatio,
                    "margin-left":(viewBoxX*1)+"px",
                    "margin-top":(viewBoxY*1)+"px"
                });
                $('div#rect').css({
                    width:$('input[name=rect_width]').val()*aspectRatio,
                    height:$('input[name=rect_height]').val()*aspectRatio,
                    "margin-left":(rectX*1)+"px",
                    "margin-top":(rectY*1)+"px"
                });
            });

        });

    </script>
</head>
<body>
<br>
<br>
<div style="margin-left:0px;width:300;height:200px;border:1px solid #cccccc;padding:30px;">
<div id="svg" style="margin-left:0px;margin-top:0px;width:200px;height:50px;border:1px solid black">
    <div id="viewBox" style="margin-left:-12.5px;margin-top:-12.5px;width:100px;height:50px;background-color:red;opacity:0.3;border:0px dashed red">
        <div id="rect" style="margin-left:0px;margin-top:0px;width:25px;height:25px;
        background-color:#008d46;opacity:1.0;border:0px dashed red"></div>
        </div>
</div>
    </div>

<div style="margin-top:10px;">
    <div>
        <label>xMin:<input type="radio" name="xAlignType" value="xMin" ></label>
        <label>xMid(default):<input type="radio" name="xAlignType" value="xMid" checked></label>
        <label>xMax:<input type="radio" name="xAlignType" value="xMax"></label>
    </div>
    <div>
        <label>YMin:<input type="radio" name="YAlignType" value="YMin"></label>
        <label>YMid(default):<input type="radio" name="YAlignType" value="YMid" checked></label>
        <label>YMax:<input type="radio" name="YAlignType" value="YMax"></label>
    </div>
    <div>
        <label>meet(default):<input type="radio" name="meetOrSlice" value="meet" checked></label>
        <label>slice:<input type="radio" name="meetOrSlice" value="slice"></label>
    </div>
    <div>
        <label>viewPort width:<input type="text" name="VP_width" value="200" style="width: 50px;"></label>
        <label> height:<input type="text" name="VP_height" value="50" style="width: 50px;"></label>
    </div>
    <div>
        <label>viewBox width:<input type="text" name="VB_width" value="400" style="width: 50px;"></label>
        <label> height:<input type="text" name="VB_height" value="200" style="width: 50px;"></label>
        <label> x:<input type="text" name="VB_x" value="50" style="width: 50px;"></label>
        <label> y:<input type="text" name="VB_y" value="50" style="width: 50px;"></label>
    </div>
    <div>
        <label>Rect width:<input type="text" name="rect_width" value="100" style="width: 50px;"></label>
        <label> height:<input type="text" name="rect_height" value="100" style="width: 50px;"></label>
        <label> x:<input type="text" name="rect_x" value="0" style="width: 50px;"></label>
        <label> y:<input type="text" name="rect_y" value="0" style="width: 50px;"></label>
    </div>
    <button class="ts">Show</button>

</div>


</body>
</html>
相關文章
相關標籤/搜索