效果:
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>