SVG viewbox 與 preserveAspectRatio

admin發表於2018-08-10

預設情況下,使用者座標系統和視窗座標系統重合,具體參閱SVG 座標系統一章節。

transform屬性可以建立新的當前使用者座標系統,具體參閱以下兩篇文章:

(1).SVG transform 用法一章節。

(2).SVG transform 變換深入理解一章節。

一.viewbox屬性:

此屬性也可以建立新的當前使用者座標系統,下面通過程式碼例項做一下詳細介紹。

首先看一段程式碼例項:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
* {
  margin:0px;
  padding:0px;
}
svg {
  border:1px solid blue;
  width:300px;
  height:150px;
  margin:50px;
  overflow:visible;
}
</style>
</head>
<body>
  <svg viewBox="0 0 150 75">
    <rect
      x="10" y="5"
      width="20" height="20"
      fill="blue" />
  </svg>                     
</body>
</html>

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201901/25/175224lgkadhk4jkvkajv5.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

建立一個寬高分別為20px的矩形,然而實際表現是尺寸明顯大於20px。

之所以出現上面現象,是viewBox屬性的原因。

語法結構:

[XML] 純文字檢視 複製程式碼
viewBox="<min-x>, <min-y>, <width>, <height>"

引數解析:

(1).<min-x>與<min-y>:規定viewBox的左上角左上角的座標。

(2).<width>與<height>:規定viewBox的尺寸。

特別說明:引數之間可以用逗號分隔,也可以用空格分隔。

上面的概念闡述並不直觀,不利於理解,不用擔心,下面會分步通過程式碼例項進行介紹。

如果不使用viewBox屬性,那麼上述程式碼的表現如下:

a:3:{s:3:\"pic\";s:43:\"portal/201901/25/175303m0q5mgzzhf7a5m7a.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

viewBox屬性值四個引數可以繪製出一個矩形框,暫且稱之為"視框",模擬如下:

a:3:{s:3:\"pic\";s:43:\"portal/201901/25/175314t8wjg8llf93l88gt.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

通過viewBox屬性定義一個矩形視框,它會通過縮放填充滿整個元素。

縮放填充過程用如下程式碼模擬:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html><html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
svg {
  border:1px solid blue;
  width:300px;
  height:150px;
  overflow:visible;
}
#rect{
  animation:rect 2s forwards; 
}
@keyframes rect{ 
  from {
    transform:scale(1)
  } 
  to {
    transform:scale(2)
  } 
} 
#box{
  animation:box 2s forwards; 
}
@keyframes box{ 
  from {
    width:150px;
    height:75px;
  } 
  to {
     width:300px;
    height:150px;
  } 
}
</style>
</head>
<body>
  <svg>
    <rect id="rect"
      x="10" y="5"
      width="20" height="20"
      fill="blue" />
  
    <rect id="box"
      x="0" y="0"
      width="150"
      height="75"
      fill="none"
      stroke="red" />
  </svg>                     
</body>
</html>

通過CSS3模擬視框縮放效果,演示了為什麼視框中繪製的元素比它所規定的尺寸要大的原因。

規定視框的尺寸是所在元素尺寸的一半,所以在其中繪製的矩形的尺寸是所規定尺寸的兩倍。

實質是通過"視框"進行適當的矩陣變換以適應指定區域的邊界(通常是視窗):

(1).<min-x>與<min-y>規定transform:translate()變換。

(2).<width>與<height>規定transform:scale()變換。

前面程式碼,viewBox屬性值前兩個引數都是0,所以進行的是transform:scale(2)縮放變換。

再來看一段程式碼例項:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
svg {
  border: 1px solid blue;
  width: 300px;
  height: 150px;
  overflow: visible;
}
</style>
</head>
<body>
  <svg viewBox="-10 -10 200 100">
    <rect
      x="10" y="5"
      width="20" height="20"
      fill="blue" />
  </svg>
</body>
</html>

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201901/25/175353zoioizre1j2jzf1r.png\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

