I'm trying to get a line to snake down a canvas. I'm using if else statements, currently the line travels left to right, then down then right to left. But here I get stuck, it should go down again and then left to right again. not sure if I should be using functions?
Here is the pen
function setup(){
createCanvas(600,800);
background(250,180,20)
}
function draw(){
var left = 600;
var right = 800;
var speed = 3
timeline.move()
}
var timeline = {
speed : 3,
x : 20,
y : 20,
move : function(){
fill(0);
ellipse(this.x,this.y,20,20)
if(this.x<width-20){
this.x = this.x + this.speed
}
else if(this.y > 0){
this.y = this.y + this.speed}
if(this.y > 100 || this.x < 20){
this.y = this.y - this.speed
this.speed= this.speed*-1
this.x = this.x + this.speed+1}
if(this.x < 20 && this.y > 200){
this.y = this.y + this.speed
}
}
}
Thanks in advance
I would try to use some kind of points or instructions instead of hardcoding the values. It would probably get much easier to build upon. You could also probably break down the movement part into more generic functions if you want.
Here is some modified code:
function setup(){
createCanvas(600,800);
background(250,180,20)
}
var points = [
{x: 500, y:20},
{x: 500, y:80},
{x: 20, y: 80},
{x: 500, y: 300}
]
var currentPointIndex =0;
function draw(){
var left = 600;
var right = 800;
var speed = 3
timeline.move()
}
var timeline = {
speed : 5,
x : 20,
y : 20,
move : function(){
fill(0);
ellipse(this.x,this.y,20,20)
var didMove = false;
var currentPoint = points[currentPointIndex];
if(this.x < currentPoint.x - this.speed){
this.x += this.speed;
didMove = true;
}
else if(this.x > currentPoint.x + this.speed){
this.x -= this.speed;
didMove = true;
}
if(this.y < currentPoint.y - this.speed){
this.y += this.speed;
didMove = true;
}
else if(this.y > currentPoint.y + this.speed){
this.y -= this.speed;
didMove = true;
}
if(!didMove && currentPointIndex < points.length){
currentPointIndex++;
}
}
}
It's quick and dirty, but shows the general idea. Hope it is helpful!
Related
I would like to change the fill colour of an object over time. Is there a way to change the fill colour of an object after X frames?
I am learning about constructors, and I am thinking that in the code's updateParticle function, after this.age counts to 'X', the fill colour of the ellipse could change.
'''
function Particle(x, y, xSpeed, ySpeed, size, colour) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.size = size;
this.colour = colour;
this.age = 0;
this.drawParticle = function() {
fill(this.colour);
noStroke();
ellipse(this.x, this.y, this.size);
}
this.updateParticle = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
this.age++;
}
}
function Emitter(x, y, xSpeed, ySpeed, size, colour) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.size = size;
this.colour = colour;
this.particles = [];
this.startParticles = [];
this.lifetime = 0;
this.addParticle = function() {
var p = new Particle(random(this.x - 10, this.x + 10),
random(this.y - 10, this.y + 10),
random(this.xSpeed - 0.4, this.xSpeed + 0.4),
random(this.ySpeed - 5, this.ySpeed - 1),
random(this.size - 4, this.size + 40),
this.colour);
return p;
}
this.startEmitter = function(startParticles, lifetime) {
this.startParticles = startParticles;
this.lifetime = lifetime;
for (var i = 0; i < startParticles; i++) {
this.particles.push(this.addParticle());
}
}
this.updateParticles = function() {
var deadParticles = 0
for (var i = this.particles.length - 1; i >= 0; i--) {
this.particles[i].drawParticle();
this.particles[i].updateParticle();
if (this.particles[i].age > random(0, this.lifetime)) {
this.particles.splice(i, 1);
deadParticles++;
}
}
if (deadParticles > 0) {
for (var i = 0; i < deadParticles; i++) {
this.particles.push(this.addParticle());
}
}
}
}
var emit;
function setup() {
createCanvas(800, 600);
emit = new Emitter(width / 2, height - 100, 0, -1, 10, color(200, 0, 200, 50));
emit.startEmitter(600, 4000);
}
function draw() {
background(200);
emit.updateParticles();
}
'''
Well you could just:
if(frameCount % 30 == 0){ // % 30 is the remainder of num / 30, so 4 % 3 = 1, since 3 / 3 = 0 And 4 / 3 = 3.33
fill("lime") // these are just preset colors in p5.js AND css lime == rgb(0,255,0)
} else {
fill('darkred')
}
or you could also do it with for example a switch statement: using background for no reason
switch(MY_frameCount){
case 1:
background('blue')
break
case 2:
background("darkgreen")
break
case 376:
background(crimson)
// break
}
MY_frameCount ++
or:
if(Math.random() < 0.1){
fill(Math.random() * 255, Math.random() * 255, Math.random() * 255)
} // this should on average fill with random color every 10 frames
is it possible to change the particle color to any color in mind?
Because i only get one color and i want to change it to make it more suitable for spring is there a way to configure the colors based on your taste following is my functions code:
function Particle() {
this.pos = createVector(random(width), random(height));
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.maxspeed = 4;
this.h = 100;
this.prevPos = this.pos.copy();
this.update = function() {
this.vel.add(this.acc);
this.vel.limit(this.maxspeed);
this.pos.add(this.vel);
this.acc.mult(0);
}
this.follow = function(vectors) {
var x = floor(this.pos.x / scl);
var y = floor(this.pos.y / scl);
var index = x + y * cols;
var force = vectors[index];
this.applyForce(force);
}
this.applyForce = function(force) {
this.acc.add(force);
}
this.show = function() {
strokeWeight(6);
stroke(255, this.h, 10);
this.h = this.h + 1;
if (this.h > 255) {
this.h = 100;
}
strokeWeight(8);
line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
this.updatePrev();
}
this.updatePrev = function() {
this.prevPos.x = this.pos.x;
this.prevPos.y = this.pos.y;
}
this.edges = function() {
if (this.pos.x > width) {
this.pos.x = 0;
this.updatePrev();
}
if (this.pos.x < 0) {
this.pos.x = width;
this.updatePrev();
}
if (this.pos.y > height) {
this.pos.y = 0;
this.updatePrev();
}
if (this.pos.y < 0) {
this.pos.y = height;
this.updatePrev();
}
}
}
The call to stroke(255, this.h, 10) in the show function is what is determining the color of the line drawn by the Particle class in this case. It looks like it is cycling from red to yellow. The stroke function is well documented. You can certainly use it to make the line drawn in this example any color you want. You can learn more about color in p5js on p5js.org.
I can't seem to get collision detection to work with the floor array? I seem to be having the issue in the ballMovement function.
The ball falls straight through the rectangles made by the array.
Floor Array (issue)
Collision Detection
<html lang=en>
<head>
<meta charset=utf-8>
<title>Javascript gravity</title>
<link rel="stylesheet" href="game.css">
</head>
<body onload="init()">
<script>
var canvas, ctx, container;
canvas = document.createElement( 'canvas' );
ctx = canvas.getContext("2d");
var ball;
var message = "Helloworld";
// Velocity x
var vx = 2.0;
// Velocity y - randomly set
var vy;
var gravity = 0.5;
var bounce = 0.7;
var xFriction = 0.1;
// Floor Array
var floor = new Array();
//Rectagles
Rectangle = function(x, y, w, h, color){
if (x == null || y == null || w == null || h == null){
alert("You must pass in all the veriables for a rectange: (x, y, width, height)");
var errorMsg = "The following are not provided:";
if (x == null)
errorMsg += " 'x' ";
if (y == null)
errorMsg += " 'y' ";
if (w == null)
errorMsg += " 'width' ";
if (h == null)
errorMsg += " 'height'";
alert(errorMsg);
throw new Error(errorMsg);
}
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.color = new Color();
this.Contains = function(x, y){
if (x >= this.x && x <= this.x + this.width &&
y >= this.y && y <= this.y + this.height)
return true;
else
return false;
};
this.Draw = function(ctx){
ctx.fillStyle = this.color.ToStandard();
ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
//Rectangle Colors
Color = function(r, g, b, a){
this.r = 255;
this.g = 255;
this.b = 255;
this.a = 1;
if (r != null)
this.r = r;
if (g != null)
this.g = g;
if (b != null)
this.b = b;
if (a != null)
this.a = a;
this.ToStandard = function(noAlpha){
if (noAlpha == null || !noAlpha)
return "rgba(" + this.r + "," + this.g + "," + this.b + "," + this.a + ")";
else
return "rgb(" + this.r + "," + this.g + "," + this.b + ")";
};
};
function init(){
setupCanvas();
vy = (Math.random() * -5) + -5;
ball = {x:canvas.width / 2, y:100, radius:10, status: 0, color:"red"};
floor.push(new Rectangle(0, 480, 500, 20));
floor.push(new Rectangle(250, 350, 200, 20));
//floor.push(new Rectangle(150, 300, 20, 20));
//floor.push(new Rectangle(200, 250, 20, 20));
//floor.push(new Rectangle(250, 200, 20, 20));
//floor.push(new Rectangle(300, 150, 20, 20));
//floor.push(new Rectangle(350, 100, 20, 20));
//floor.push(new Rectangle(400, 50, 20, 20));
for (var i = 0; i < floor.length; i++)floor[i].color = new Color(0, 0, 0, 1);
}//end init method
function draw() {
ctx.clearRect(0,0,canvas.width, canvas.height);
for (var i = 0; i < floor.length; i++)
floor[i].Draw(ctx);
//display some text
ctx.fillStyle = "red";
ctx.font = "20px Arial";
ctx.fillText(message, 20,20);
//draw cirlce
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2, false);
ctx.fillStyle = ball.color;
ctx.fill();
ctx.closePath();
ballMovement();
}
setInterval(draw, 1000/35);
function ballMovement(){
ball.x += vx;
ball.y += vy;
vy += gravity;
//If either wall is hit, change direction on x axis
if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0){
vx *= -1;
}
// Ball hits the canvas floor
if (ball.y + ball.radius > canvas.height){// ||
// Re-positioning on the base
ball.y = canvas.height - ball.radius;
//bounce the ball
vy *= -bounce;
//do this otherwise, ball never stops bouncing
if(vy<0 && vy>-2.1)
vy=0;
//do this otherwise ball never stops on xaxis
if(Math.abs(vx)<1.1)
vx=0;
xF();
}
// Ball hits the rectangles
if (ball.y + ball.radius > floor.width){// ||
// Re-positioning on the base
ball.y = floor.height - ball.radius;
//bounce the ball
vy *= -bounce;
//do this otherwise, ball never stops bouncing
if(vy<0 && vy>-2.1)
vy=0;
//do this otherwise ball never stops on xaxis
if(Math.abs(vx)<1.1)
vx=0;
xF();
}
}
function xF(){
if(vx>0)
vx = vx - xFriction;
if(vx<0)
vx = vx + xFriction;
}
function setupCanvas() {//setup canvas
container = document.createElement( 'div' );
container.className = "container";
canvas.width = 500;
canvas.height = 500;
document.body.appendChild( container );
container.appendChild(canvas);
ctx.strokeStyle = "red";
ctx.lineWidth =1;
}
</script>
</body>
</html>
There are a couple of mistakes:
You compare the ball position on Y axis ball.y to the bar width floor.width, it may be a typing/editing mistake.
You should replace floor.width by floor.y to check whether the ball hits the bar when it falls.
But floor is an Array of Rectangle, it includes the bar and potential bricks to break, if I guess it right. So you need to loop through floor before checking, otherwise floor.height equals undefined.
for (let i = 0; i < floor.length; i += 1) {
const rect = floor[i];
// Ball hits the rectangle
if (ball.y + ball.radius > rect.y) {
// ...
}
}
Then, floor isn't an appropriate name for an Array which doesn't contain any 'floor'.
Finally, add a condition to handle the ball X position (collisions with the bar, the bricks, etc.).
Working example:
https://jsfiddle.net/nmerinian/3sokr512/22/
Have a good day
I would like to do the following in p5.js. Say I have a canvas roughly like this:
Let's say I have given those red squares some interactivity using the function mouseClicked() and their respective coordinates in the canvas (as in, if I click on a square, change its color).
Now I'd like to use that blue "i"-button to display some sort of info box, and it should look approximately like this:
I want that "info dialog" to go away if the user clicks on that "OK-button" (whcih is not really a button, but also just a square in a p5 canvas).
Question: Is there an elegant way of deactivating the "square interactivity" and activating that "OK button interactivity" and to have the interactivity the other way around whenever the info box is not being displayed?
The only way I can think of to achieve this goes like this:
function mouseClicked(){
if(infoBoxIsBeingDisplayed){
do something
}else{
do something else
}
}
However, this seems a little convoluted.
I'd appreciate any suggestions on how to do this better.
Your solution seems fine, and it also seems much less "convoluted" than any of the other options. Keep it simple.
You might be able to clean up your code by splitting up your logic into smaller utility functions. Something like this:
function mouseClicked(){
if(infoBoxIsBeingDisplayed){
mouseClickedInfoBox();
}else{
mouseClickedSquaresCanvas();
}
}
Then your logic would be in those utility functions, specific to each screen. You could further split it up to generalize your bounds-checking, but the idea is the same.
I've run into a similar problem to this before, the best way I came up with to solve this (which is a fairly patchy way to do it) is to move the squares outside of the canvas. sorry my code is probably really messy but look at the function game and you will see what i did
If you run the game make it full screen.
example:(to play the game use A and D or use the arrow keys but i suggest A and D because the way the code snippet is set up the game doesn't fit on the page and the page moves around when you press the arrow keys)
var bs = [];
var speed;
var ship1;
var num = 40;
var d;
var gscore = 0;
var highscore = 0;
var cap = 0;
function setup() {
createCanvas(windowWidth,windowHeight- 4);
for(var i = 0; i < num; i++) {
bs[i] = new Box(random(0, width), random(-600,-30));
}
ship1 = new ship();
button1 = new button();
}
function draw() {
background(0);
if(cap == 0){
gscore = gscore + 0.1;
}
if(highscore < gscore){
highscore = gscore;
}
speed = map(gscore,4,100,4,5);
ship1.show();
ship1.update();
for(var i = 0; i < num; i++) {
bs[i].update();
bs[i].show();
if(bs[i].y >= height){
bs[i].x = random(0, width);
bs[i].y = random(-600,-30);
}
for(var j = 0; j < num; j++) {
if(bs[i].touch(bs[j])){
if(bs[i] != bs[j]){
bs[j].x = random(0, width);
bs[j].y = random(-600,-30);
}
}
}
if(bs[i].touch(ship1)){
game();
}
}
push();
fill(255,0,0);
textSize(36);
text("score: "+ floor(gscore),0,36);
text("highscore: "+floor(highscore),0,72);
pop();
}
function Box(x, y) {
this.x = x;
this.y = y;
this.show = function() {
fill(255);
noStroke();
rect(this.x, this.y, 30, 30);
}
this.update = function() {
this.y = this.y + speed;
}
this.touch = function(other){
d = dist(this.x, this.y, other.x, other.y);
if(d < 15/*half of the squares*/+15/*the total area of the ship*/){
return true;
}else {
return false;
}
}
}
function game(){//look here, game is the end game screen
for(var i = 0; i < num; i++) {
bs[i].x = -200;//making all squares x value -200
bs[i].y = -200;//making all squares y value -200
}
ship1.x = -200;//making ship x value -200
ship1.y = -200;//making ship y value -200
cap = 1;//cap is a variable made to stop the score from increasing when the end game screen is shown its "capping" the score
push();
fill(255,0,0);
textAlign(CENTER);
textSize(64);
text("You lose", width/2, height/2);
fill(255);
text("Try again?", width/2,height/2+64);
button1.touch();//touch checks if the mouse is over the button(the button sucks ass btw the hitbox for it is a square not a rectangle)
button1.show();//showing the button
button1.update();//updates the text and button color when highlighted
fill(texthover);
textSize(48);
text("Yes",width/2, height/2+145);
pop();
}
function button(){
this.x = width/2;
this.y = height/2+128;
this.d;
this.update = function() {
this.x = width/2;
this.y = height/2+128;
}
this.show = function(){
push();
rectMode(CENTER);
fill(hover);
rect(this.x, this.y, 128, 64, 50);
pop();
}
this.touch = function(){
this.d = dist(this.x, this.y, mouseX, mouseY);
if(this.d <32){
hover = 51;
texthover = 255;
if(mouseIsPressed){
for(var i = 0; i < num; i++) {
bs[i].x = random(0, width);
bs[i].y = random(-600,-30);
}
ship1.x = width/2;
ship1.y = 450;
gscore = 0;
cap = 0;
}
}else {
hover = 200;
texthover = 0;
}
}
}
function ship() {
this.x = width/2;
this.y = 450;
this.update = function() {
if(keyIsDown(LEFT_ARROW) || keyIsDown(65)) {
if(this.x>14){
this.x = this.x - map(gscore,2,100,2,3);
}
}
if(keyIsDown(RIGHT_ARROW) || keyIsDown(68)) {
if(this.x<width- 15){
this.x = this.x + map(gscore,2,100,2,3);
}
}
}
this.show = function() {
push();
rectMode(CENTER);
fill(200,200,0);
rect(this.x+15, this.y+5, 5, 30);
fill(150,100,200);
rect(this.x+15, this.y + 15,30, 15)
pop();
}
}
function windowResized() {
createCanvas(windowWidth,windowHeight- 4);
button1.update();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/addons/p5.dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.14/p5.js"></script>
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>