SVG多解析度、自適應縮放解決方案

食肉動物發表於2014-05-07

SVG格式本身就是向量圖形格式,可以隨意縮放。但是如果如果整個畫面都是通過SVG進行搭建,同一個SVG圖形嵌入在HTML中,要同時滿足多個解析度螢幕的檢視,還是需要進行一些額外的設定,包括JS動態設定width、height等。

使用者在設計SVG圖形的初期,先要確定該SVG圖形的大致畫面比例和檢視方向,比如:該畫面是在手機上檢視還是Pad上檢視還是pc上;還有,允許該畫面只是上下滑動檢視(對於高度遠大於寬度的情況),還是畫面只是左右滑動檢視等。

確定了以上的資訊,要設計一個可以在多解析度螢幕下自適應的SVG畫面,有以下幾個步驟

1.在SVG根標籤中新增 preserveAspectRatio="xMinYMin meet" 屬性
     該屬性指定SVG圖形在螢幕的最左上角開始顯示,並且保持等比縮放。

2.在SVG跟標籤中新增 viewBox 屬性
     該屬性來設定SVG畫布的大小,但該大小是一個相對的大小,並不是絕對尺寸大小。比如設定一個viewBox="0,0,800,3000",可以認為將畫布大小的寬分為800份,高分為3000份,然後所有SVG的元素都在800*3000所分割成的畫布上擺放。這時候不用考慮螢幕實際高寬。再次提醒注意:viewBox將畫布分為800*3000份的小格子,然後所有的元素在該畫布上擺放。至於該格子的絕對大小,則根據我們後面所設定的width height單位來決定。

3.新增SVG元素。
     注意,各個SVG元素的高寬和xy座標都按照800*3000的大小來設定,也就是說如果想要在最右下角放一個100*100的矩形,那麼就應該寫成
   
 <rect x="700" y="2900" width="100" height="100" fill="red" />
     我們上面已經說過,這時候不用關心實際螢幕的高寬,只按照viewBox畫布大小進行設定。

4.呼叫JS函式動態設定svg元素的高寬,進行自適應調整。
     在這一步要確定如何檢視該畫面,對於該畫面800*3000,我們設定為只能上下滑動檢視,左右固定寬度的方式。
   
     <script type="text/javascript">
         $(function() {
             var svgRootDom = $("#sketchpad")[0];
             adjustToFreezeHeight(svgRootDom);
         });
    </script>


最終的HTML格式如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>FreezeWidth</title>
<link rel="stylesheet" href="screen.css">
<script type="text/javascript" src="../../js/jquery-2.1.0.js"></script>
<script type="text/javascript" src="./screen.js"></script>
<script type="text/javascript">
    $(function() {
        var svgRootDom = $("#sketchpad")[0];
        adjustToFreezeWidth(svgRootDom);
    });
    
</script>
</head>
<body style="background-color: black;">
<svg id="sketchpad" preserveAspectRatio="xMinYMin meet" viewBox="0,0,3000,3000">
    <rect x="0" y="0" width="100%" height="100%" fill="green"/>
    <rect x="10" y="10" width="100" height="100" fill="orange" />
    <rect x="200" y="300" width="90" height="90" fill="orange" />
    <circle cx="400" cy="1500" r="50" fill="gray" />
    <rect x=700 y="2900" width="100" height="100" fill="blue" />
    
</svg>
</body>
</html>

所封裝的自適應函式 screen.js

function adjustToFreezeWidth(rootSvg) {
    var windowWidth = $(window).width();

    var viewBoxVal = rootSvg.getAttribute("viewBox");
    var viewBoxWidth = viewBoxVal.split(",")[2];
    var viewBoxHeight = viewBoxVal.split(",")[3];
    rootSvg.removeAttribute("width");
    rootSvg.removeAttribute("height");

    var setWidth = windowWidth;
    var setHeight = (setWidth * viewBoxHeight) / viewBoxWidth;
    rootSvg.setAttribute("width", setWidth);
    rootSvg.setAttribute("height", setHeight);
}

function adjustToNone(rootSvg) {

    var viewBoxVal = rootSvg.getAttribute("viewBox");
    var viewBoxWidth = viewBoxVal.split(",")[2];
    var viewBoxHeight = viewBoxVal.split(",")[3];
    rootSvg.removeAttribute("width");
    rootSvg.removeAttribute("height");

    rootSvg.setAttribute("width", viewBoxWidth);
    rootSvg.setAttribute("height", viewBoxHeight);

}

function adjustToFreezeHeight(rootSvg) {

    var windowHeight = $(window).height();

    var viewBoxVal = rootSvg.getAttribute("viewBox");
    var viewBoxWidth = viewBoxVal.split(",")[2];
    var viewBoxHeight = viewBoxVal.split(",")[3];
    rootSvg.removeAttribute("width");
    rootSvg.removeAttribute("height");

    var setHeight = windowHeight;
    var setWidth = (setHeight * viewBoxWidth)/viewBoxHeight;
    rootSvg.setAttribute("width", setWidth);
    rootSvg.setAttribute("height", setHeight);
}

function adjustToFreezeAll() {

    var windowHeight = $(window).height();
    var windowWidth = $(window).width();
    
    rootSvg.removeAttribute("width");
    rootSvg.removeAttribute("height");

    rootSvg.setAttribute("width", windowWidth);
    rootSvg.setAttribute("height", windowHeight);

}



小結:通過以上的函式計算和SVG設定,可以實現SVG圖形在多解析度螢幕下實現自適應的縮放。尤其對於安卓系統,多種解析度的情況,只需要設定一個SVG圖形,便可以滿足絕大多數情況。

需要注意的是,

1.目前該方案適用的是SVG圖形鋪滿全屏的情況下,如果SVG圖形並沒有鋪滿全屏,那麼需要修改adjust***函式中的windowHeight和windowWidth為實際的SVG高寬。

2.該方案需要使用者提前設定是按照哪種方式檢視,再呼叫對應的調整函式。大多數情況下,我們設計的SVG圖形只要滿足大致的高寬比就可以,不至於那給PC設計的SVG放在手機上檢視,那麼效果可能不好(當然也可以在手機上設定為高度鎖定,左右滑動檢視,也可以)。但需要注意的是,如果把一個原來設計的高大於寬的圖形非要顯示在寬大於高的裝置上,那麼效果可能會不同。

相關文章