435 lines
15 KiB
JavaScript
435 lines
15 KiB
JavaScript
/**
|
|
* Created by Administrator on 2017/9/8.
|
|
*/
|
|
var Point = function(x, y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
};
|
|
|
|
var Circle = function(rad, centerPoint) { //圆
|
|
this.rad = rad;
|
|
this.centerPoint = centerPoint;
|
|
};
|
|
|
|
var DelaunayDataSet = function(vertex, context) { //三角形
|
|
this.vertex = vertex;
|
|
this.context = context;
|
|
|
|
this.fillTriangleColor = "#ff0000";
|
|
this.fillTriangleCheck = true;
|
|
|
|
this.strokeTriangleColor = "rgba(255, 255, 255,0)";//棱锥边的颜色
|
|
this.strokeTriangleCheck = true;
|
|
}
|
|
|
|
var TriSettings = [];
|
|
var lights = [];
|
|
var max_lights = 20;//小球的数量
|
|
DelaunayDataSet.prototype.drawLight = function() {
|
|
// alert(this.context.canvas.height)
|
|
while (lights.length < max_lights) {
|
|
var light = {
|
|
x: Math.random() * this.context.canvas.width,
|
|
y: Math.random() * this.context.canvas.height,
|
|
angle: Math.random() * 360 * (Math.PI / 180),
|
|
speed: Math.random() / 8
|
|
}
|
|
lights.push(light);
|
|
}
|
|
for (var i = 0; i < lights.length; i++) {
|
|
var light = lights[i];
|
|
light.x += Math.cos(light.angle) * light.speed;// 速度*[-1,1]
|
|
light.y += Math.sin(light.angle) * light.speed;
|
|
if (light.x < 0 || light.y < 0 || light.x > this.context.canvas.width || light.y > this.context.canvas.height) {
|
|
light.x = Math.random() * this.context.canvas.width;
|
|
light.y = Math.random() * this.context.canvas.height;
|
|
continue;
|
|
}
|
|
with(this.context) {
|
|
fillStyle = "#ffffff";//小球颜色
|
|
beginPath();
|
|
arc(light.x, light.y, 5, 0, 2 * Math.PI, false);//圆形的半径
|
|
shadowColor = '#ffffff';//小球阴影色
|
|
shadowBlur = 10;//模糊级数
|
|
shadowOffsetX = 0;
|
|
shadowOffsetY = 0;
|
|
fill();
|
|
closePath();
|
|
|
|
}
|
|
}
|
|
this.context.shadowBlur = 0;
|
|
};
|
|
|
|
DelaunayDataSet.prototype.drawTriangle = function() {
|
|
|
|
for (var i = 0; i < this.triangleVertexNumber.length; i += 3) {
|
|
|
|
|
|
if (this.triangleVertexNumber[i] !== 0 && this.triangleVertexNumber[i] !== 1 && this.triangleVertexNumber[i] !== 2 && this.triangleVertexNumber[i + 1] !== 0 && this.triangleVertexNumber[i + 1] !== 1 && this.triangleVertexNumber[i + 1] !== 2 && this.triangleVertexNumber[i + 2] !== 0 && this.triangleVertexNumber[i + 2] !== 1 && this.triangleVertexNumber[i + 2] !== 2) {
|
|
|
|
var ctx = this.context;
|
|
var points = [];
|
|
points.push({
|
|
x: this.vertex[this.triangleVertexNumber[i]].x,
|
|
y: this.vertex[this.triangleVertexNumber[i]].y
|
|
});
|
|
points.push({
|
|
x: this.vertex[this.triangleVertexNumber[i + 1]].x,
|
|
y: this.vertex[this.triangleVertexNumber[i + 1]].y
|
|
});
|
|
points.push({
|
|
x: this.vertex[this.triangleVertexNumber[i + 2]].x,
|
|
y: this.vertex[this.triangleVertexNumber[i + 2]].y
|
|
});
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(points[0].x, points[0].y)//开始划线的起点
|
|
ctx.lineTo(points[1].x, points[1].y)//三个结束点
|
|
ctx.lineTo(points[2].x, points[2].y)
|
|
ctx.lineTo(points[0].x, points[0].y)
|
|
|
|
if (this.fillTriangleCheck) {
|
|
var settings = TriSettings[i];
|
|
if (!settings) {
|
|
var num = 120 + (80 / this.triangleVertexNumber.length * i) | 0;
|
|
var sp = new Point(this.vertex[this.triangleVertexNumber[i]].x, this.vertex[this.triangleVertexNumber[i]].y);
|
|
var ep = new Point(sp.x + 50 + Math.random() * 200, sp.y + 50 + Math.random() * 200);
|
|
var opacity = .05 + Math.random() * .6;//背景透明度
|
|
settings = {
|
|
start_point: sp,
|
|
end_point: ep,
|
|
opacity: opacity
|
|
}
|
|
TriSettings[i] = settings;
|
|
}
|
|
|
|
var color = '255,88,00';
|
|
var collision = false;
|
|
for (var l = 0; l < lights.length; l++) {
|
|
var collision = is_in_triangle(lights[l].x, lights[l].y, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y)
|
|
if (collision) {
|
|
color = '255,255,255';//背景渐变色
|
|
continue;
|
|
}
|
|
}
|
|
|
|
var grad = ctx.createLinearGradient(settings.start_point.x, settings.start_point.y, settings.end_point.x, settings.end_point.y);
|
|
grad.addColorStop(0, 'rgba(255,88,00,' + settings.opacity + ')');//开始颜色到结束颜色的透明度及颜色的变化
|
|
grad.addColorStop(1, 'rgba(' + color + ',' + settings.opacity + ')');//三角形渐变的颜色
|
|
ctx.fillStyle = grad;
|
|
ctx.fill();
|
|
}
|
|
|
|
if (this.strokeTriangleCheck) {
|
|
ctx.strokeStyle = this.strokeTriangleColor;
|
|
ctx.stroke();
|
|
}
|
|
|
|
ctx.closePath();
|
|
|
|
}
|
|
}
|
|
};
|
|
|
|
DelaunayDataSet.prototype.update = function() {
|
|
|
|
var vertexNumber = this.vertex.length;
|
|
this.triangleVertexNumber = [0, 1, 2];
|
|
this.circumCircles = [];
|
|
|
|
|
|
var firstCircle = calculationCircle(this.vertex[0], this.vertex[1], this.vertex[2]);
|
|
this.circumCircles.push(firstCircle);
|
|
|
|
for (var i = 3; i < vertexNumber; i++) {
|
|
calTriangles(this, i);
|
|
if (i > 3) {
|
|
removeTriangle(this, i);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
// define the method which is very useful
|
|
|
|
|
|
function distanceBetweenPoints(pt1, pt2) {
|
|
var dx = pt2.x - pt1.x;
|
|
var dy = pt2.y - pt1.y;
|
|
|
|
return Math.sqrt(dx * dx + dy * dy);
|
|
}
|
|
|
|
function distanceBetweenPointAndCircle(pt, circle) {
|
|
var dx = pt.x - circle.centerPoint.x;
|
|
var dy = pt.y - circle.centerPoint.y;
|
|
|
|
return Math.sqrt(dx * dx + dy * dy);
|
|
}
|
|
|
|
function judgeBetweenDistance(_pt, _circle) {
|
|
var dis = distanceBetweenPointAndCircle(_pt, _circle);
|
|
|
|
var circleJudge = false;
|
|
if (dis < _circle.rad) {
|
|
circleJudge = true;
|
|
}
|
|
|
|
return circleJudge;
|
|
}
|
|
|
|
//this is the process of 3 ( separating of the triangles, add the circum circles, and deleting the extra triangle
|
|
|
|
|
|
function calTriangles(_delaunayDataSet, num) {
|
|
var newNumber = num;
|
|
var pt = _delaunayDataSet.vertex[newNumber];
|
|
|
|
var tempVertexNumber = [];
|
|
var tempCircles = [];
|
|
var tempNumbers = [];
|
|
|
|
for (var i = 0; i < _delaunayDataSet.circumCircles.length; i++) {
|
|
if (judgeBetweenDistance(pt, _delaunayDataSet.circumCircles[i])) {
|
|
tempNumbers.push(i);
|
|
|
|
var selectingNum01 = _delaunayDataSet.triangleVertexNumber[3 * i];
|
|
var selectingNum02 = _delaunayDataSet.triangleVertexNumber[3 * i + 1];
|
|
var selectingNum03 = _delaunayDataSet.triangleVertexNumber[3 * i + 2];
|
|
|
|
tempVertexNumber.push(selectingNum01);
|
|
tempVertexNumber.push(selectingNum02);
|
|
tempVertexNumber.push(newNumber);
|
|
|
|
tempVertexNumber.push(selectingNum02);
|
|
tempVertexNumber.push(selectingNum03);
|
|
tempVertexNumber.push(newNumber);
|
|
|
|
tempVertexNumber.push(selectingNum03);
|
|
tempVertexNumber.push(selectingNum01);
|
|
tempVertexNumber.push(newNumber);
|
|
|
|
var ct01circle1 = calculationCircle(_delaunayDataSet.vertex[selectingNum01], _delaunayDataSet.vertex[selectingNum02], _delaunayDataSet.vertex[newNumber]);
|
|
var ct01circle2 = calculationCircle(_delaunayDataSet.vertex[selectingNum02], _delaunayDataSet.vertex[selectingNum03], _delaunayDataSet.vertex[newNumber]);
|
|
var ct01circle3 = calculationCircle(_delaunayDataSet.vertex[selectingNum03], _delaunayDataSet.vertex[selectingNum01], _delaunayDataSet.vertex[newNumber]);
|
|
|
|
tempCircles.push(ct01circle1);
|
|
tempCircles.push(ct01circle2);
|
|
tempCircles.push(ct01circle3);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < tempVertexNumber.length; i++) {
|
|
_delaunayDataSet.triangleVertexNumber.push(tempVertexNumber[i]);
|
|
}
|
|
|
|
for (i = 0; i < tempCircles.length; i++) {
|
|
_delaunayDataSet.circumCircles.push(tempCircles[i]);
|
|
}
|
|
|
|
for (i = 0; i < tempNumbers.length; i++) {
|
|
var num = tempNumbers[i] - i;
|
|
|
|
var slicedObjectPtNumbers;
|
|
var slicedCircles;
|
|
|
|
if (num == 0) {
|
|
slicedObjectPtNumbers = _delaunayDataSet.triangleVertexNumber.slice(3);
|
|
slicedCircles = _delaunayDataSet.circumCircles.slice(1);
|
|
} else {
|
|
var slicedObjectPtNumberBefore = _delaunayDataSet.triangleVertexNumber.slice(0, 3 * num);
|
|
var slicedObjectPtNumberAfter = _delaunayDataSet.triangleVertexNumber.slice(3 * num + 3);
|
|
slicedObjectPtNumbers = slicedObjectPtNumberBefore.concat(slicedObjectPtNumberAfter);
|
|
|
|
var slicedCircleBefore = _delaunayDataSet.circumCircles.slice(0, num);
|
|
var slicedCircleAfter = _delaunayDataSet.circumCircles.slice(1 + num);
|
|
slicedCircles = slicedCircleBefore.concat(slicedCircleAfter);
|
|
}
|
|
|
|
_delaunayDataSet.triangleVertexNumber = slicedObjectPtNumbers;
|
|
_delaunayDataSet.circumCircles = slicedCircles;
|
|
}
|
|
|
|
}
|
|
|
|
function calculationCircle(pt01, pt02, pt03) {
|
|
|
|
var x1 = pt01.x;
|
|
var y1 = pt01.y;
|
|
|
|
var x2 = pt02.x;
|
|
var y2 = pt02.y;
|
|
|
|
var x3 = pt03.x;
|
|
var y3 = pt03.y;
|
|
|
|
var c = 2.0 * ((x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1));
|
|
var tempX = ((y3 - y1) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) + (y1 - y2) * (x3 * x3 - x1 * x1 + y3 * y3 - y1 * y1)) / c;
|
|
var tempY = ((x1 - x3) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) + (x2 - x1) * (x3 * x3 - x1 * x1 + y3 * y3 - y1 * y1)) / c;
|
|
var tempPt = new Point(tempX, tempY);
|
|
|
|
var tempRad = Math.sqrt(Math.pow(tempX - x1, 2) + Math.pow(tempY - y1, 2));
|
|
|
|
return new Circle(tempRad, tempPt);
|
|
}
|
|
|
|
function removeTriangle(_delaunayDataSet, tempVertexNum) {
|
|
var circumcircleArrays = _delaunayDataSet.circumCircles;
|
|
var ommitCircumCircleNumbers = [];
|
|
|
|
for (var i = 0; i < circumcircleArrays.length; i++) {
|
|
var vertexNum01 = _delaunayDataSet.triangleVertexNumber[i * 3];
|
|
var vertexNum02 = _delaunayDataSet.triangleVertexNumber[i * 3 + 1];
|
|
var vertexNum03 = _delaunayDataSet.triangleVertexNumber[i * 3 + 2];
|
|
|
|
for (var num = 0; num < tempVertexNum; num++) {
|
|
if (num != vertexNum01 && num != vertexNum02 && num != vertexNum03) {
|
|
|
|
if (judgeBetweenDistance(_delaunayDataSet.vertex[num], circumcircleArrays[i])) {
|
|
ommitCircumCircleNumbers.push(i);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//omit
|
|
var tempCircumCircleArray = [];
|
|
var tempTriagneNumberArray = [];
|
|
|
|
for (i = 0; i < circumcircleArrays.length; i++) {
|
|
for (var j = 0; j < ommitCircumCircleNumbers.length; j++) {
|
|
if (ommitCircumCircleNumbers[j] == i) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (j == ommitCircumCircleNumbers.length) {
|
|
|
|
tempTriagneNumberArray.push(_delaunayDataSet.triangleVertexNumber[3 * i]);
|
|
tempTriagneNumberArray.push(_delaunayDataSet.triangleVertexNumber[3 * i + 1]);
|
|
tempTriagneNumberArray.push(_delaunayDataSet.triangleVertexNumber[3 * i + 2]);
|
|
|
|
tempCircumCircleArray.push(_delaunayDataSet.circumCircles[i]);
|
|
}
|
|
}
|
|
|
|
_delaunayDataSet.triangleVertexNumber = [];
|
|
for (i = 0; i < tempTriagneNumberArray.length; i++) {
|
|
_delaunayDataSet.triangleVertexNumber[i] = tempTriagneNumberArray[i];
|
|
}
|
|
|
|
_delaunayDataSet.circumCircles = [];
|
|
for (i = 0; i < tempCircumCircleArray.length; i++) {
|
|
_delaunayDataSet.circumCircles[i] = tempCircumCircleArray[i];
|
|
}
|
|
}
|
|
|
|
function initTriangle(context, recWid, recHig, recTop, recLeft) {
|
|
var vertex = [];
|
|
|
|
var bigRad = Math.sqrt(Math.pow(recWid, 2) + Math.pow(recHig, 2)) / 2;
|
|
var bigCirclePos = new Point(recWid / 2 + recLeft, recHig / 2 + recTop);
|
|
|
|
vertex.push(new Point(bigCirclePos.x - Math.sqrt(3) * bigRad, bigCirclePos.y - bigRad));
|
|
vertex.push(new Point(bigCirclePos.x + Math.sqrt(3) * bigRad, bigCirclePos.y - bigRad));
|
|
vertex.push(new Point(bigCirclePos.x, bigCirclePos.y + bigRad * 2));
|
|
|
|
return new DelaunayDataSet(vertex, context);
|
|
}
|
|
|
|
function is_in_triangle(px, py, ax, ay, bx, by, cx, cy) {
|
|
|
|
var v0 = [cx - ax, cy - ay];
|
|
var v1 = [bx - ax, by - ay];
|
|
var v2 = [px - ax, py - ay];
|
|
|
|
var dot00 = (v0[0] * v0[0]) + (v0[1] * v0[1]);
|
|
var dot01 = (v0[0] * v1[0]) + (v0[1] * v1[1]);
|
|
var dot02 = (v0[0] * v2[0]) + (v0[1] * v2[1]);
|
|
var dot11 = (v1[0] * v1[0]) + (v1[1] * v1[1]);
|
|
var dot12 = (v1[0] * v2[0]) + (v1[1] * v2[1]);
|
|
|
|
var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
|
|
|
|
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
|
|
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
|
|
|
|
return ((u >= 0) && (v >= 0) && (u + v < 1));
|
|
}
|
|
|
|
window.requestAnimFrame = (function() {
|
|
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
|
|
function(callback) {
|
|
window.requestAnimationFrame(callback, 1000 / 1000);
|
|
};
|
|
})();
|
|
|
|
(function() {
|
|
var canvas = document.getElementById("myCanvas");
|
|
var canvasWid = 1200;
|
|
var canvasHig = 130;
|
|
|
|
canvas.width = canvasWid;
|
|
canvas.height = canvasHig;
|
|
var context = canvas.getContext("2d");
|
|
|
|
var recWid = canvasWid;
|
|
var recHig = canvasHig;
|
|
|
|
var recTop = 0;
|
|
var recLeft = 0;
|
|
|
|
var delaneyNum = 30;
|
|
var myDelaunayDataSet = initTriangle(context, recWid, recHig, recTop, recLeft);
|
|
|
|
var tempPt;
|
|
tempPt = new Point(0, 0);
|
|
myDelaunayDataSet.vertex.push(tempPt);
|
|
|
|
tempPt = new Point(canvasWid, 0);
|
|
myDelaunayDataSet.vertex.push(tempPt);
|
|
|
|
tempPt = new Point(0, canvasHig);
|
|
myDelaunayDataSet.vertex.push(tempPt);
|
|
|
|
tempPt = new Point(canvasWid, canvasHig);
|
|
myDelaunayDataSet.vertex.push(tempPt);
|
|
|
|
for (var i = 0; i < delaneyNum - 4; i++) {
|
|
var pt = new Point(Math.random() * recWid + recLeft, Math.random() * recHig + recTop);
|
|
myDelaunayDataSet.vertex.push(pt);
|
|
}
|
|
|
|
var mousePos = new Point(canvasWid / 2, canvasHig / 2);
|
|
myDelaunayDataSet.vertex.push(mousePos);
|
|
|
|
myDelaunayDataSet.update();
|
|
myDelaunayDataSet.drawTriangle();
|
|
|
|
function getMousePos(canvas, evt) {
|
|
var rect = canvas.getBoundingClientRect();
|
|
return new Point(evt.clientX - rect.left, evt.clientY - rect.top);
|
|
}
|
|
|
|
loop();
|
|
|
|
function loop() {
|
|
context.clearRect(0, 0, canvasWid, canvasHig);
|
|
context.fillStyle='rgba(255,75,00,0.6)';
|
|
context.fillRect(0,0,1350,130);
|
|
// context.font="30px Arial";
|
|
// context.fillText("在线课堂",550,75);
|
|
// context.font="22px Arial";
|
|
// context.fillText("One who is anxious to learn, can always learn from others.",300,140);
|
|
myDelaunayDataSet.drawTriangle();
|
|
myDelaunayDataSet.drawLight();
|
|
requestAnimFrame(loop);
|
|
}
|
|
|
|
})(); |