HTML5 Canvas : Spawn randomly positioned objects outside of the canvas - javascript

What I am trying to learn is how to spawn objects outside of the canvas from various directions...that is left, right, top, bottom.
For (i = 0; i < 10; i++) {
ctx.beginPath();
ctx.arc(Math.random()*Window.outerWidth, Math.random()*Window.outerHeight 30, 0, 2 * Math.PI, false);
ctx.fillStyle = 'black';
ctx.fill();
ctx.closePath();
}
So basically imagine objects appearing from some random positions at the top, left, right and botton edges of the canvas screen. Maybe even the corners. So the point is im having some issues with understanding the logic behind how this works. How do I achieve something like that?
Please bear in mind that I am not just looking for answers but a resource for learning. If you answer then please do so with teaching in mind and not 'points'.

This Math.random() * Window.outerWidth is fast write of :
var min = 0, max = Window.outerWidth;
Math.random() * (max - min + 1) + min;
To understand it, look this function :
function getRandom(min, max) { //You get number between [min, max]
return Math.floor(Math.random() * (max - min + 1)) + min;
}
If you want to add circle inside canvas, you need to set :
var min = 0,
max = Window.outerWidth;
Your code remove min variable. You get :
Math.random() * (max - 0) + 0; // replace min by 0
Math.random() * max // remove 0
Math.random() * Window.outerWidth // max = Window.outerWidth
You get : Math.random() * Window.outerWidth.
Links :
Generating random whole numbers in JavaScript in a specific range?

Related

Chaos Game fractal not rendering correctly

