Aquarium 0.1

水族館のアニメーションを SVG.js で描いてみました。 ブラウザの再読み込みボタンで魚の位置を変えられます。

実行結果

生成されたコード


ソース


aquarium01.html

SVG.js ライブラリと JavaScript のソースファイルを指定します。
<script type="text/javascript" src="js/svg.min.js"></script>
<script type="text/javascript" src="js/aquarium01.js"></script>
実行結果のところには "svg" という id の div 要素と "code" という id の pre 要素を用意しました。中身は aquarium01.js の中で作って入れます。
<h2>実行結果</h2>
<div id="svg">
</div>
<h3>生成されたコード</h3>
<pre id="code" class="brush: xml; class-name: 'code'">
</pre>

aquarium01.js

今回は window.onload() だけでは表しきれず、新たに moveFish() を作り、 setInterval() で 400ms 毎に呼び出すようにしました。 moveFish() で作った SVG コードを「生成されたコード」に表示しようと試みましたが、 うまくいかないのでやめました。

const width = 400;  // of fish tank
const height = 300; //
const depth = 230;  //
var x;              //
var y;              //
const delay = 400;  // [ms]
const max = 3;
var draw;           // SVG
var fish;           // fish
var a = [max];      // angle
var da = [max];     // delta angle
var use = [max];    // for fish
var fy = [max];

/**
 * moveFish function
 * @since 0.1
 */
const moveFish = function() {
    for (i = 0; i < max; i++) {
        a[i] += da[i];
        if (a[i] > 2 * Math.PI) {
            a[i] -= 2 * Math.PI;
        }
        _x = x + Math.round((width * 0.4) * Math.cos(a[i])) + width * 0.5;
        use[i].move(_x - fish.width() / 2, fy[i] - fish.height() / 2);
        use[i].transform({scaleX: -Math.round(Math.sin(a[i]) * 1000) / 1000});
    }
}

/**
 * onload function
 * @since 0.1
 */
window.onload = function() {
    // Generate svg element
    //<svg width="640" height="400" style="background-color: #333; border: solid 1px lightgray">
    draw = SVG().addTo('#svg').size(640, 400).css('border', 'solid 1px lightgray');
    //<defs>
    //<g id="fish">
    fish = draw.defs().group({id: 'fish'});
    //  <rect x="0" y="5" width="30" height="10" 
    //    style="fill:royalblue;fill-opacity:0.6;stroke:#273f87;stroke-opacity:0.6;stroke-width:2"/>
    fish.rect(30, 10).move(0, 5).fill({color: 'royalblue', opacity: 0.6}).stroke({color: '#273f87', opacity: 0.6, width: 2});
    //  <ellipse cx="40" cy="10" rx="20" ry="10" 
    //    fill="royalblue" stroke="#273f87"/>
    fish.ellipse().attr({cx: 40, cy: 10, rx: 20, ry: 10}).fill('royalblue').stroke({color: '#273f87', width: 2});
    //  <ellipse cx="50" cy="10" rx="5" ry="5" 
    //    fill="black" stroke="white"/>
    fish.ellipse().attr({cx: 50, cy: 10, rx: 5, ry: 5}).fill('black').stroke({color: 'white', width: 2});
    //</defs>
    //<rect x="0" y="0" width="640" height="400" 
    //  style="fill:#333"/>
    draw.rect(640, 400).fill({color: '#333'}).stroke('none');
    x = Math.round((640 - width) / 2);
    y = Math.round((400 - height) / 2);
    draw.rect(400, 300).move(x, y).fill('none').stroke({color: 'white', width: 2});
    //<use xlink:href="#fish" x="?" y="?"/>
    for (i = 0; i < max; i++) {
        a[i] = Math.random() * 2 * Math.PI;
        da[i] = (Math.random() * 5 + 5) / 360 * 2 * Math.PI;
        _x = x + Math.round((width * 0.4) * Math.cos(a[i])) + width * 0.5;
        fy[i] = y + (height - depth) + Math.round(Math.random() * (depth * 0.8)) + depth * 0.1;
        use[i] = draw.use(fish).move(_x - fish.width() / 2, fy[i] - fish.height() / 2);
        use[i].transform({scaleX: -Math.round(Math.sin(a[i]) * 1000) / 1000});
    }
    //<rect x="0" y="0" width="400" height="300"
    //  style="fill:lightseagreen;fill-opacity:0.1;stroke:white;stroke-width:2"/>
    //  style="fill:;fill-opacity:0.1"/>
    _x = Math.round((640 - width) / 2);
    _y = Math.round((400 - height) / 2) + (height - depth);
    draw.rect(width, depth).move(_x, _y).fill({color: 'lightseagreen', opacity: 0.1}).stroke('none');
    //</svg>
    var svgNode = document.getElementById('svg').children[0];
    var codeNode = document.getElementById('code');
    // Get generated SVG code
    var svgText = new XMLSerializer().serializeToString(svgNode);
    // Show the code with additional new lines
    codeNode.textContent = svgText.replace(/></g, '>\n<');
    setInterval(moveFish, delay);
}

参考文献

このプログラムは以下の情報またはソフトウェアを参照しています。