我试图教自己如何使用画布 - 而且我可能已经在脑海里了 - 但我想我是否有人解决这个问题我遇到过
作为一个教训,我决定尝试从这个元球的想法开始: http://codepen.io/ge1doot/pen/RNdwQB
并重新修改它以使元球静止,但随着向下滚动页面,以不同的速率向上移动。
我有点在这里工作 - 在小提琴上表现得比在下面好得多。 https://jsfiddle.net/L7cr46px/2/
function getScrollOffsets() {
var doc = document, w = window;
var x, y, docEl;
if ( typeof w.pageYOffset === 'number' ) {
x = w.pageXOffset;
y = w.pageYOffset;
} else {
docEl = (doc.compatMode && doc.compatMode === 'CSS1Compat')?
doc.documentElement: doc.body;
x = docEl.scrollLeft;
y = docEl.scrollTop;
}
return {x:x, y:y};
}
var lava, ballData;
ballData = new Array();
(function() {
var metablobby = metablobby || {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function (id, callback, initRes) {
this.elem = document.getElementById(id);
this.callback = callback || null;
if (this.elem.tagName == "CANVAS") this.ctx = this.elem.getContext("2d");
window.addEventListener('resize', function () {
this.resize();
}.bind(this), false);
this.elem.onselectstart = function () { return false; }
this.elem.ondrag = function () { return false; }
initRes && this.resize();
return this;
},
resize: function () {
var o = this.elem;
this.width = o.offsetWidth;
this.height = o.offsetHeight;
for (this.left = 0, this.top = 0; o != null; o = o.offsetParent) {
this.left += o.offsetLeft;
this.top += o.offsetTop;
}
if (this.ctx) {
this.elem.width = this.width;
this.elem.height = this.height;
}
this.callback && this.callback();
},
pointer: {
screen: null,
elem: null,
callback: null,
pos: {x:0, y:0},
mov: {x:0, y:0},
drag: {x:0, y:0},
start: {x:0, y:0},
end: {x:0, y:0},
active: false,
touch: false,
move: function (e, touch) {
//this.active = true;
this.touch = touch;
e.preventDefault();
var pointer = touch ? e.touches[0] : e;
this.mov.x = pointer.clientX - this.screen.left;
this.mov.y = pointer.clientY - this.screen.top;
if (this.active) {
this.pos.x = this.mov.x;
this.pos.y = this.mov.y;
this.drag.x = this.end.x - (this.pos.x - this.start.x);
this.drag.y = this.end.y - (this.pos.y - this.start.y);
this.callback.move && this.callback.move();
}
},
scroll: function(e, touch){
run();
},
init: function (callback) {
this.screen = metablobby.screen;
this.elem = this.screen.elem;
this.callback = callback || {};
if ('ontouchstart' in window) {
// touch
this.elem.ontouchstart = function (e) { this.down(e, true); }.bind(this);
this.elem.ontouchmove = function (e) { this.move(e, true); }.bind(this);
this.elem.ontouchend = function (e) { this.up(e, true); }.bind(this);
this.elem.ontouchcancel = function (e) { this.up(e, true); }.bind(this);
}
document.addEventListener("mousemove", function (e) { this.move(e, false); }.bind(this), true);
document.addEventListener("scroll", function (e) { this.scroll(e, false); }.bind(this), true);
return this;
}
},
}
}
// ==== Point constructor ====
var Point = function(x, y) {
this.x = x;
this.y = y;
this.magnitude = x * x + y * y;
this.computed = 0;
this.force = 0;
}
Point.prototype.add = function(p) {
return new Point(this.x + p.x, this.y + p.y);
}
// ==== Ball constructor ====
var Ball = function(parent,i) {
var x = Math.floor(Math.random() * window.innerWidth) + 1;
var y = Math.floor(Math.random() * (window.innerHeight)*5) + 1;
var radius = (Math.floor(Math.random() * 65) + 15)
var drift = Math.random();
ballData[i]=[x,y,radius, drift];
this.vel = new Point(0,0);
this.pos = new Point(x,y);
this.size = radius;
this.width = parent.width;
this.height = parent.height;
}
// ==== move balls ====
Ball.prototype.move = function(i) {
// ---- interact with pointer ----
if (pointer.active) {
var dx = pointer.pos.x - this.pos.x;
var dy = pointer.pos.y - this.pos.y;
var a = Math.atan2(dy, dx);
var v = -Math.min(
10,
500 / Math.sqrt(dx * dx + dy * dy)
);
this.pos = this.pos.add(
new Point(
Math.cos(a) * v,
Math.sin(a) * v
)
);
}
var drift = ballData[i-1][3];
var pageOffset = getScrollOffsets().y;
this.pos.y = ballData[i-1][1] - (pageOffset*drift);
this.vel.y = 0 - (pageOffset*drift);
this.pos = this.pos.add(this.vel);
}
// ==== lavalamp constructor ====
var LavaLamp = function(width, height, numBalls) {
this.step = 4;
this.width = width;
this.height = height;
this.wh = Math.min(width, height);
this.sx = Math.floor(this.width / this.step);
this.sy = Math.floor(this.height / this.step);
this.paint = false;
this.metaFill = '#000000';
this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0];
this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1];
this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0];
this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1];
this.grid = [];
this.balls = [];
this.iter = 0;
this.sign = 1;
// ---- init grid ----
for (var i = 0; i < (this.sx + 2) * (this.sy + 2); i++) {
this.grid[i] = new Point(
(i % (this.sx + 2)) * this.step, (Math.floor(i / (this.sx + 2))) * this.step
)
}
// ---- create metaballs ----
for (var i = 0; i < 50; i++) {
this.balls[i] = new Ball(this,i);
}
}
// ==== compute cell force ====
LavaLamp.prototype.computeForce = function(x, y, idx) {
var force;
var id = idx || x + y * (this.sx + 2);
if (x === 0 || y === 0 || x === this.sx || y === this.sy) {
var force = 0.6 * this.sign;
} else {
var cell = this.grid[id];
var force = 0;
var i = 0,
ball;
while (ball = this.balls[i++]) {
force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude);
}
force *= this.sign
}
this.grid[id].force = force;
return force;
}
// ---- compute cell ----
LavaLamp.prototype.marchingSquares = function(next) {
var x = next[0];
var y = next[1];
var pdir = next[2];
var id = x + y * (this.sx + 2);
if(typeof this.grid[id] !== "undefined"){
if (this.grid[id].computed === this.iter) return false;
var dir, mscase = 0;
// ---- neighbors force ----
for (var i = 0; i < 4; i++) {
var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2);
var force = this.grid[idn].force;
if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) {
// ---- compute force if not in buffer ----
force = this.computeForce(
x + this.ix[i + 12],
y + this.ix[i + 16],
idn
);
}
if (Math.abs(force) > 1) mscase += Math.pow(2, i);
}
if (mscase === 15) {
// --- inside ---
return [x, y - 1, false];
} else {
// ---- ambiguous cases ----
if (mscase === 5) dir = (pdir === 2) ? 3 : 1;
else if (mscase === 10) dir = (pdir === 3) ? 0 : 2;
else {
// ---- lookup ----
dir = this.mscases[mscase];
this.grid[id].computed = this.iter;
}
// ---- draw line ----
var ix = this.step / (
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) /
Math.abs(Math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1
);
ctx.lineTo(
this.grid[(x + this.plx[4 * dir + 0]) + (y + this.ply[4 * dir + 0]) * (this.sx + 2)].x + this.ix[dir] * ix,
this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix
);
this.paint = true;
// ---- next ----
return [
x + this.ix[dir + 4],
y + this.ix[dir + 8],
dir
];
}
}
}
LavaLamp.prototype.renderMetaballs = function() {
var i = 0, ball;
while (ball = this.balls[i++]) ball.move(i);
// ---- reset grid ----
this.iter++;
this.sign = -this.sign;
this.paint = false;
ctx.fillStyle = '#FF0000';
ctx.beginPath();
// ---- compute metaballs ----
i = 0;
while (ball = this.balls[i++]) {
// ---- first cell ----
var next = [
Math.round(ball.pos.x / this.step),
Math.round(ball.pos.y / this.step), false
];
// ---- marching squares ----
do {
next = this.marchingSquares(next);
} while (next);
// ---- fill and close path ----
if (this.paint) {
ctx.fill();
ctx.closePath();
ctx.beginPath();
this.paint = false;
}
}
}
// ==== main loop ====
var run = function() {
//requestAnimationFrame(run);
ctx.clearRect(0, 0, screen.width, screen.height);
lava.renderMetaballs();
}
// ---- canvas ----
var screen = metablobby.screen.init("thedots", null, true),
ctx = screen.ctx,
pointer = screen.pointer.init();
screen.resize();
// ---- create LavaLamps ----
lava = new LavaLamp(screen.width, screen.height, 10);
// ---- start engine ----
run();
})();
&#13;
html,body {
height: 100%;
width: 100%;
background-color: white;
}
body {
height: 500vh;
}
#thedots {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 100;
pointer-events: none;
}
&#13;
<canvas id="thedots" width="1203" height="363"></canvas>
&#13;
但是我会看到疯狂的渲染错误。或者他们可能没有渲染错误,只是一些错误的代码。任何帮助将不胜感激。
谢谢!