I'm attempting to write code that will generate fractals according to the Chaos game
In particular, I'm trying to debug the faulty generation/rendering of this fractal:
I'm doing this with Javascript in a Canvas element. The relevant Javascript is below:
canvas = document.getElementById('myCanvas');
context = canvas.getContext('2d');
//constants
border = 10 //cardinal distance between vertices and nearest edge(s)
class Point{
constructor(_x, _y){
this.x = _x;
this.y = _y;
}
}
vertices = []
secondLastVertex = 0;
lastVertex = 0;
//vertices in clockwise order (for ease of checking adjacency)
vertices.push(new Point(canvas.width / 2, border)); //top
vertices.push(new Point(canvas.width - border, canvas.height * Math.tan(36 * Math.PI / 180) / 2)); //upper right
vertices.push(new Point(canvas.width * Math.cos(36 * Math.PI / 180), canvas.height - border)); //lower right
vertices.push(new Point(canvas.width * (1 - (Math.cos(36 * Math.PI / 180))), canvas.height - border)); //lower left
vertices.push(new Point(border, canvas.height * Math.tan(36 * Math.PI / 180) / 2)); //upper left
//move half distance towards random vertex but it can't neighbor the last one IF the last two were the same
function updatePoint(){
//pick a random vertex
v = Math.floor(Math.random() * vertices.length);
if(lastVertex == secondLastVertex)
//while randomly selected vertex is adjacent to the last approached vertex
while((v == (lastVertex - 1) % 5) || (v == (lastVertex + 1) % 5))
//pick another random vertex
v = Math.floor(Math.random() * vertices.length);
//cycle the last two vertices
secondLastVertex = lastVertex;
lastVertex = v;
//move half way towards the chosen vertex
point.x = (vertices[v].x + point.x) / 2;
point.y = (vertices[v].y + point.y) / 2;
}
//starting point (doesn't matter where)
point = new Point(canvas.width / 2, canvas.height / 2);
for (var i = 0; i < 1000000; i++){
//get point's next location
updatePoint();
//draw the point
context.fillRect(Math.round(point.x), Math.round(point.y), 1, 1);
}
The rendering that is produced looks like this:
So far I haven't been able to determine what is causing the rendering to be so skewed and wrong. One possibility is that I've misunderstood the rules that generate this fractal (i.e. "move half the distance from the current position towards a random vertex that is not adjacent to the last vertex IF the last two vertices were the same")
Another is that I have some bug in how I'm drawing fractals. But the same code with rule/starting-vertex modifications is able to draw things like the Sierpinkski triangle/carpet and even other pentagonal fractals apparently perfectly. Though one other pentagonal fractal ended up with some weird skewing and "lower right fourth of each self-similar substructure" weirdness.
I tried making some slight modifications to how I interpreted the rules (e.g. "next vertex can't be adjacent OR EQUAL TO previous vertex if last two vertices were the same") but nothing like that helped. I also tried not rounding the coordinates of the target point before plotting it, but though this slightly changed the character/sharpness of the details, it didn't change any larger scale features of the plot.
My issue as kindly pointed out by ggorlen, was that I wasn't comparing vertices for adjacency correctly. I mistakenly thought Javascript evaluated something like (-1 % 5) as 4, rather than -1.
To fix this, I add 4 to the index instead of subtracting 1, before modding it against 5 (the number of vertices)
This completely fixed the render. (in not just this case but other cases I'd been testing with different fractals)

Why does my css-animation extend beyond the window?

I have made a CSS-animation with Velocity.js:
https://codepen.io/blaustern_fotografie/pen/GvxWoW
The code is designed such that the circles are not allowed to go beyond the window on the left and right side. The function "my_animate" is responsible for this:
function my_animate(circle) {
var new_y = Math.floor(
Math.random() * ((height -50)-50)+50
);
var new_x = Math.floor(
Math.random() * ((width-50)-50)+50
);
var r = Math.random();
//var nd = Math.floor(r * 500 - 250);
$(circle).velocity(
{
translateX: new_x-$(circle).position().left,
translateY: new_y-$(circle).position().top,
//translateZ: nd,
opacity: r,
blur: Math.round((1 - r) * 5)
},
{
duration: Math.round(Math.random() * 10000 + 10000),
complete: function() {
my_animate(circle);
}
}
);
}
Does anyone know why the circles are passing the edges?
Problem seems here in calculating the new position.
The use of Math.random() is leading to random values being generated for new_x.
var new_x = Math.floor(
Math.random() * ((width -50)-50)+50
);
Then new_x-$(circle).position().left is leading to values being generated which are out of window range.
You should normalise your randomiser to generate new position such that the values generated are always between the min and max points on the viewport.
You need to make the Math.random in range of your window.width, otherwise the randomizer will just calculate values out of your window.width.

dda algorithm - raycasting

I started a project using the raycasting technique GitHub Project
To find the length of the ray (distance from players pos to wall) I just increment by one. But there are several problems with that, its time consuming, inaccurate & will be difficult for texturing.
I tried to implement the daa algorithm, which doesnt just increments by 1 -> he goes through the grids and returns exact positions.
http://www.geeksforgeeks.org/dda-line-generation-algorithm-computer-graphics/
Has anyone experience with that or any tips?
No algorithm way:
for(let resolution = 0; resolution < display.width / 2; resolution++){ //every 2nd px gets scanned
let ray = this.pov + (-this.fov / 2 + this.fov / (display.width / 2) * resolution);
let distance = 0, hit = false;
/*ugly way of raycasting!*/
do{
let x = this.x + distance * Math.cos(ray * (Math.PI / 180));
let y = this.y + distance * Math.sin(ray * (Math.PI / 180));
if(map[Math.floor(x / block)][Math.floor(y / block)]){
distance = Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2));
hit = true
}
distance += 1;
}while(!hit);
distance = convert / distance;
canvas.fillStyle = "#fff";
canvas.fillRect(resolution * 2, display.height / 2 - distance / 2, 2, distance);
}
You don't need DDA or Bresenham algorithm to find intersections of the ray with walls.
If you need one intersection with given border (or box edges) - just calculate it with ray equation and border position.
If you want to get intersections with grid cells - use voxelization algorithm like Amanatides-Woo

Auto adjust brightness/contrast to read text from images

