みかづきブログ その3

3ヶ月つづけてみました。

Canvasで落書き 2.2.0

前回つくったもの にマウスのスピードに応じてLineの太さを変更する機能を追加しました。


Canvasで落書き 2.1.0 - みかづきブログ その3

マウスをすばやく動かしたときほどLineが細くなります。

DEMO


JavaScript

Point.js

(function(win, doc, ns) {

    "use strict";

    // インスタンスをつくる際にサイズを渡せるように変更
    function Point(x, y, opt_size) {
        var _this = this;

        _init();

        function _init() {
            ns.EventDispatcher.call(_this);
        }

        _this.x    = x;
        _this.y    = y;
        _this.size = opt_size || 1;
    }

    Point.prototype = new ns.EventDispatcher();
    Point.prototype.constructor = Point;

    Point.prototype.setSize = function(size) {
        var _this = this;
        
        _this.size = size;
    };
    
    Point.prototype.draw = function(ctx, opt_size) {
        var _this = this,
            size  = opt_size || _this.size || 1;

        ctx.save();
            ctx.beginPath();
            ctx.arc(_this.x, _this.y, size, 0, Math.PI * 2, false);
            ctx.fill();
            ctx.moveTo(_this.x, _this.y);
        ctx.restore();

        return _this;
    };

    // 2つのPointの距離を返すクラスメソッドを追加
    Point.getDistance = function(pointA, pointB) {
         return Math.sqrt(Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2));
    };
    
    ns.Point = Point;

})(this, document, App);

Line.js

(function(win, doc, ns) {

    "use strict";

    var Point = ns.Point;

    function Line(opt_point) {
        var _this = this,
            pointList = [];

        _init();

        function _init() {
            ns.EventDispatcher.call(_this);
            _this.pointList = pointList;
            
            if (opt_point) {
                _this.push(opt_point);
            }
        }
    }

    Line.prototype = new ns.EventDispatcher();
    Line.prototype.constructor = Line;

    Line.prototype.push = function(pointModel) {
        var _this = this;

        _this.pointList.push(pointModel);
    };

    Line.prototype.drawLine = function(ctx) {
        var _this     = this,
            pointList = _this.pointList,
            length    = pointList.length,
            i;

        ctx.save();
            ctx.lineCap  = "round";
            ctx.lineJoin = "round";

        if (length > 1) {
            for (i = 1; i < length; ++i) {
                ctx.beginPath();
                    ctx.moveTo(pointList[i - 1].x, pointList[i - 1].y);
                    ctx.lineTo(pointList[i].x, pointList[i].y);
                    ctx.lineWidth = pointList[i].size; // lineWidthを設定できるように変更
                ctx.stroke();
            }
        } else {
            pointList[0].draw(ctx);
        }

        ctx.restore();        
    };

    Line.prototype.drawQuadraticCurve = function(ctx) {
        var _this              = this,
            pointList          = _this.pointList,
            length             = pointList.length,
            quadraticPointList = [],
            lastIndex          = 0,
            i;

        ctx.save();
            ctx.lineCap  = "round";
            ctx.lineJoin = "round";

            if (length > 1) {
                quadraticPointList[lastIndex] = pointList[0];

                ctx.beginPath();
                    ctx.moveTo(quadraticPointList[0].x, quadraticPointList[0].y);

                    for (i = 1; i < length; ++i) {
                        quadraticPointList[++lastIndex] = new Point(
                            (quadraticPointList[lastIndex - 1].x + pointList[i].x) / 2,
                            (quadraticPointList[lastIndex - 1].y + pointList[i].y) / 2
                        );
                        quadraticPointList[++lastIndex] = (pointList[i]);
                            ctx.quadraticCurveTo(
                                quadraticPointList[i * 2 - 2].x,
                                quadraticPointList[i * 2 - 2].y,
                                quadraticPointList[i * 2 - 1].x,
                                quadraticPointList[i * 2 - 1].y
                            );
                        ctx.lineWidth = pointList[i].size; // lineWidthを設定できるように変更
                        ctx.stroke();
                        ctx.beginPath();
                            ctx.moveTo(quadraticPointList[i * 2 - 1].x, quadraticPointList[i * 2 - 1].y);
                    }
                    ctx.lineTo(quadraticPointList[lastIndex].x, quadraticPointList[lastIndex].y);
                ctx.stroke();
            } else {
                pointList[lastIndex].draw(ctx);
            }
        ctx.restore();
    };

    ns.Line = Line;

})(this, document, App);

