Texture flickering in p5 - p5.js

I have a scene with a cube and a custom obj. I am attempting to apply a gradient as a texture to the cube via createGraphics, but every time I use createGraphics as a texture on the cube it flickers
The custom model does not have the same issue when using the createGraphics texture for it, it is exclusively a problem with the cube.
Here is my code:
var camy;
var camz;
var camoffset;
var horiZon;
var c1;
var c2;
function preload() {
fria = loadImage('nocity.png');
island = loadModel('untitled.obj');
}
function setup() {
canvas = createCanvas(windowWidth, windowHeight, WEBGL);
pixelDensity=1;
c1 = color(255, 255, 255);
c2 = color(0, 0, 0);
sunset = createGraphics(200, 200);
}
function windowResized() {
resizeCanvas(windowWidth,windowHeight);
}
function draw() {
background(0, 5, 100);
angleMode(DEGREES);
camoffset = 2500 - windowWidth;
horiZon = map(mouseY, 0, height, -35, -65);
camx = map(mouseX, 0, width, -500, 500);
camz = map(mouseY, height, 0, -1400 - camoffset, -2100 - camoffset);
camy = map(mouseY, height, 0, -1000 - camoffset, -400);
setGradient(0, 0, 200, 200, c1, c2);
perspective(PI / 3.0, width / height, 0.1, 10000);
camera(camx, camy, camz, 0, 0, 0, 0, 1, -0.25);
translate(-2.5, 6, 0);
rotateZ(180);
rotateY(180);
noStroke();
texture(fria);
model(island);
texture(sunset);
translate(0, 100, horiZon);
box(200, 200, 1);
}
function setGradient(x, y, w, h, c1, c2) {
noFill();
for (var i = y; i <= y + h; i++) {
var inter = map(i, y, y + h, 0, 1);
var c = lerpColor(c1, c2, inter);
sunset.stroke(c);
sunset.line(x, i, x + w, i);
}
}

I found a solution to this problem. When I removed the camera code, the flickering disappeared. So the solution I made was I instead used translation and rotation to emulate the camera motions that I wanted. It is quite hard to think of it this way, but you can figure out what translation you need to do with simple trig.

Related

How to work with multiple datasets in p5.js?

