how can I use parcel.js to run p5.js code? - p5.js

I've lately been using parcel.js with react apps and it's been very user friendly.
I'm following along to a Coding Train tutorial and parcel for whatever reason is not running the code.
https://github.com/CodingTrain/website/tree/master/CodingChallenges/CC_001_StarField/P5
When I run this with live server, no errors and everything runs correctly.
When I attempt to run it with parcel.js, there are no errors, it just doesn't run, nothing renders.
Any idea why this might be happening?
Thank you

I think the issue here is that Parcel.js doesn't put variables defined in src'd scripts into the global scope by default, and p5.js depends on these globals by default (setup and draw in particular). You could solve the problem by making speed, setup and draw in sketch.js, and Star in Star.js, properties of window (or, equivalently, global). See the example below, which works when built with parcel index.html.
(This method has the benefit of preserving access to the familiar (global) p5.js commands without the need for a prefix, but might give complications with globals being overwritten if you're using other libraries.)
//sketch.js
let stars = [];
window.speed = undefined;
window.setup = function setup() {
createCanvas(600, 600);
for (let i = 0; i < 800; i++) {
stars[i] = new Star();
}
}
window.draw = function draw() {
speed = map(mouseX, 0, width, 0, 50);
background(0);
translate(width / 2, height / 2);
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].show();
}
}
//Star.js
window.Star = function Star() {
this.x = random(-width, width);
this.y = random(-height, height);
this.z = random(width);
this.pz = this.z;
this.update = function() {
this.z = this.z - speed;
if (this.z < 1) {
this.z = width;
this.x = random(-width, width);
this.y = random(-height, height);
this.pz = this.z;
}
};
this.show = function() {
fill(255);
noStroke();
var sx = map(this.x / this.z, 0, 1, 0, width);
var sy = map(this.y / this.z, 0, 1, 0, height);
var r = map(this.z, 0, width, 16, 0);
ellipse(sx, sy, r, r);
var px = map(this.x / this.pz, 0, 1, 0, width);
var py = map(this.y / this.pz, 0, 1, 0, height);
this.pz = this.z;
stroke(255);
line(px, py, sx, sy);
};
}
<html>
<head>
<meta charset="UTF-8" />
<title>StarField_p5.js</title>
<style>
body {
padding: 0;
margin: 0;
}
canvas {
vertical-align: top;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/addons/p5.sound.min.js"></script>
<script src="./Star.js"></script>
<script src="./sketch.js"></script>
</head>
<body>
<main></main>
</body>
</html>
Alternatively you could use instance mode of P5.js to set things up without globals (See also thread here - the code sample of which has now had its P5.js dependency removed, but you can look at the commit history). This has the downside that the familiar P5.js / processing functions have to be prefixed with an object reference, minimally something like s.createCanvas (the methods often seem to depend on being bound properly in object orientated style). It is likely the safer approach if other libraries are involved though, especially as p5.js defines lots of globals with common names like random, map and height if it isn't used in instance mode.
Something like this:
// index.js
// I've combined sketch.js and Star.js here to make
// it easier to share variable speed
const myp5 = new p5((s) => {
const stars = [];
let speed =1;
s.setup = function setup() {
s.createCanvas(600, 600);
for (let i = 0; i < 800; i++) {
stars[i] = new Star();
}
};
s.draw = function draw() {
speed = s.map(s.mouseX, 0, s.width, 0, 50);
s.background(0);
s.translate(s.width / 2, s.height / 2);
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].show();
}
};
function Star() {
this.x = s.random(-s.width, s.width);
this.y = s.random(-s.height, s.height);
this.z = s.random(s.width);
this.pz = this.z;
this.update = function () {
this.z = this.z - speed;
if (this.z < 1) {
this.z = s.width;
this.x = s.random(-s.width, s.width);
this.y = s.random(-s.height, s.height);
this.pz = this.z;
}
};
this.show = function () {
s.fill(255);
s.noStroke();
var sx = s.map(this.x / this.z, 0, 1, 0, s.width);
var sy = s.map(this.y / this.z, 0, 1, 0, s.height);
var r = s.map(this.z, 0, s.width, 16, 0);
s.ellipse(sx, sy, r, r);
var px = s.map(this.x / this.pz, 0, 1, 0, s.width);
var py = s.map(this.y / this.pz, 0, 1, 0, s.height);
this.pz = this.z;
s.stroke(255);
s.line(px, py, sx, sy);
};
}
},'sketch1');
<html>
<head>
<meta charset="UTF-8" />
<title>StarField_p5.js</title>
<style>
body {
padding: 0;
margin: 0;
}
canvas {
vertical-align: top;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/p5.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5#1.0.0/lib/addons/p5.sound.min.js"></script>
<script src="./index.js"></script>
</head>
<body>
<div id="sketch1"></div>
</body>
</html>

Related

Is there a way to draw a matter.js composite with p5?

I recently saw the matter.js on the coding train channel from 2017, I've managed to replicate the examples shown on those videos but now I wanted to do something more advanced. There is a Composite module called stack in the documentation used to create a soft body in the matter.js demos but I wonder if there is a way to draw this using p5 instead.
This is what I've gotten so far, any help is appreciated
I think the main issue with your code was that you weren't adding the Composite to the world. Here's a working example with a few other tweaks:
const {
Bodies,
Common,
Composites,
Constraint,
Engine,
Runner,
World
} = Matter;
var engine;
var world;
var particles = [];
var boundaries = [];
var composi1;
var composi2;
function setup() {
createCanvas(400, 400);
engine = Engine.create();
world = engine.world;
// Use a runner to actually run the simulation
const runner = Runner.create();
Runner.run(runner, engine);
// Add two composites so we can see them interact
composi1 = new softbodi(100, 50, 4, 4, 0, 0, true, 20);
composi2 = new softbodi(50, 300, 4, 2, 0, 0, true, 20);
boundaries.push(new Boundary(200, height, width, 50, 0));
}
function draw() {
background(51);
for (var i = 0; i < boundaries.length; i++) {
boundaries[i].show();
}
composi1.show();
composi2.show();
}
function softbodi(
xx,
yy,
columns,
rows,
columnGap,
rowGap,
crossBrace,
particleRadius) {
this.r = particleRadius;
this.composite = Composites.stack(
xx,
yy,
columns,
rows,
columnGap,
rowGap,
function(x, y) {
return Bodies.circle(x, y, particleRadius);
}
);
this.mesh = Composites.mesh(this.composite, columns, rows, crossBrace);
// Dont forget to add you composite to the world
World.add(world, this.composite);
this.show = function() {
var parr = [];
parr = Matter.Composite.allBodies(this.composite);
for (var i = 0; i < parr.length; i++) {
var pos = parr[i].position;
var angle = parr[i].angle;
push();
translate(pos.x, pos.y);
rotate(angle);
rectMode(CENTER);
strokeWeight(1);
stroke(255);
fill(127);
ellipse(0, 0, this.r * 2);
pop();
}
};
}
function Boundary(x, y, w, h, a) {
var options = {
friction: 0,
restitution: 0.95,
angle: a,
isStatic: true
};
this.body = Bodies.rectangle(x, y, w, h, options);
this.w = w;
this.h = h;
World.add(world, this.body);
this.show = function() {
var pos = this.body.position;
var angle = this.body.angle;
push();
translate(pos.x, pos.y);
rotate(angle);
rectMode(CENTER);
strokeWeight(1);
noStroke();
fill(0);
rect(0, 0, this.w, this.h);
pop();
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>

Error while using class in prototype of function

I'm working on a p5 project and I have an issue. When I'm trying to use my class name in my prototype I've an error ',' expected but I don't have any place where I can place one.
Here are the files.
-----FIRST FILE-----
class Pipe {
constructor() {
this.width = 50;
this.height = floor(random(canvas.height - 100));
this.x = canvas.width + this.width;
this.topY = canvas.height - this.height;
}
show() {
fill(0, 204, 0);
rect(this.x, canvas.height - this.height, this.x + width, canvas.height);
}
update() {
this.x -= panSpeed;
}
### IT'S THIS "p" which causing the problem ###
colided(Player p) {
if (p.x + p.size > this.x && p.x - p.size < this.x + this.width) {
if (p.y + p.size > this.topY) {
return true;
}
}
return false;
}
}
-----SECOND FILE-----
class Player {
constructor(x, y) {
this.x = x;
this.y = y;
this.velY = 0;
this.velX = panSpeed;
this.size = 20;
}
show() {
noStroke();
fill(255, 255, 0);
ellipse(this.x, this.y, this.size);
}
update() {
this.velY += gravity;
this.velY = constrain(this.velY, -1000, 25);
this.y += this.velY;
if (pipe.colided(this)) {
this.y = 0;
}
}
flap() {
this.velY -= 50;
}
}
-----THIRD FILE-----
var panSpeed = 5;
var gravity = 3;
var player;
var pipe;
function setup() {
window.canvas = createCanvas(800, 800);
player = new Player(100, canvas.height / 2);
pipe = new Pipe();
}
function draw() {
background(135, 206, 250);
pipe.update();
pipe.show();
player.update();
player.show();
}
function keyPressed() {
switch (key) {
case ' ':
player.flap();
break;
}
}
-----THE HTML-----
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>p5.js example</title>
<style> body {padding: 0; margin: 0;} </style>
<script src="lib/p5.js"></script>
<script src="lib/p5.sound.js"></script>
<script src="js/sketch.js"></script>
<script src="js/toto.js"></script>
<script src="js/pipe.js"></script>
</head>
<body>
</body>
</html>
First off, remove ### IT'S THIS "p" which causing the problem ###
Second off your issue is
colided(Player p) {
...
}
You're trying to give it a type of Player, which is not valid JavaScript. If you remove player and just have
colided(p) {
...
}
That'll sort your issue. FYI if you were to use Typescript as an example for optional static typing, the syntax would be colided(p : Player)
class Pipe {
constructor() {
this.width = 50;
this.height = floor(random(canvas.height - 100));
this.x = canvas.width + this.width;
this.topY = canvas.height - this.height;
}
show() {
fill(0, 204, 0);
rect(this.x, canvas.height - this.height, this.x + width, canvas.height);
}
update() {
this.x -= panSpeed;
}
colided(p) {
if (p.x + p.size > this.x && p.x - p.size < this.x + this.width) {
if (p.y + p.size > this.topY) {
return true;
}
}
return false;
}
}
class Player {
constructor(x, y) {
this.x = x;
this.y = y;
this.velY = 0;
this.velX = panSpeed;
this.size = 20;
}
show() {
noStroke();
fill(255, 255, 0);
ellipse(this.x, this.y, this.size);
}
update() {
this.velY += gravity;
this.velY = constrain(this.velY, -1000, 25);
this.y += this.velY;
if (pipe.colided(this)) {
this.y = 0;
}
}
flap() {
this.velY -= 50;
}
}
var panSpeed = 5;
var gravity = 3;
var player;
var pipe;
function setup() {
window.canvas = createCanvas(800, 800);
player = new Player(100, canvas.height / 2);
pipe = new Pipe();
}
function draw() {
background(135, 206, 250);
pipe.update();
pipe.show();
player.update();
player.show();
}
function keyPressed() {
switch (key) {
case ' ':
player.flap();
break;
}
}
<script src="https://cdn.jsdelivr.net/npm/p5#0.10.2/lib/p5.js"></script>

Setting background image in canvas animation

I need to set background image for this canvas animation without affecting the animation style.
This CodePen is shown below.
var c = document.getElementById('canv');
var $ = c.getContext('2d');
var w = c.width = window.innerWidth;
var h = c.height = window.innerHeight;
var grav = 0.00095;
var s = [20, 15, 10, 5];
var gravX = w / 2;
var gravY = h / 2;
var nodes;
var num = 55;
var minDist = 155;
var spr = 0.0000009;
part();
run();
//random size function
function S() {
var curr = s.length;
var cur_ = Math.floor(Math.random() * curr);
return s[cur_];
}
function part() {
nodes = [];
for (var i = 0; i < num; i++) {
var node = {
hue: Math.random()*360,
rad: S(),
x: Math.random() * w,
y: Math.random() * h,
vx: Math.random() * 8 - 4,
vy: Math.random() * 8 - 4,
upd: function() {
this.x += this.vx;
this.y += this.vy;
if (this.x > w) this.x = 0;
else if (this.x < 0) this.x = w;
if (this.y > h) this.y = 0;
else if (this.y < 0) this.y = h;
},
draw: function() {
//outer ring
var g = $.createRadialGradient(this.x, this.y, this.rad * 2, this.x, this.y, this.rad);
g.addColorStop(0,'hsla(242, 55%, 15%,.7)');
g.addColorStop(.5, 'hsla(242, 50%, 10%,.5)');
g.addColorStop(1,'hsla(242, 30%, 5%,.5)');
$.fillStyle = g;
$.beginPath();
$.arc(this.x, this.y, this.rad * 2, 0, Math.PI * 2, true);
$.fill();
$.closePath();
//inner particle
var g2 = $.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.rad);
g2.addColorStop(0, 'hsla('+this.hue+', 85%, 40%, 1)');
g2.addColorStop(.5, 'hsla('+this.hue+',95%, 50%,1)');
g2.addColorStop(1,'hsla(0,0%,0%,0)');
$.fillStyle = g2;
$.beginPath();
$.arc(this.x, this.y, this.rad, 0, Math.PI * 2, true);
$.fill();
$.closePath();
}
};
nodes.push(node);
}
}
function run() {
$.globalCompositeOperation = 'source-over';
$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.fillRect(0, 0, w, h);
$.globalCompositeOperation = 'lighter';
for (i = 0; i < num; i++) {
nodes[i].upd();
nodes[i].draw();
}
for (i = 0; i < num - 1; i++) {
var n1 = nodes[i];
for (var j = i + 1; j < num; j++) {
var n2 = nodes[j];
Spr(n1, n2);
}
Grav(n1);
}
window.requestAnimationFrame(run);
}
function Spr(na, nb) {
var dx = nb.x - na.x;
var dy = nb.y - na.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < minDist) {
$.lineWidth = 1;
$.beginPath();
$.strokeStyle = "hsla(217, 95%, 55%, .15)";
$.moveTo(na.x, na.y);
$.lineTo(nb.x, nb.y);
$.stroke();
$.closePath();
var ax = dx * spr;
var ay = dy * spr;
na.vx += ax;
na.vy += ay;
nb.vx -= ax;
nb.vy -= ay;
}
}
function Grav(n) {
n.vx += (gravX - n.x) * grav;
n.vy += (gravY - n.y) * grav;
};
window.addEventListener('resize', function() {
c.width = w = window.innerWidth;
c.height = h = window.innerHeight;
});
body{
width:100%;
margin:0;
overflow:hidden;
}
<canvas id='canv' ></canvas>
CSS
Just replace the beginning of the run() code to:
function run() {
...
//$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.clearRect(0, 0, w, h);
...
Then move the color settings to CSS together with an image reference:
#canv {
background: hsla(242, 40%, 5%, .85) url(path/to/image.jpg);
}
Add background-size to the CSS rule if needed. Note that since you're using different blending modes such as lighter which depends on existing content, you may not get desired result as it will blend with an empty canvas and not a solid - the approach below should solve that in this case.
CodePen
JavaScript
As before, replace the first lines in run() but after you made sure the image you want to use has loaded, simply draw it in:
function run() {
...
//$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.drawImage(img, 0, 0, w, h); // img must be loaded (use onload)
...
If your image contains transparency you also need to clear the canvas first:
function run() {
...
//$.fillStyle = 'hsla(242, 40%, 5%,.85)';
$.clearRect(0, 0, w, h);
$.drawImage(img, 0, 0, w, h); // img must be loaded (use onload)
...
CodePen

How do i bind onclick event to piechart segment?

How do i bind onclick event to piechart segment?
https://github.com/sauminkirve/HTML5/blob/master/PieChart/piechart.html
A pie chart segment is really a wedge. You have several ways to hit-test a wedge.
One way is the math way:
Test if the mouse is within the radius of a circle created by the wedges.
If the radius test is true, then calculate the angle of the mouse versus the circle's centerpoint.
Compare that angle to each wedge. If the angle is between the starting and ending angle of a specific wedge's arc, then the mouse is inside that wedge.
Another way is to use canvas's built in path hit-testing method: isPointInPath
Redefine one wedge. There's no need to actually stroke or fill that wedge. Just do the commands from beginPath to closePath.
Use context.isPointInPath(mouseX,mouseY) to hit-test if the mouse is inside that wedge.
If isPointInPath returns true, you've discovered the wedge under the mouse. If not, then redefine & hit-test each of the other wedges.
Here's something I coded a while back that hit-tests the wedges of a pie chart when hovering and moves the wedge out of the pie when a wedge is clicked.
It uses the isPointInPath method to do the hit-testing:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineJoin = "round";
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas.scrollLeft();
var scrollY = $canvas.scrollTop();
function Wedge(cx, cy, radius, startAngleDeg, endAngleDeg, fill, stroke, linewidth) {
this.cx = cx;
this.cy = cy;
this.radius = radius;
this.startAngle = startAngleDeg * Math.PI / 180;
this.endAngle = endAngleDeg * Math.PI / 180;
this.fill = fill;
this.stroke = stroke;
this.lineWidth = linewidth;
this.offsetX = 0;
this.offsetY = 0;
this.rr = radius * radius;
this.centerX = cx;
this.centerY = cy;
this.midAngle = this.startAngle + (this.endAngle - this.startAngle) / 2;
this.offsetDistance = 15;
this.explodeX = this.offsetDistance * Math.cos(this.midAngle);
this.explodeY = this.offsetDistance * Math.sin(this.midAngle);
this.isExploded = false;
};
Wedge.prototype.draw = function(fill, stroke) {
this.define();
this.fillStroke(fill, stroke);
ctx.beginPath();
ctx.arc(this.cx, this.cy, this.radius, 0, Math.PI * 2);
ctx.closePath();
ctx.lineWidth = 0.50;
ctx.stroke();
}
Wedge.prototype.fillStroke = function(fill, stroke) {
ctx.fillStyle = fill || this.fill;
ctx.fill();
ctx.strokeStyle = stroke, this.stroke;
ctx.lineWidth = this.lineWidth;
ctx.stroke();
}
Wedge.prototype.define = function() {
var x = this.cx + this.offsetX;
var y = this.cy + this.offsetY;
ctx.beginPath();
ctx.arc(x, y, this.radius, this.startAngle, this.endAngle);
ctx.lineTo(x, y);
ctx.closePath();
}
Wedge.prototype.ptAtAngle = function(radianAngle) {
var xx = (this.cx + this.offsetX) + this.radius * Math.cos(radianAngle);
var yy = (this.cy + this.offsetY) + this.radius * Math.sin(radianAngle);
return ({
x: x,
y: y
});
}
Wedge.prototype.explode = function(isExploded) {
this.isExploded = isExploded;
this.offsetX = isExploded ? this.explodeX : 0;
this.offsetY = isExploded ? this.explodeY : 0;
this.draw();
}
Wedge.prototype.isPointInside = function(x, y) {
var dx = x - (this.cx + this.offsetX);
var dy = y - (this.cy + this.offsetY);
if (dx * dx + dy * dy > this.rr) {
return (false);
}
var angle = (Math.atan2(dy, dx) + Math.PI * 2) % (Math.PI * 2);
return (angle >= this.startAngle && angle <= this.endAngle);
}
Wedge.prototype.marker = function(pos) {
ctx.beginPath();
ctx.arc(pos.x, pos.y, 3, 0, Math.PI * 2);
ctx.closePath();
ctx.fillStyle = "red";
ctx.fill();
}
function handleMouseDown(e) {
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
clear();
for (var i = 0; i < wedges.length; i++) {
var wedge = wedges[i].wedge;
if (wedge.isPointInside(mouseX, mouseY)) {
wedge.explode(!wedge.isExploded);
}
wedge.draw();
}
}
function handleMouseUp(e) {
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// Put your mouseup stuff here
isDown = false;
}
function handleMouseOut(e) {
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// Put your mouseOut stuff here
isDown = false;
}
function handleMouseMove(e) {
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
for (var i = 0; i < wedges.length; i++) {
var wedge = wedges[i].wedge;
if (wedge.isPointInside(mouseX, mouseY)) {
wedge.draw("black");
} else {
wedge.draw();
}
}
}
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function(e) {
handleMouseOut(e);
});
function clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
var PI2 = Math.PI * 2;
var cx = 150;
var cy = 150;
var r = 100;
var line = 2;
var stroke = "black";
var wedges = [];
wedges.push({
percent: 18,
fill: "red"
});
wedges.push({
percent: 30,
fill: "blue"
});
wedges.push({
percent: 25,
fill: "green"
});
wedges.push({
percent: 13,
fill: "purple"
});
wedges.push({
percent: 14,
fill: "gold"
});
var rAngle = 0;
for (var i = 0; i < wedges.length; i++) {
var wedge = wedges[i];
var angle = 360 * wedge.percent / 100;
wedge.wedge = new Wedge(cx, cy, r, rAngle, rAngle + angle, wedge.fill, "black", 1);
wedge.wedge.draw();
rAngle += angle;
}
window.onscroll = function(e) {
var BB = canvas.getBoundingClientRect();
offsetX = BB.left;
offsetY = BB.top;
}
body {
background-color: ivory;
}
#canvas {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Hover wedge to highlight it<br>Click wedge to explode that wedge</h4>
<canvas id="canvas" width=300 height=300></canvas>

Capturing the mouse coordinates on every step of a jQuery animation

I'm trying to get the mouse coordinates during a jQuery animation, I'm doing this because I'm working on an interactive plug-in which moves the background image inside a div from covercss property to 100% of it's scale when the user go over the element.
I'm near to completing the plug-in but the animation is buggy because it work on the last position of the mouse fired by mousemove event of jQuery.
Does exists some way to avoid the problem?
This is my situation:
$(settings.selector).hover(function (e) {
$(this).bind('mousemove', setFollowMouse);
}, function () {
$(this).unbind('mousemove', setFollowMouse);
zoomOut();
});
var setFollowMouse = function (e) {
var o = {offsetLeft:this.offsetLeft, offsetTop:this.offsetTop};
if (!settings.bg.zooming_in && settings.bg.current_scale != 100) {
settings.bg.zooming_in = true;
zoomIn(e, o);
} else {
followMouse(e, o);
}
}
var zoomIn = function (e, o) {
$({scale:settings.bg.min_perc}).animate ({
scale:100
},{
easing:settings.zoom_in.easing,
duration:settings.zoom_in.duration,
step:function () {
settings.bg.current_scale = this.scale;
followMouse(e, o);
},
complete:function () {
settings.bg.current_scale = 100;
settings.bg.zooming_in = false;
followMouse(e, o);
}
});
}
var followMouse = function (e, o) {
var m_x = e.pageX - o.offsetLeft;
var m_y = e.pageY - o.offsetTop;
settings.bg.perc_pos_x = ((m_x * 100) / (a_w - bg_w)) + '%';
settings.bg.perc_pos_y = ((m_y * 100) / (a_h - bg_h)) + '%';
var bg_w = getScalePercent(settings.bg.width, settings.bg.current_scale);
var a_w = settings.container.width;
var bg_h = getScalePercent(settings.bg.height, settings.bg.current_scale);
var a_h = settings.container.height;
var bpx = - (bg_w - a_w) * m_x / a_w;
var bpy = - (bg_h - a_h) * m_y / a_h;
$(settings.selector).css({
backgroundPosition:bpx + 'px ' + bpy + 'px'
,backgroundSize:bg_w + 'px ' + bg_h + 'px'
});
}
As you see, I use animation to calculate the progressive scaling of the background-image, and trying to calculating it with the follow mouse method, but if I sto moving the mouse, the animation works with the last mousemove event.pageX and Y mouse position.
I've done this because I have problems with make animation method fluid if I trying to rewrite it continuously by with the mouse.
Should I follow some different way to avoid the bug?
forgive my dodgy math; but this should help!
<html>
<head>
<script type="text/javascript" charset="utf-8">
window.onload = function () {
var img = new Image();
img.src = 'http://wallpapers.free-review.net/wallpapers/23/Autumn_Theme_-_Windows_7_Backgrounds.jpg';
var canvas = document.getElementById("canvas1");
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousemove', onMouseMove, false);
var ctx = canvas.getContext("2d");
var scale = 0.9;
var scaledwidth = canvas.width * scale;
var scaledheight = canvas.height * scale;
var scaledcenterX = scaledwidth /2;
var scaledcenterY = scaledheight /2;
var animloop = setInterval(function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, scaledwidth, scaledheight, canvas.width - scaledcenterX, canvas.height - scaledcenterY, 0, 0, canvas.width, canvas.height);
}, .01);
function onMouseMove(e) {
mouseX = e.clientX - canvas.offsetLeft;
mouseY = e.clientY - canvas.offsetTop;
scale = mouseX/1000;
scaledwidth = canvas.width * scale;
scaledheight = canvas.height * scale;
}
};
</script>
<style>
body {
background: #001;
background-size: cover;
overflow: hidden;
}
#canvas1 {
position: absolute;
top: 0;
left: 0;
padding: 0;
margin: 0;
height: 100% auto;
}
</style>
</head>
<body>
<canvas id="canvas1"></canvas>
</body>
</html>
I've just solved the problem with this simple edit to my code:
var setFollowMouse = function (e) {
settings.mouse.x = e.pageX - this.offsetLeft;
settings.mouse.y = e.pageY - this.offsetTop;
if (!settings.bg.zooming_in && settings.bg.current_scale != 100) {
settings.bg.zooming_in = true;
zoomIn();
} else {
followMouse();
}
}
the old one:
var setFollowMouse = function (e) {
var o = {offsetLeft:this.offsetLeft, offsetTop:this.offsetTop};
if (!settings.bg.zooming_in && settings.bg.current_scale != 100) {
settings.bg.zooming_in = true;
zoomIn(e, o);
} else {
followMouse(e, o);
}
}
this has removed the buggy behavior.

Resources