I was wondering if anyone can point me in the right direction to auto adjust brightness/contrast of an image taken from phone camera using javascript to make reading of text from the image easier.
Appreciate any help,
Many thanks.
To automatically adjust an image we could use a histogram that we generate from the image, and then use a threshold to find a black/white point to use to scale the pixel values to their max in opposite ends.
In HTML5 we would need to use the canvas element in order to read pixel information.
#Building a histogram
A histogram is an overview of which values are most represented in an image. For brightness-contrast we would be interested in the luma value (the perceived lightness of a pixel).
Example luma histogram
To calculate a luma value we can use REC.709 (AKA BT.709, recommended, used here) or REC.601 formulas.
Y = 0.299 * R + 0.587 * G + 0.114 * B
We need to convert this to an integer (iluma = Math.round(luma);), otherwise we would get a hard time building the histogram which is based on integer values [0, 255] for storage (see example code below).
The strategy to determine which range to use can vary, but for simplicity we can choose a threshold strategy based on a minimum representation of pixels in both end.
Red line showing example threshold
To find the darkest based on a threshold we would scan from left to right and when we get a luma value above threshold use that as minimum value. If we get to center (or even just 33% in) we could abort and default to 0.
For the brightest we would do the same but from right to left and defaulting to 255 if no threshold is found.
You can of course use different threshold values for each end - it's all a game of trial-and-error with the values until you find something that suits your scenario.
We should now have two values representing the min-max range:
Min-max range based on threshold
#Scaling the general luma level
First calculate the scale factor we need to use based on the min-max range:
scale = 255 / (max - min) * 2
We will always subtract min from each component even if that means it will clip (if < 0 set the value to 0). When subtracted we scale each component value using the scale factor. The x2 at the end is to compensate for the variations between luma and actual RGB values. Play around with this value like the others (here just an arbitrary example).
We do this for each component in each pixel (0-clip and scale):
component = max(0, component - min) * scale
When the image data is put back the contrast should be max based on the given threshold.
#Tips
You don't have to use the entire image bitmap to analyze the histogram. If you deal with large image sources scale down to a small representation - you don't need much as we're after the brightest/darkest areas and not single pixels.
You can brighten and add contrast an image using blending modes with it self, such as multiply, lighten, hard-light/soft-light etc. (<= IE11 does not support blending modes). Adjust the formula for these, and just experiment.
#Example
This works on a buffer showing the techniques described above. There exist more complex and accurate methods, but this is given as a proof-of-concept (licensed under CC-3.0-by-sa, attribution required).
It starts out with a 10% threshold value. Use slider to see the difference in result using the threshold. The threshold can be calculated via other methods than the one shown here. Experiment!
Run snippet using Full page -
var ctx = c.getContext("2d"),
img = new Image; // some demo image
img.crossOrigin =""; // needed for demo
img.onload = setup;
img.src = "//i.imgur.com/VtNwHbU.jpg";
function setup() {
// set canvas size based on image
c.width = this.width;
c.height = this.height;
// draw in image to canvas
ctx.drawImage(this, 0, 0);
// keep the original for comparsion and for demo
org.src = c.toDataURL();
process(this, +tv.value);
}
function process(img, thold) { //thold = % of hist max
var width = img.width, height = img.height,
idata, data,
i, min = -1, max = -1, // to find min-max
maxH = 0, // to find scale of histogram
scale,
hgram = new Uint32Array(width); // histogram buffer (or use Float32)
// get image data
idata = ctx.getImageData(0, 0, img.width, img.height); // needed for later
data = idata.data; // the bitmap itself
// get lumas and build histogram
for(i = 0; i < data.length; i += 4) {
var luma = Math.round(rgb2luma(data, i));
hgram[luma]++; // add to the luma bar (and why we need an integer)
}
// find tallest bar so we can use that to scale threshold
for(i = 0; i < width; i++) {
if (hgram[i] > maxH) maxH = hgram[i];
}
// use that for threshold
thold *= maxH;
// find min value
for(i = 0; i < width * 0.5; i++) {
if (hgram[i] > thold) {
min = i;
break;
}
}
if (min < 0) min = 0; // not found, set to default 0
// find max value
for(i = width - 1; i > width * 0.5; i--) {
if (hgram[i] > thold) {
max = i;
break;
}
}
if (max < 0) max = 255; // not found, set to default 255
scale = 255 / (max - min) * 2; // x2 compensates (play with value)
out.innerHTML = "Min: " + min + " Max: " + max +
" Scale: " + scale.toFixed(1) + "x";
// scale all pixels
for(i = 0; i < data.length; i += 4) {
data[i ] = Math.max(0, data[i] - min) * scale;
data[i+1] = Math.max(0, data[i+1] - min) * scale;
data[i+2] = Math.max(0, data[i+2] - min) * scale;
}
ctx.putImageData(idata, 0, 0)
}
tv.oninput = function() {
v.innerHTML = (tv.value * 100).toFixed(0) + "%";
ctx.drawImage(img, 0, 0);
process(img, +tv.value)
};
function rgb2luma(px, pos) {
return px[pos] * 0.299 + px[pos+1] * 0.587 + px[pos+2] * 0.114
}
<label>Threshold:
<input id=tv type=range min=0 max=1 step= 0.01 value=0.1></label>
<span id=v>10%</span><br>
<canvas id=c></canvas><br>
<div id=out></div>
<h3>Original:</h3>
<img id=org>

