ズッキーニのプログラミング実験場

プログラミング + アカデミック + 何か面白いこと。 記載されているものは基本的に私が所属する団体とは関係がありません。

   Jun 12

[CoffeeScript]HTML5のCanvasでアニメーション

by zuqqhi2 at 2013年6月12日
Pocket

とある統計のアルゴリズムの動きを視覚的に確認したいがために、
それの全段階としてCoffeeScriptとHTML5のCanvasでアニメーション処理を書いてみた。

まずmain.coffee。

Point2D = require('../src/point2d').Point2D

main = ()->
    canvas = document.getElementById('canvas')
    context = canvas.getContext('2d')

    num_points = 9
    labels = ["abc", "bcd", "cde", "def", "efg", "fgh", "ghi", "hij", "ijk", "jkl"]
    points = []
    for i in [0..num_points]
        x = canvas.width /2 + Math.floor(Math.random() * 200) - 100
        y = canvas.height /2 + Math.floor(Math.random() * 200) - 100
        vx = Math.random() * 5.0 - 2.5
        vy = Math.random() * 5.0 - 2.5

        points.push new Point2D(x, y, 10, vx, vy, labels[i], canvas.width, canvas.height, context)
        points[i].draw()

    mainloop = ()->
        context.save()
        context.beginPath()
        context.clearRect(0, 0, canvas.width, canvas.height)
        context.restore()
        
        for i in [0..num_points]
            points[i].update_position()
            points[i].reflect()
            points[i].draw()

        setTimeout(mainloop, 30)

    mainloop()

window.onload = main

次に、2次元のデータ点を表現するpoint2d.coffee。

class Point2D
    constructor: (x, y, r, vx, vy, label, wnd_width, wnd_height, context) ->
        @x = x
        @y = y
        @r = r
        @vx = vx
        @vy = vy
        @label = label
        @wnd_width = wnd_width
        @wnd_height = wnd_height
        @context = context

    update_position: ->
        @x += @vx
        @y += @vy

    reflect: ->
        if @x - @r < 0
            @x = @r
            @vx *= -1.0

        if @x + @r > @wnd_width
            @x = @wnd_width - @r
            @vx *= -1.0

        if @y - @r < 0
            @y = @r
            @vy *= -1.0

        if @y + @r > @wnd_height
            @y = @wnd_height - @r
            @vy *= -1.0
        
    draw: ->
        @context.beginPath()
        @context.strokeStyle = '#00F'
        @context.fillStyle = '#00F'
        @context.arc(@x, @y, @r, 0, Math.PI * 2, false)
        @context.fill()
        @context.stroke()
        @context.restore()

        @context.beginPath()
        @context.font = "18px 'MS Pゴシック'"
        @context.fillStyle = "blue"
        @context.fillText(@label, @x, @y-@r)
        @context.restore()

exports.Point2D = Point2D

無駄にテストコードも書いてしまった。
ちなみにjasmine-nodeを使っております。

Point2D = require('../src/point2d').Point2D

describe "Point2D", ->
    p1 = undefined
    p2 = undefined
    p3 = undefined
    p4 = undefined
    p5 = undefined
    p6 = undefined
    
    beforeEach ->
        p1 = new Point2D(0, 0, 0, 0, 0, "", 0, 0, undefined)
        p2 = new Point2D(100, 200, 30, 2.0, 2.0, "test", 640, 480, undefined)
        p3 = new Point2D(5, 200, 30, 2.0, 2.0, "test", 640, 480, undefined)
        p4 = new Point2D(630, 200, 30, 2.0, 2.0, "test", 640, 480, undefined)
        p5 = new Point2D(100, 10, 30, 2.0, 2.0, "test", 640, 480, undefined)
        p6 = new Point2D(100, 470, 30, 2.0, 2.0, "test", 640, 480, undefined)

    it "should be x and y axis value are 0", ->
        expect(p1.x).toEqual 0
        expect(p1.y).toEqual 0
        expect(p1.r).toEqual 0
        expect(p1.vx).toEqual 0
        expect(p1.vy).toEqual 0
        expect(p1.wnd_width).toEqual 0
        expect(p1.wnd_height).toEqual 0
        expect(p1.label).toEqual ""

    it "should be x and y axis value are 5, 10", ->
        expect(p2.x).toEqual 100
        expect(p2.y).toEqual 200
        expect(p2.r).toEqual 30
        expect(p2.vx).toEqual 2.0
        expect(p2.vy).toEqual 2.0
        expect(p2.wnd_width).toEqual 640
        expect(p2.wnd_height).toEqual 480
        expect(p2.label).toEqual "test"

    it "should add velocity for x and y to 102.0 and 202.0", ->
        p2.update_position()
        expect(p2.x).toEqual 102.0
        expect(p2.y).toEqual 202.0

    it "should reflect with left side", ->
        p3.reflect()
        expect(p3.x).toEqual 30
        expect(p3.vx).toEqual -2.0

    it "should reflect with right side", ->
        p4.reflect()
        expect(p4.x).toEqual 610
        expect(p4.vx).toEqual -2.0
    
    it "should reflect with left side", ->
        p5.reflect()
        expect(p5.y).toEqual 30
        expect(p5.vy).toEqual -2.0
    
    it "should reflect with left side", ->
        p6.reflect()
        expect(p6.y).toEqual 450
        expect(p6.vy).toEqual -2.0

ここまでの実行結果はこんな感じ。
animation

さて、後は多次元尺度構成法のアルゴリズムを乗っければ完成だ。

Related Posts

Pocket

You can follow any responses to this entry through the RSS 2.0 feed. Both comments and pings are currently closed.