はしくれエンジニアもどきのメモ

情報系技術・哲学・デザインなどの勉強メモ・備忘録です。

SVGのpreserveAspectRaitoとCanvasのdrawImage

SVGのpreserveAspectRaitoとCanvasのdrawImage

SVGの preserveAspectRatio と ブラウザによってCanvas のdrawImage の仕様が違ったのでメモ。

ブラウザ環境

以下のブラウザ環境で確認しました。

SVG のpreserveAspectRatio

SVG画像は、imgタグでwidth, heightを指定して表示できます。


<img src=".svg" width="100" height="100" alt="">

このとき、 SVG のpreserveAspectRatioプロパティは、 SVGを拡大・縮小したときにアスペクト比を固定しないかするか、 固定した場合、指定サイズの小さい方に合わせるか大きい方に合わせるか設定できる。

参考になる記事は以下。

指定方法は主に3つ。 meet, slice は、 基準点になるXMinYMin - XMaxYMax と組み合わせて使う

  • none
    縦横比を固定しない。

    ex.
    
    <svg preserveAspectRatio="none" >
    ~~~
    </svg >
    
    
  • meet
    縦横比を固定して、指定画像サイズの小さい方に合わせる。 そのため、画像全体が描画される。

    ex.
    
    <svg preserveAspectRatio="XMidYMid meet" >
    ~~~
    </svg >
    
  • slice
    縦横比を固定して、 指定画像サイズの大きい方に合わせる。 はみ出した部分は切り捨てられる。

    ex.
    
    <svg preserveAspectRatio="XMidYMid slice" >
    ~~~
    </svg >
    

実際にサイズ指定して比較してみたサンプルです。 

codepen.io

まとめると、

  1. imgタグで、width, height を指定しないと、 SVGのwidth, heightのサイズで画像が表示される。

  2. imgタグで、widthまたは height を片方がだけ指定すると、 指定したほうは指定サイズになり、指定していない方は縦横比固定で自動的に決まる。   

  3. imgタグで、width, height を両方指定して縦横比が守られている場合、 指定サイズのまま表示される。

  4. imgタグで、width, height を両方指定して縦横比が違う場合、 SVGで指定しているpreserveAspectRatio の通りに描画される。

preserveAspectRatioプロパティが未指定の場合

そもそも、preserveAspectRatioプロパティが未指定の場合どうなるのか。 おそらくブラウザの実装で決まると思うのですが、 どうやらChrome, Firefox共に、 XMidYMid meet と同じになるようです。 縦横比固定で、小さい方に合わせて中心からスケール変更されます。 なので、preserveAspectRatio="none" を指定しないかぎり、 縦横比固定のりサイズしかできないことになります。

CanvasのdrawImage

SVG画像は、CanvasdrawImage(); でwidth とheight を指定してCanvas に描画することができます。

ここで、上記のSVG のpreserveAspectRatio を踏まえて、drawImage()で、width, heightを変更して同じように描画されるか見てみます。


var ctx = canvas.getContext('2d');
var svg_img = new Image();
svg_img.src = '~~~.svg';
svg_img.onload = function(){
  var width = this.width;
  var height = this.height;
  ctx.drawImage(this, 0, 0, width*2, heihgt); //width2倍で描画など
};

preserveAspectRatio指定なしのSVGCanvasに描画したサンプル

(Firefoxでは縦横比固定で表示され、Chromeでは横長に描画される。)

codepen.io

どうやら、Firefoxでは、 SVG画像をimgタグで読み込んだととき同じ挙動(preserveAspectRatioプロパティが有効)して、 一方、Chrome では、preserveAspectRatioプロパティが有っても無くても、縦横比関係なくwidth, height を変更( preserveAspectRatio="none" のような挙動)できるようです。

drawImage(firefox)
Firefox
drawImage(chrome)
Chrome

対処

なので、Canvasに描画する際のスケール変更は、 ブラウザによって動作が変わる場合があります。

思いつく対処としては、SVG画像をpreserveAspectRatio="none" としておくことです。 これで、Firefox, Chrome 共に、縦横比関係なくスケール変更できます(縦横比の固定もできます)。

また、この挙動は、CanvasライブラリであるCreateJS(EaselJS 0.8.1) の SVG画像で生成したBitmapインスタンスでも同じように起きるので注意が必要です。