使用canvas画一个亮点跟随线移动的动画功能

原创
2017/08/15 14:15
阅读数 1.7K

效果:

canvas-line.js 代码:

(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
	typeof define === 'function' && define.amd ? define(factory) :
	(global.TrackLine = factory());
}(this, (function () { 'use strict';

var tool = {
    //计算两点间距离
    getDistance: function getDistance(p1, p2) {
        return Math.sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1]));
    }
};

var global = typeof window === 'undefined' ? {} : window;

var requestAnimationFrame = global.requestAnimationFrame || global.mozRequestAnimationFrame || global.webkitRequestAnimationFrame || global.msRequestAnimationFrame || function (callback) {
    return global.setTimeout(callback, 1000 / 60);
};

var TrackLine = function TrackLine(userOptions) {
    //全局参数
    var self = this;
    var canvas = document.getElementById("path");
    var context = canvas.getContext('2d');
    var width = canvas.width || window.innerWidth;
    var height = canvas.height || window.innerHeight;
    var lines = []; //所有线条
    canvas.style.cssText = "position:absolute;" + "left:0;" + "top:0;" + "z-index:0;user-select:none;";

    //默认参数
    var options = {
        lineWidth: 1,
        strokeStyle: '#F9815C',
        isShowLine: true,
        isAnimate: true,
        radius: 3,
        shadowBlur: 6,
        shadowColor: '#fff',
        speed: 1
    };

    //参数合并
    var merge = function merge(userOptions, options) {
        Object.keys(userOptions).forEach(function (key) {
            options[key] = userOptions[key];
        });
    };

    //线条
    function Line(options) {
        this.options = options;
        this.fillStyle = options.fillStyle || "#F9815C";
        this.turnPoints = options.data || [[100,120],[200,120],[200,180],[100,180],[100,120]];//画一个四方形
        this.step = 0;
        this.pointList = options.pointList || this.getPointList();
    }

    Line.prototype.getPointList = function () {
        var turnPoints = this.turnPoints;
        var pointList = this.pointList = [];
        if (turnPoints.length < 2) {
            return [];
        }
        for (var i = 0; i < turnPoints.length; i++) {
            var start = turnPoints[i];
            var end = turnPoints[i + 1];
            if (start && end) {
                var distance = Math.floor(tool.getDistance(start, end));
                var vx = (end[0] - start[0]) / distance;
                var vy = (end[1] - start[1]) / distance;
                for (var j = 0; j < distance; j++) {
                    pointList.push([start[0] + vx * j, start[1] + vy * j]);
                }
            }
        }
    };

    Line.prototype.draw = function (context) {
        var pointList = this.turnPoints;
        if (pointList.length >= 2) {
            context.save();
            context.beginPath();
            context.lineWidth = options.lineWidth;
            context.strokeStyle = options.strokeStyle;
            for (var i = 0; i < pointList.length; i++) {
                var x = pointList[i][0];
                var y = pointList[i][1];
                if (i == 0) {
                    context.moveTo(x, y);
                } else {
                    context.lineTo(x, y);
                }
            }
            context.stroke();
            context.restore();
        }
    };

    Line.prototype.drawMoveCircle = function (context) {
        var pointList = this.pointList || this.getPointList();

        context.save();
        context.fillStyle = options.fillColor;
        context.shadowColor = options.shadowColor;
        context.shadowBlur = options.shadowBlur;
        context.beginPath();
        context.arc(pointList[this.step][0], pointList[this.step][1], options.radius, 0, Math.PI * 2, true);
        context.fill();
        context.closePath();
        context.restore();
        this.step += options.speed;
        if (this.step >= pointList.length) {
            this.step = 0;
        }
    };

    //初始化线条
    var createLine = function createLine() {
        var lines = self.lines = [];
        for (var i = 0; i < options.data.length; i++) {
            lines.push(new Line(options.data[i]));
        }
    };

    //渲染
    var render = function render() {
        
        context.fillStyle = 'rgba(0,0,0,.93)';
        var prev = context.globalCompositeOperation;
        context.globalCompositeOperation = 'destination-in';
        context.fillRect(0, 0, width, height);
        context.globalCompositeOperation = prev;

        var lines = self.lines;
         //静态背景线条渲染
         for (var i = 0; i < lines.length; i++) {
             lines[i].draw(context);
         }
        //动画渲染
        for (var j = 0; j < lines.length; j++) {
            lines[j].drawMoveCircle(context); //移动圆点
        }
    };

    //初始化
    var init = function init(options) {
        merge(userOptions, options);

        createLine();

        (function drawFrame() {
            requestAnimationFrame(drawFrame);
            render();
        })();
    };

    init(options);
    self.options = options;
};

return TrackLine;

})));

HTML源码:

<!DOCTYPE html>
<html>

<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<style type="text/css">
    canvas {
        background-color: black;
    }
</style>
</head>

<body>
    <canvas id="path" width="500" height="500"></canvas>
    <script type="text/javascript" src="dat.gui.js"></script>
    <script type="text/javascript" src="canvas-line.js"></script>
    <script type="text/javascript">

        var data = [[[70,70],[120,120],[140,140]]];

        var moveLine = new TrackLine({
            //marker点半径
            markerRadius: 2,
            //marker点颜色,为空或null则默认取线条颜色
            markerColor: null,
            //线条类型 solid、dashed、dotted
            lineType: 'solid',
            //线条宽度
            lineWidth: 1,
            //线条颜色
            colors: ['#F9815C', '#F8AB60', '#EDCC72', '#E2F194', '#94E08A', '#4ECDA5'],
            //移动点半径
            radius: 3,
            //移动点颜色
            fillColor: '#fff',
            //移动点阴影颜色
            shadowColor: '#fff',
            //移动点阴影大小
            shadowBlur: 10,

            data: data
        });

        var options = {
            //移动点半径
            moveRadius: 2,
            //移动点颜色
            fillColor: '#fff',
            //移动点阴影颜色
            shadowColor: '#fff',
            //移动点阴影大小
            shadowBlur: 10,
        };

        function finished() {
            moveLine.update(options);
        }

        var gui = new dat.GUI({
            nameMap: {
                moveRadius: '移动点半径',
                fillColor: '移动点颜色',
                shadowColor: '移动点阴影颜色',
                shadowBlur: '移动点阴影大小',
            }
        });

        finished();
        gui.add(options, 'moveRadius', 1, 10).onFinishChange(finished);
        gui.addColor(options, 'fillColor').onChange(finished);
        gui.addColor(options, 'shadowColor').onChange(finished);
        gui.add(options, 'shadowBlur', 0, 20).onChange(finished);
    </script>

</body>

 

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部