I want to create multiple line graphs with their own datasets into one p5.js sketch.
I created one line graph and do not know how to make another line graph to work with a different dataset.
https://editor.p5js.org/ariel.koh/sketches/VsRk3KxYp
I tried to create another preload table for my second graph but it did not work so I am still confused.
This was what I tried but I think it is not right, I never tried working with multiple datasets before so I am confused :(
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
// canonattacks dataset
canonaattacksdataset = loadTable("canonattacks.csv", "csv",
"header");
}
You're on the right track loading the data.
The p5.js code you posted is a bit convoluted, here only a few examples:
the year labels a manually drawn, for each chart (even though the data is contained in the csv files)
if the text is simply drawn for the years but separate style, coordinate transformations, etc. are used then the push()/pop() call don't add anything.(e.g push();let sbm = 'Saul Bass Movies';...)
the drawLineGraph() function is defined twice (which might get you into variable shadowing bugs) and might be accidentally called within itself
No wonder you're confused.
I'd simplify as much as possible:
get back to loading and displaying one graph
load the second dataset (as you already correctly do above)
display the second graph
For example:
// file -> duplicate and file -> save
// this sketch first before you
// start working on it.
//
//
//
// Graph from Data, Line graph example
//
// Slides:
// http://slides.com/sojamo/cid-3-2122/fullscreen#/12/5
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
canonaattacksdataset = loadTable("canonattacks.csv", "csv", "header");
}
function setup() {
// if you add SVG as 3rd parameter and then
// press s, the canvas will be saved as SVG file
createCanvas(displayWidth, displayHeight, SVG);
}
function draw() {
background(184, 37, 0);
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text("Burns", 30, 20, 330, 150); // Text wraps within text box
pop();
//linegraph
drawLineGraph({
dataset: burnsdataset,
column: 1,
x: 30,
y: 50,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text("Canon Attacks", 30, 250, 330, 150); // Text wraps within text box
pop();
//linegraph
drawLineGraph({
dataset: canonaattacksdataset,
column: 1,
x: 30,
y: 280,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
}
function drawLineGraph(theProps = {}) {
let values = theProps.dataset.getColumn(theProps.column);
let minValue = min(values);
let maxValue = max(values);
let x = theProps.x || 0;
let y = theProps.y || 0;
let w = theProps.w || 400;
let h = theProps.h || 300;
let bg = theProps.bg || color(255, 40);
let fg = theProps.fg || color(255, 120);
let dc = theProps.dc || color(0, 120);
let bc = theProps.bc || color(0, 120);
let lc = theProps.lc || color(255);
let thickness = theProps.thickness || 1;
let isLabel = theProps.isLabel || false;
let isCurve = theProps.isCurve || false;
let isDots = theProps.isDots || false;
let isBackground = theProps.isBackground || false;
let spacing = w / (values.length - 1);
let marginTopBottom = 20;
// we will calcualte the x and y values for each
// point first, because we need it later a couple
// of times.
let xx = [];
let yy = [];
let n = values.length;
for (let i = 0; i < n; i++) {
xx[i] = i * spacing;
yy[i] = map(
values[i],
minValue,
maxValue,
-marginTopBottom,
marginTopBottom - h
);
}
push();
translate(x, y);
translate(0, h);
// 1. draw background
if (isBackground == true) {
fill(bg);
rect(0, 0, w, -h);
// 2. draw grid
noStroke();
for (let i = 0; i < n - 1; i++) {
// fill(255,i%2 == 0 ? 80:40);
rect(xx[i], 0, 1, -h);
}
}
// 3. draw curved line graph
noFill();
stroke(lc);
strokeWeight(thickness);
beginShape();
if (isCurve == true) {
vertex(xx[0], yy[0]);
}
for (let i = 0; i < n; i++) {
let fn = isCurve == true ? curveVertex : vertex;
fn(xx[i], yy[i]);
}
if (isCurve == true) {
vertex(xx[n - 1], yy[n - 1]);
}
endShape();
// 4. draw dot / label for each value
noStroke();
// finally lets draw the dots and
// labels if enabled
let d = thickness + 8;
for (let i = 0; i < n; i++) {
push();
translate(xx[i], yy[i]);
if(isDots == true) {
fill(bc);
ellipse(0, 0, d + 4, d + 4);
fill(dc);
ellipse(0, 0, d, d);
}
if (isLabel == true) {
fill(lc)
rotate(-0.5);
textSize(7);
text(values[i], d, -d);
}
pop();
}
pop();
}
With that working you can focus on making the code nicer.
Taking the idea of "don't repeat yourself(DRY)" you can notice a few patterns that could be improved:
you try to not just draw the graph, but also also display the graph's
label: perhaps the drawLineGraph() could include that
you seem to manually be drawing every single year label, even though the data is already in the dataset and the x position is already calculated to display the points of the graph
Tackling point 1 is fairly straight foward: simply move the label drawing instrunctions inside the function, handle the extra argument to get the label text and adjust coordinates so they're relative to the graph.
Here's a modified version of the above integrating label as part of the drawLineGraph() function:
// file -> duplicate and file -> save
// this sketch first before you
// start working on it.
//
//
//
// Graph from Data, Line graph example
//
// Slides:
// http://slides.com/sojamo/cid-3-2122/fullscreen#/12/5
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
canonaattacksdataset = loadTable("canonattacks.csv", "csv", "header");
}
function setup() {
// if you add SVG as 3rd parameter and then
// press s, the canvas will be saved as SVG file
createCanvas(displayWidth, displayHeight, SVG);
}
function draw() {
background(184, 37, 0);
//linegraph
drawLineGraph({
dataset: burnsdataset,
label: "Burns",
column: 1,
x: 30,
y: 50,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
//linegraph
drawLineGraph({
dataset: canonaattacksdataset,
label: "Canon Attacks",
column: 1,
x: 30,
y: 280,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
}
function drawLineGraph(theProps = {}) {
let values = theProps.dataset.getColumn(theProps.column);
let minValue = min(values);
let maxValue = max(values);
let x = theProps.x || 0;
let y = theProps.y || 0;
let w = theProps.w || 400;
let h = theProps.h || 300;
let bg = theProps.bg || color(255, 40);
let fg = theProps.fg || color(255, 120);
let dc = theProps.dc || color(0, 120);
let bc = theProps.bc || color(0, 120);
let lc = theProps.lc || color(255);
let thickness = theProps.thickness || 1;
let isLabel = theProps.isLabel || false;
let isCurve = theProps.isCurve || false;
let isDots = theProps.isDots || false;
let isBackground = theProps.isBackground || false;
let label = theProps.label || "";
let spacing = w / (values.length - 1);
let marginTopBottom = 20;
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text(label, x, y + h + marginTopBottom * 0.5, w, h); // Text wraps within text box
pop();
// we will calculate the x and y values for each
// point first, because we need it later a couple
// of times.
let xx = [];
let yy = [];
let n = values.length;
for (let i = 0; i < n; i++) {
xx[i] = i * spacing;
yy[i] = map(
values[i],
minValue,
maxValue,
-marginTopBottom,
marginTopBottom - h
);
}
push();
translate(x, y);
translate(0, h);
// 1. draw background
if (isBackground == true) {
fill(bg);
rect(0, 0, w, -h);
// 2. draw grid
noStroke();
for (let i = 0; i < n - 1; i++) {
// fill(255,i%2 == 0 ? 80:40);
rect(xx[i], 0, 1, -h);
}
}
// 3. draw curved line graph
noFill();
stroke(lc);
strokeWeight(thickness);
beginShape();
if (isCurve == true) {
vertex(xx[0], yy[0]);
}
for (let i = 0; i < n; i++) {
let fn = isCurve == true ? curveVertex : vertex;
fn(xx[i], yy[i]);
}
if (isCurve == true) {
vertex(xx[n - 1], yy[n - 1]);
}
endShape();
// 4. draw dot / label for each value
noStroke();
// finally lets draw the dots and
// labels if enabled
let d = thickness + 8;
for (let i = 0; i < n; i++) {
push();
translate(xx[i], yy[i]);
if(isDots == true) {
fill(bc);
ellipse(0, 0, d + 4, d + 4);
fill(dc);
ellipse(0, 0, d, d);
}
if (isLabel == true) {
fill(lc)
rotate(-0.5);
textSize(7);
text(values[i], d, -d);
}
pop();
}
pop();
}
And here's a modified version of the above that renders the labels on the x axis (year):
// file -> duplicate and file -> save
// this sketch first before you
// start working on it.
//
//
//
// Graph from Data, Line graph example
//
// Slides:
// http://slides.com/sojamo/cid-3-2122/fullscreen#/12/5
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
// canon attacks dataset
canonaattacksdataset = loadTable("canonattacks.csv", "csv", "header");
}
function setup() {
// if you add SVG as 3rd parameter and then
// press s, the canvas will be saved as SVG file
createCanvas(displayWidth, displayHeight, SVG);
drawPlots();
}
function drawPlots() {
background(184, 37, 0);
// burnsdataset linegraph
drawLineGraph({
dataset: burnsdataset,
label: "Burns",
xColumn: 0,
yColumn: 1,
x: 30,
y: 50,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
// canonaattacksdataset linegraph
drawLineGraph({
dataset: canonaattacksdataset,
label: "Canon Attacks",
xColumn: 0,
yColumn: 1,
x: 30,
y: 300,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
}
function drawLineGraph(theProps = {}) {
let values = theProps.dataset.getColumn(theProps.yColumn);
let minValue = min(values);
let maxValue = max(values);
let labels = theProps.dataset.getColumn(theProps.xColumn);
let x = theProps.x || 0;
let y = theProps.y || 0;
let w = theProps.w || 400;
let h = theProps.h || 300;
let bg = theProps.bg || color(255, 40);
let fg = theProps.fg || color(255, 120);
let dc = theProps.dc || color(0, 120);
let bc = theProps.bc || color(0, 120);
let lc = theProps.lc || color(255);
let thickness = theProps.thickness || 1;
let isLabel = theProps.isLabel || false;
let isCurve = theProps.isCurve || false;
let isDots = theProps.isDots || false;
let isBackground = theProps.isBackground || false;
let label = theProps.label || "";
let spacing = w / (values.length - 1);
let marginTopBottom = 20;
// y position for labels (e.g. years)
let labelsY = marginTopBottom * 0.5;
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text(label, x, y - marginTopBottom, w, h); // Text wraps within text box
pop();
// we will calculate the x and y values for each
// point first, because we need it later a couple
// of times.
let xx = [];
let yy = [];
let n = values.length;
for (let i = 0; i < n; i++) {
xx[i] = i * spacing;
yy[i] = map(
values[i],
minValue,
maxValue,
-marginTopBottom,
marginTopBottom - h
);
}
push();
translate(x, y);
translate(0, h);
// 1. draw background
if (isBackground == true) {
fill(bg);
rect(0, 0, w, -h);
// 2. draw grid
noStroke();
for (let i = 0; i < n - 1; i++) {
// fill(255,i%2 == 0 ? 80:40);
rect(xx[i], 0, 1, -h);
}
}
// 3. draw curved line graph
noFill();
stroke(lc);
strokeWeight(thickness);
beginShape();
if (isCurve == true) {
vertex(xx[0], yy[0]);
}
for (let i = 0; i < n; i++) {
let fn = isCurve == true ? curveVertex : vertex;
fn(xx[i], yy[i]);
// label per data point
push();
noStroke();
fill(255);
textSize(9);
textAlign(CENTER);
text(labels[i], xx[i], labelsY);
pop();
}
if (isCurve == true) {
vertex(xx[n - 1], yy[n - 1]);
}
endShape();
// 4. draw dot / label for each value
noStroke();
// finally lets draw the dots and
// labels if enabled
let d = thickness + 8;
for (let i = 0; i < n; i++) {
push();
translate(xx[i], yy[i]);
if(isDots == true) {
fill(bc);
ellipse(0, 0, d + 4, d + 4);
fill(dc);
ellipse(0, 0, d, d);
}
if (isLabel == true) {
fill(lc)
rotate(-0.5);
textSize(7);
text(values[i], d, -d);
}
pop();
}
pop();
}
// if you want to use the SVG export
// option, go to setup and enable SVG mode
function keyPressed() {
if (key === "s") {
saveSVG("line-graph.svg");
}
}
There's one slight detail snuck in there: I've renamed draw() to drawPlots() and called it once from setup(). That is to render the plots a single time since they don't change and save CPU resources. If you do plan to have some sort interation changing these graphs then you should use draw().

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>

p5.js not drawing a 3d box

I am creating a simulator using P5.js. Within the simulator, I need a green box, however it does not seem to be appearing. The code is below:
var outputs = [];
function setup() {
createCanvas(600, 400, WEBGL);
background(200);
for (var i = 0; i < 1; i++) {
drop = new Water(width / 2, height / 2, 0, 1);
outputs[i] = drop;
}
}
function draw() {
push();
translate(200, 150, 0);
stroke(0, 100, 0);
fill(0, 255, 0);
box(150, 150, 150);
pop();
for (var i = 0; i < outputs.length; i++) {
outputs[i].update();
}
background(200);
}
Here is the water class:
function Water(x_, y_, z_, yVel_) {
this.r = random(0.25, 1);
this.xOff = random(-(this.r / 10), (this.r / 10));
this.zOff = random(-(this.r / 10), (this.r / 10));
this.x = x_ + this.xOff;
this.y = y_;
this.z = z_ + this.zOff;
this.yVel = yVel_;
this.pos = createVector(this.x, this.y, this.z);
this.show = function() {
push();
translate(this.pos.x, this.pos.y, this.pos.z);
noStroke();
fill(0, 0, 255);
sphere(this.r * 2);
pop();
}
this.update = function() {
this.vel = createVector(random(-(this.r / 10), (this.r / 10)),
this.yVel, random(-(this.r / 10),
(this.r / 10)));
this.pos.add(this.vel);
this.show();
}
}
This is a web based simulation, with another module which appears to be working fine.
Any help would be greatly appreciated. Thanks in advance!
Removing the parts that require the Water class, and moving the background function call to the top of draw, it seems to work just fine.
So, the problem is
Either that you forgot to put background on top
Or something's wrong with the Water class.
Here's your code with the mentioned problems fixed.
var outputs = [];
function setup() {
createCanvas(600, 400, WEBGL);
}
function draw() {
background(200);
push();
translate(200, 150, 0);
stroke(0, 100, 0);
fill(0, 255, 0);
box(150, 150, 150);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.1/p5.min.js"></script>
Its not rendering because you're background is over your scene
function draw() {
background(200);
push();
translate(200, 150, 0);
stroke(0, 100, 0);
fill(0, 255, 0);
box(150, 150, 150);
pop();
for (var i = 0; i < outputs.length; i++) {
outputs[i].update();
}
}
What your doing is drawing the box and the drops and you cover it all up with your background
if you don't have a background you will see how p5.js renders animation
p5.js not moving it, its just looping through draw every frame and the background covers up the previous frame

p5.js this._renderer.image is not a function issue

var adobe1bar1;
function preload() {
adobe1bar1 = loadImage("1-1.png");
}
function setup() {
createCanvas(500, 500, WEBGL);
center = createVector(width / 2, height / 2, height / 2);
cameraZ = -500;
}
function draw() {
background(40); // backgraound white
var cameraX = map(mouseX, 0, width, -500, 500); // map
var cameraY = map(mouseY, 0, height, -500, 500);
console.log(cameraY, cameraX);
if (cameraZ < -500) {
cameraZ = -500;
}
if (cameraZ > 0) {
cameraZ = 0;
}
camera(center.x + cameraX, center.y + cameraY, center.z + cameraZ, center.x, center.y, center.z, 0, 1, 0);
translate(center.x, center.y, center.z);
translate(0, 0, 0);
image(adobe1bar1, -250, -250, 500, 500);
}
Here is my p5.js code.
When I use the image() function
The following error message keeps appearing.
Uncaught TypeError: this._renderer.image is not a function
Is there a solution?
When not using 'WEBGL',
it uploads images without error,
but the camera() function does not work.
image is not a WEBGL function.
Try to apply an image texture to a plane instead.
texture(adobe1bar1);
translate(-250, -250, 0);
plane(500);
https://github.com/processing/p5.js/wiki/Getting-started-with-WebGL-in-p5
EDIT:
To use transparent texture you need to enable blend mode which can be done by using:
fill(0,0,0,0);
In setup

Map translated coordinates back to original

Once a transformation of coordinates has taken place during a the rendering of a computer graphics scene, how do you map inputs on the rendered scene back to the original actor(s) coordinate systems?
Using this JSFiddle https://jsfiddle.net/bbz5s183/3/ as a starting point, implement the canvas click event handler so that.
It can identify if a star was clicked.
It will work consistently no matter how the canvas is resized.
JSFIDDLE SCRIPT CONTENT BELOW
var draggable = document.getElementById('draggable')
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
// Draw a star in a 1 x 1 coordinate plane.
function star(color) {
context.beginPath();
context.moveTo(0.5, 0);
context.lineTo(0.15, 1.0);
context.lineTo(1.0, 0.4);
context.lineTo(0, 0.4);
context.lineTo(0.85, 1.0);
context.closePath();
context.fillStyle = color;
context.fill();
}
// Draw a scene of stars in a coordinate plane defined by the canvas.
// This is initially 300 x 300, but can be resized to anything by dragging the gray border.
function render() {
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(canvas.width / 2, canvas.height / 2);
context.scale(canvas.width / 5, canvas.height / 5);
star('red');
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(canvas.width / 4, canvas.height / 4);
context.scale(canvas.width / 5, canvas.height / 5);
star('yellow');
}
// Pop an alert indicating which star (if any) was clicked on.
// NOTE: The logic MUST work consistently no matter how the canvas is resized.
canvas.addEventListener('click', function (event) {
event.stopImmediatePropagation();
// HELP ME !!!
// HELP ME !!!
// HELP ME !!!
// HELP ME !!!
});
// IGNORE: It allows the canvas to resized by dragging on it.
draggable.addEventListener('mousedown', function handleMouseDown(mousedown) {
document.addEventListener('mouseup', function handleMouseUp(mouseup) {
var currWidth = Number(canvas.getAttribute('width'));
var deltaWidth = mouseup.clientX - mousedown.clientX;
var currHeight = Number(canvas.getAttribute('height'));
var deltaHeight = mouseup.clientY - mousedown.clientY;
canvas.setAttribute('width', currWidth + deltaWidth);
canvas.setAttribute('height', currHeight + deltaHeight);
document.removeEventListener('mouseup', handleMouseUp);
render();
});
});
render();
Answered my own question: https://jsfiddle.net/bbz5s183/4/
JAVASCRIPT FOLLOWS
// Draw a scene of stars in a coordinate plane defined by the canvas.
// This is initially 300 x 300, but can be resized to anything by dragging the gray border.
function render() {
bounds = [];
/* RENDER RED ACTOR - BOUNDING BOX */
var red = {
name: 'red',
// Translate to 25% right, 25% down on canvas.
x: 0.25 * canvas.width,
y: 0.25 * canvas.height,
// Scale to fill 20% of canvas.
width: 0.2 * canvas.width,
height: 0.2 * canvas.height
};
context.setTransform(1, 0, 0, 1, 0, 0);
box('red', red);
bounds.push(red);
/* RENDER RED ACTOR - MODEL */
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(red.x, red.y);
context.scale(red.width, red.height);
star('red');
/* RENDER YELLOW ACTOR - BOUNDING BOX */
var yellow = {
name: 'yellow',
// Translate to 50% right, 50% down on canvas.
x: 0.50 * canvas.width,
y: 0.50 * canvas.height,
// Scale to fill 20% of canvas.
width: 0.2 * canvas.width,
height: 0.2 * canvas.height
};
context.setTransform(1, 0, 0, 1, 0, 0);
box('yellow', yellow);
bounds.push(yellow);
/* RENDER YELLOW ACTOR - MODEL */
context.setTransform(1, 0, 0, 1, 0, 0);
context.translate(yellow.x, yellow.y);
context.scale(yellow.width, yellow.height);
star('yellow');
}
// Pop an alert indicating which star (if any) was clicked on.
// NOTE: The logic MUST work consistently no matter how the canvas is resized.
canvas.addEventListener('click', function (event) {
var x = event.pageX - event.target.offsetLeft;
var y = event.pageY - event.target.offsetTop;
for (var i = 0; i < bounds.length; i++) {
if (boxIntersection(bounds[i], x, y)) {
alert(bounds[i].name);
};
}
event.stopImmediatePropagation();
return false;
});

Resources