Translate

2020年8月22日 星期六

SVG 的 path

SVG 有一個超強的路徑設定功能 path , 可以用最少的字串,描述出任何的線段,這個設計肯定是工程師大腦做出來的,這個功能也是 SVG 最精華的部份,指令說明如下:

指令大寫表示絕對座標,小寫表示相對座標

M x,y               - 移動點位到 x,y
L x,y               - 線段到 x,y
H x                 - 橫線到 x
V y                 - 垂直線到 y
C x1,y1,x2,y2,x,y   - 貝滋曲線 x1,y1 和 x2,y2 為控制點,終點在 x,y
S x2,y2,x,y         - 貝滋曲線 x1,y1 為前一個曲線的映射點,新增控制點 x2,y2,終點在 x,y
Q x12,y12,x,y       - 貝滋曲線 x12=x1=x2 , y12=y1=y2 兩個控制點在同一點,終點在 x,y
T x,y               - 貝滋曲線,前面必須是 Q , 控制點為 Q 的映射點,終點在 x,y
Z                   - 連回線段的起點
A rx,ry,d,f1,f2,x,y - 圓弧 
    rx,ry : 橢圓長和寬的半徑, 如果長度小於和終點 x,y 的長度,則 rx,ry 會修正為和終點的距離
        d : 橢圓旋轉角度 (順時針)
       f1 : 0=小角度弧線, 1=大角度弧線
       f2 : 0=逆時針方向, 1=順時針方向
      x,y : 終點

範例 :



<svg style="width:120px;height:120px;border:1px solid black">
<g style="stroke:#0000ff;fill:none">
  <path d="M10,50 L50,10 H100 V50 C100,100,20,100,50,50 Z"></path>
</g>
<g style="stroke:#ff0000;fill:none">
  <circle cx="100" cy="100" r="3"></circle>
  <circle cx="20" cy="100" r="3"></circle>
  <line x1="100" y1="50" x2="100" y2="100"></line>
  <line x1="20" y1="100" x2="50" y2="50"></line>
</g>
</svg>

<svg style="width:140px;height:120px;border:1px solid black">
<g style="stroke:#0000ff;fill:none">
  <path d="M10,50 C20,10,40,10,50,50 S120,100,100,50"></path>
</g>
<g style="stroke:#ff0000;fill:none">
  <circle cx="20" cy="10" r="3"></circle>
  <circle cx="40" cy="10" r="3" fill="#0f0"></circle>
  <circle cx="60" cy="90" r="3" fill="#0f0"></circle>
  <circle cx="120" cy="100" r="3"></circle>
  <line x1="10" y1="50" x2="20" y2="10"></line>
  <line x1="40" y1="10" x2="60" y2="90" stroke="#0c0"></line>
  <line x1="120" y1="100" x2="100" y2="50"></line>
</g>
</svg>

<svg style="width:120px;height:120px;border:1px solid black">
<g style="stroke:#0000ff;fill:none">
  <path d="M10,50 Q20,10,50,50 T100,50"></path>
</g>
<g style="stroke:#ff0000;fill:none">
  <circle cx="20" cy="10" r="3" fill="#0f0"></circle>
  <circle cx="80" cy="90" r="3" fill="#0f0"></circle>
  <line x1="10" y1="50" x2="20" y2="10"></line>
  <line x1="20" y1="10" x2="80" y2="90" stroke="#0c0"></line>
  <line x1="80" y1="90" x2="100" y2="50"></line>
</g>
</svg>
<br>

svg 最難理解的 Arc 這裡設了幾個範例,當旋轉 90 度後的紫色,因為短邊半徑 30 , 等於直徑 60 小於離終點的距離 (100) ,於是依照比例被放大了<br>

<svg style="width:220px;height:180px;border:1px solid black">
<g style="stroke:#0000ff;fill:none;stroke-width:2">
  <path d="M10,50 L50,50 A70,30, 0,0,0,150,50 L200,50" stroke="#00f"></path>
  <path d="M10,50 L50,50 A70,30, 0,1,0,150,50 L200,50" stroke="#f00"></path>
  <path d="M10,50 L50,50 A70,30,20,1,0,150,50 L200,50" stroke="#0d0"></path>
  <path d="M10,50 L50,50 A70,30,90,1,0,150,50 L200,50" stroke="#b0b"></path>
</g>
</svg>


svg 最難理解的 Arc 這裡設了幾個範例,當旋轉 90 度後的紫色,因為短邊半徑 30 , 等於直徑 60 小於離終點的距離 (100) ,於是依照比例被放大了

既然瞭解 path 的用法,就可以來畫一些有趣的圖了



<svg viewBox="-1,-1,102,102" style="width:100px;height:100px">
  <circle cx="50" cy="50" r="50" fill="#fff" stroke="#000"></circle>
  <path d="M50,0 A1,1,0,0,1,50,50 A1,1,0,0,0,50,100 A1,1,0,0,0,50,0" stroke="#000" fill="#000"></path>
  <circle cx="50" cy="25" r="5" fill="#000" stroke="#000"></circle>
  <circle cx="50" cy="75" r="5" fill="#fff" stroke="#fff"></circle>
</svg>

2020年8月21日 星期五

SVG 基礎