Canvas jitters half my rendering

I was working on a fun project that implicates creating "imperfect" circles by drawing them with lines and animate their points to generate a pleasing effect.
The points should alternate between moving away and closer to the center of the circle, to illustrate:
I think I was able to accomplish that, the problem is when I try to render it in a canvas half the render jitters like crazy, you can see it in this demo.
You can see how it renders for me in this video. If you pay close attention the bottom right half of the render runs smoothly while the top left just..doesn't.
This is how I create the points:
for (var i = 0; i < q; i++) {
var a = toRad(aDiv * i);
var e = rand(this.e, 1);
var x = Math.cos(a) * (this.r * e) + this.x;
var y = Math.sin(a) * (this.r * e) + this.y;
this.points.push({
x: x,
y: y,
initX: x,
initY: y,
reverseX: false,
reverseY: false,
finalX: x + 5 * Math.cos(a),
finalY: y + 5 * Math.sin(a)
});
}
Each point in the imperfect circle is calculated using an angle and a random distance that it's not particularly relevant (it relies on a few parameters).
I think it's starts to mess up when I assign the final values (finalX,finalY), the animation is supposed to alternate between those and their initial values, but only half of the render accomplishes it.
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I can't figure it out, thanks in advance!
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I Think that your animation function has not care about the elapsed time. Simply the animation occurs very fast. The number of requestAnimationFrame callbacks is usually 60 times per second, So Happens just what is expected to happen.
I made some fixes in this fiddle. This animate function take care about timestamp. Also I made a gradient in the animation to alternate between their final and initial positions smoothly.
ImperfectCircle.prototype.animate = function (timestamp) {
var factor = 4;
var stepTime = 400;
for (var i = 0, l = this.points.length; i < l; i++) {
var point = this.points[i];
var direction = Math.floor(timestamp/stepTime)%2;
var stepProgress = timestamp % stepTime * 100 / stepTime;
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);
}
}
Step by Step:
based on comments
// 1. Calculates the steps as int: Math.floor(timestamp/stepTime)
// 2. Modulo to know if even step or odd step: %2
var direction = Math.floor(timestamp/stepTime)%2;
// 1. Calculates the step progress: timestamp % stepTime
// 2. Convert it to a percentage: * 100 / stepTime
var stepProgress = timestamp % stepTime * 100 / stepTime;
// if odd invert the percentage.
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
// recompute position based on step percentage
// factor is for fine adjustment.
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);

Categories

Resources