viewBox屬性值前兩個引數值設定為-10,下面看此效果原理動畫演示:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
svg {
  border: 1px solid blue;
  width: 300px;
  height: 150px;
  overflow: visible;
}
#rect{
  animation:rect 4s forwards; 
}
@keyframes rect{ 
  0% {
    transform:translate(0,0) scale(1)
  }
  50% {
    transform:translate(10px,10px) scale(1);
  }
  100% {
    transform:translate(10px,10px) scale(2);
  } 
} 
#box{
  animation:box 4s forwards; 
}
@keyframes box{ 
  0% {
    transform:translate(0,0)
  }  
  50% {
    transform:translate(10px,10px);
    width:150px;
    height:75px;
  }
  100% {
    transform:translate(10px,10px);
    width:300px;
    height:150px;
  } 
}
</style>
</head>
<body>
  <svg>
    <rect id="rect"
      x="10" y="5"
      width="20" height="20"
      fill="blue" />
    <rect id="box"
      x="-10" y="-10"
      width="150" height="75"
      fill="none"
      stroke="red"/>
  </svg>
</body>
</html>

通俗的講,可以認為viewBox建立一個放置於畫布上的框,一些圖案位於此框中,然後移動這個框(框中的圖案會跟隨移動),讓框的左上角與視窗的左上角對齊,然後進行縮放操作。總之,viewBox建立一個新的使用者座標系,應用此屬性的元素的後代會在這個新的使用者座標系中定位和確定尺寸,而不是初始座標系。

二.preserveAspectRatio屬性:

上面程式碼,viewBox建立"視框"的尺寸和SVG視窗等比例,能夠恰好縮放填滿視窗。

實際應用中,總有比例不相等的情況,此時,preserveAspectRa屬性的作用得以體現。

語法結構:

[XML] 純文字檢視 複製程式碼
preserveAspectRatio = defer? <align> <meetOrSlice>?

defer引數可選,只有在<image>應用preserveAspectRatio才被用到,不是本文關鍵,暫且不管。

引數解析:

(1).align:規定viewBox如何與SVG viewport對齊方式。

(2).meetOrSlice:可選,規定如何維持高寬比。

先看一個簡單的程式碼片段:

[XML] 純文字檢視 複製程式碼
preserveAspectRatio="xMidYMid meet"

從xMidYMid(預設值)可以看出,對齊方式需要橫向和縱向共同完成。

分解如下:

(1).xMin:viewport和viewBox左邊對齊。

(2).xMid:viewport和viewBox x軸中心對齊。

(3).xMax:viewport和viewBox右邊對齊。

(4).YMin:viewport和viewBox上邊緣對齊。

(5).YMid:viewport和viewBox y軸中心點對齊。

(6).YMax:viewport和viewBox下邊緣對齊。

特別說明:注意大小寫,和駝峰命名規則相同。

再來看meetOrSlice引數:

(1).meet:預設值,保持縱橫比縮放viewBox適應viewport。

(2).slice:保持縱橫比同時比例小的方向放大填滿viewport。

(3).none:扭曲縱橫比以充分適應viewport。

這應該是很好理解的,看一個簡單的程式碼例項:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
svg {
  border: 1px solid blue;
  width: 400px;
  height: 200px;
  overflow: visible;
}
</style>
</head>
<body>
  <svg viewBox="0 0 200 50" preserveAspectRatio="xMinYMin meet">
    <rect
      x="0" y="0"
      width="200" height="50"
      fill="blue" />
  </svg>
</body>
</html>

為了便於觀察出效果,將rect尺寸與viewBox尺寸設定為相同。

xMinYMin表示視框與視窗左上對齊,meet表示保持縱橫比例進行縮放,只要橫向或者縱向填充滿視窗即可。

再來看一段程式碼例項:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<style>
svg {
  border: 1px solid blue;
  width: 400px;
  height: 200px;
  overflow: visible;
}
</style>
</head>
<body>
  <svg viewBox="0 0 200 50" preserveAspectRatio="xMinYMin slice">
    <rect
      x="0" y="0"
      width="200" height="50"
      fill="blue" />
  </svg>
</body>
</html>

slice表示保持縱橫比例進行縮放,但是需要比例小的方向放大填滿viewport。

其他屬性就不挨個演示了,比較簡單,大家自行測試即可。

相關文章