LoginSignup
1
3

More than 5 years have passed since last update.

Snap.svgで内側領域の塗り分けの設定(fill-rule)に気をつけようという話

Last updated at Posted at 2017-12-03

Snap.svg、すごいですよね。
あれでアニメーション作るとめちゃ楽しいですね。

さて、遊んでいる時に、困ったことがあり、数十分作業が止まったので、それの解決方法をメモしておきます。

環境

  • Snap.svg 0.5.1 (読み込んで使用)
  • Firefox 57.0.1 (表示用ブラウザ)
  • InkScape 0.92 (パス作成用)

内側が思ったように塗り分けられなかった

問題のPath図形

問題のPath図形は以下の様なものです。長いので、以後省略と書きます。
(パスが異常に長いのは、趣味垢用に作っていたものの流用なので許してください。)

m 208.90541,109.29049 
a 2.776174,1.2825703 56.427847 0 1 0.17457,2.82556 2.776174,1.2825703 56.427847 0 1 -2.63953,-1.92948 2.776174,1.2825703 56.427847 0 1 -0.17457,-2.82557 2.776174,1.2825703 56.427847 0 1 2.63953,1.92949 
z 
m -7.6781,-9.03334 
c -1.38619,7.72423 -0.87929,12.29629 2.92643,15.66947 3.63687,2.44904 6.89158,-0.27701 7.59069,-3.58952 l 7.31827,3.98818 -3.91191,-7.35347 c 4.18733,-0.94355 5.73619,-4.5737 3.68133,-7.54654 -3.13739,-3.778909 -8.23264,-4.527779 -15.63278,-3.116419 -0.0367,0.008 0.48808,-1.9531 0.48808,-1.9531 0.70114,-0.23214 2.17497,-0.7302 2.17431,-1.07625 -0.003,-0.31091 -2.15625,-0.73908 -2.15625,-0.73908 -0.4811,0.26621 -1.18982,1.43616 -1.95937,2.67939 -0.94574,-0.51419 -2.17534,-1.16488 -2.49479,-0.88413 -0.24015,0.24378 0.29808,1.47343 0.9046,2.45516 0,0 -2.71018,1.650499 -2.70297,1.926699 0.043,0.0607 0.41039,2.18349 0.72963,2.16888 0.32026,-0.006 0.9949,-1.77835 1.08578,-2.16491 0,0 2.00074,-0.47543 1.95888,-0.46435 
z 
m 10.86239,5.84155 
a 2.7761738,1.2825702 34.267371 0 0 2.82323,0.20883 2.7761738,1.2825702 34.267371 0 0 -1.89732,-2.66272 2.7761738,1.2825702 34.267371 0 0 -2.82323,-0.20885 2.7761738,1.2825702 34.267371 0 0 1.89732,2.66274 
z

InkScapeで以下のようなSVGファイルを作り、読み込みました。

sample_risou.html
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="420px" height="297px" style="background-color:#B2243C"> <path
       id="path8443-6-3"
       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.29069689;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
       d="省略"
       inkscape:connector-curvature="0"
       inkscape:label="center_icon" /></svg>

すると、下のように表示されます。
正しい写真.PNG

うまく行かなかったソース

sample.html
  <script src="./snap.svg.js"></script>
  <svg id="p" version="1.1" xmlns="http://www.w3.org/2000/svg"
    width="420px" height="297px"
    style="background-color:#B2243C"> 
  </svg>

このSVGに以下のようなソースでパス図形を表示させます。

sample.js
  Snap("#p").path(省略).attr({
    "fill":'#ffffff'
  })

で、longpathですが、
これを作画してみると、以下のようになってしまいます。
穴が一つしか空いていない写真.PNG

穴が一つしか空いていません。
これは大きな問題です。

原因

InkScapeが生成したSVGファイルの、長ったらしいstyle属性の中身に原因がありました。

  opacity:1;
  fill:#ffffff;
  fill-opacity:1;
  fill-rule:evenodd;
  stroke:none;
  stroke-width:0.29069689;
  stroke-linecap:round;
  stroke-linejoin:miter;
  stroke-miterlimit:4;
  stroke-dasharray:none;
  stroke-dashoffset:0;
  stroke-opacity:1;
  paint-order:fill markers stroke

多くは大したことのないデータですが、問題はこれの

  fill-rule:evenodd;

です。
これをうまくいかなかったJavaScriptに、

sample.js
  Snap("#p").path(省略).attr({
    "fill":'#ffffff',
    "fill-rule":"evenodd"
  });

このようにいれてやると、思った通りに表示されました。

解説

そもそも、何故、一つのパス図形で、内側でくり抜かれるという表現ができるかというと、SVGが"内側"についてのルールを定めているからなんです。
そのルールを指定してあげるのが、このfill-ruleでした。
SVG仕様(日本語訳)の当該説明箇所

自動生成で過剰に生成される長いソースの中に、とても重要な情報が含まれていることもあるので注意しよう、という話でした。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3