早期在 IE6 的時代接觸到 javascript ,覺得這個東西相當有趣,還可以搭配 java applet 做出很多效果,後來還用 java applet 開發電子地圖EGM 並利用 javascript 去控制 applet 中的物件;在那個時期想要在網頁上畫向量的點線面是相當麻煩的一件事,我當時的做法是利用 applet 來畫,後來得知還有另一個方式是 VML ,只是在當時只有 IE 支援,而且我要開發地圖需要更快的速度以及要解決網路傳輸的問題,最後還是選擇 applet ,當時甚至規劃了一整套 javascript 的 function ,可以在 applet 上畫向量,而如今瀏覽器已經不再支援 applet ,javascript 的功能也強大到足以取代 applet 和 flash

現在要在瀏覽器畫向量圖完全沒有問題,使用 SVG 不但功能強大,而且很多繪圖軟體都支援,和 javascript 的整合也相當完整,那麼就在這裡先整理 SVG 的基礎架構吧 !

svg 命名空間宣告,(如果沒有宣告,可能會看不到圖)
           xmlns="http://www.w3.org/2000/svg" 
           xmlns:xlink="http://www.w3.org/1999/xlink" 
           xmlns:ev="http://www.w3.org/2001/xml-events"

svg      - 最外層 svg 宣告,參數:
           width   - 寬
           height  - 高
           viewbox - 左上x 左上y 寬 高 (重新定義座標系)
           preserveAspectRatio - 預設為 xMidYMid meet
               參數組合為 xMin,xMid,xMax (注意 x 是小寫)
               加上 YMin,YMid,YMax (注意 Y 是大寫)
               加上空格後接 meet (填滿) 或 slice (裁切)  
               設為 none 會變形縮放

g        - group,相當於 layer
line     - 畫線,參數 x1,y1 畫到 x2,y2
polyline - 畫線,參數 points="x1,y1 x2,y2 x3,y3 ..."
polygon  - 畫面,參數 points="x1,y1 x2,y2 x3,y3 ..."
rect     - 矩形,參數 x,y,width,height,rx,ry (rx,ry 為圓角)
circle   - 畫圓,參數 cx,cy,r(半徑)
ellipse  - 橢圓,參數 cx,cy,rx,ry
text     - 文字,參數 x,y
image    - 圖片,參數 href="網址" x,y,width,height,preserveAspectRatio

共用參數 : **(CSS 有設定時以 CSS 設定優先)**
  stroke : "#顏色" , 線段顏色
  stroke-width : n , 線段寬度
  fill : "#顏色" , 填充顏色
  fill-rule : nonzero 或 evenodd

關於 preserveAspectRatio 的值同 svg 參數,可以參考 這裡 ,底下的範例設為 none 這樣圖片才會跟著設定的大小變形

範例:


<style>
.a08211_c1
{
  stroke:#000;
  stroke-width:3;
  fill:none;
}
.a08211_c2
{
  stroke:#f00;
  fill:#ff0;
  stroke-width:3;
  font-size:54px;
}
</style>

<svg width="300" height="300" viewBox="0 0 350 300" preserveAspectRatio="xMidYMid meet" style="background-color:#ddddff">
  <g id="a08211_layer1" class="a08211_c1">
    <line x1="0" y1="0" x2="100" y2="20"></line>
    <line x1="0" y1="10" x2="100" y2="30" stroke="#ff0000"></line>
    <line x1="0" y1="20" x2="100" y2="40" stroke="#ff0000" style="stroke:#00ff00"></line> 
    <!-- 當 css 的 style 設定 stroke 後,本來的 stroke 設定就被蓋掉了 -->
    <polyline points="120,5 200,5 200,40 160,40"></polyline>
    <polygon points="120,65 200,65 200,100 160,100"></polygon>
  </g>
  <g id="a08211_layer2" class="a08211_c2">
    <rect x="10" y="60" width="60" height="40" rx="20" ry="10"></rect>
    <circle cx="40" cy="160" r="30"></circle>
    <ellipse cx="150" cy="160" rx="50" ry="30"></ellipse>
    <polyline points="220,5 300,5 300,40 260,40"></polyline>
    <polygon points="220,65 300,65 300,100 260,100"></polygon>
    <text x="210" y="180">123</text>
    <image href="https://yiharng.github.io/bird.jpg" x="0" y="200" width="300" height="100" preserveAspectRatio="none"></image>
  </g>
</svg>
123

2020年8月13日 星期四

css 的 mask

CSS 有一個小功能是 mask , 可以用來製作遮罩,和 clip-path 不同的地方是,他可以用漸層或用另一個圖片的 alpha 來做裁切, 範例如下 :



<style>
.a08131_aa
{
  width:300px;
  -webkit-mask-image:repeating-linear-gradient(0deg, 
      #00000000,#000000ff 25%,#00000000 50%),
repeating-linear-gradient(90deg, 
      #00000000,#000000ff 25%,#00000000 50%)
}
.a08131_bb
{
  width:300px;
  -webkit-mask-image:repeating-radial-gradient(
      #000000ff,#00000000 50%,#00000088);
}
.a08131_cc
{
  width:300px;
  -webkit-mask:url(https://yiharng.github.io/bomb.png) 0 0/150px 80px repeat ;
}
</style>

<img class="a08131_aa" src="https://yiharng.github.io/bird.jpg">
<img class="a08131_bb" src="https://yiharng.github.io/bird.jpg">
<img class="a08131_cc" src="https://yiharng.github.io/bird.jpg">

完整語法是 :

-webkit-mask: url(圖片) x y/寬 高 repeat;

-webkit-mask-image: url(圖片);
-webkit-mask-position: x y;
-webkit-mask-size: 寬 高;
-webkit-mask-repeat: repeat 或 no-repeat;

其它更詳細的參數可以參考 https://developer.mozilla.org/zh-CN/docs/Web/CSS/mask