main.js

(function(win, doc, ns) {

    "use strict";
    
    var SIZE = 10,
        _getAve = _buildGetAve(10);
    
    function _buildGetAve(opt_maxLength) {
        var index     = 0,
            array     = [],
            maxLength = opt_maxLength || 10;

        function _ave() {
            var length = array.length,
                sum    = 0,
                i;

            for (i = 0; i < length; ++i) {
                sum += array[i];
            }

            return sum / length;
        }

        function getAve(val) {
            array[index] = val;
            index = (index + 1) % maxLength;

            return _ave();
        }

        return getAve;
    }
    
    // 2点間の距離からポイントのサイズを割り出す関数を追加
    function _getSize(l) {
        var MAX_DISTANCE = 100,
            width;
        
        if (l > MAX_DISTANCE) {
            width =  1;
        } else {
            width =  (MAX_DISTANCE - l) * SIZE / MAX_DISTANCE;
        }
        
        _getAve(width);
        
        return _getAve(width);
    }
    
    var ticker      = new ns.Ticker(60),
        lineManager = ns.LineManager.getInstance(),
        canvas      = doc.getElementById("canvas"),
        ctx         = canvas.getContext("2d"),
        fps         = doc.getElementById("fps"),
        START_EVENT = "mousedown",
        MOVE_EVENT  = "mousemove",
        END_EVENT   = "mouseup";

    setup();

    function setup() {
        addSketchEventForCanvas(canvas);

        ticker.addEventListener("tick", function(evt) {
            fps.innerHTML = evt.measuredFPS;
            update(evt.delta);
            draw();
        });

        ticker.start();
    }

    function update(delta) {
    }

    function draw() {
        canvas.width = win.innerWidth;
        canvas.height = win.innerHeight;

        ctx.save();
            ctx.fillStyle = ctx.strokeStyle = "rgba(0, 0, 255, 1)";
            lineManager.drawQuadraticCurve(ctx);
        ctx.restore();
    }

    function addSketchEventForCanvas(elm) {
        var throttle     = new ns.Throttle(10, handleThrottleMoveEvent),
            ctx          = elm.getContext("2d"),
            positionList = [],
            lastPoint = null,
            index = 0;
        
        elm.addEventListener(START_EVENT, handleStartEvent, false);
        doc.addEventListener(END_EVENT,   handleEndEvent,   false);

        function handleThrottleMoveEvent(evt) {
            var currentPoint = new ns.Point(evt.offsetX, evt.offsetY);

            currentPoint.setSize(_getSize(ns.Point.getDistance(lastPoint, currentPoint)));
            lastPoint = currentPoint;
            lineManager.addPoint(currentPoint);
        }
        
        function handleStartEvent(evt) {
            lastPoint = new ns.Point(evt.offsetX, evt.offsetY, SIZE / 2);
  
            lineManager.push(new ns.Line(lastPoint));
            elm.addEventListener(MOVE_EVENT, handleMoveEvent, false);
        }
        
        function handleMoveEvent(evt) {
            throttle.fireEvent(evt);
        }
        
        function handleEndEvent(evt) {
            elm.removeEventListener(MOVE_EVENT, handleMoveEvent, false);
            lastPoint = null;
        }
    }

})(this, document, App);

以上、こんなかんじになりました。