I'm trying to create a wheel of fortune type animation using jquery but for some reason the code that i am using always displays the wrong number!
here is the jsfiddle: http://jsfiddle.net/wf49mqaa/2/
click on the WHITE AREA in the wheel to see the animation and you will see a wrong number will be shown!
at the moment I only have 4 columns and 4 segments in my jquery code but in the future i am will pull the amount of segments from a database and I need this to work correctly at all times and display the correct number.
I tried everything from changing the segment = Math.ceil(((percent/100) * 4)), to segment = Math.ceil(((percent/100) * 4) -1), and also segment = Math.ceil(((percent/100) * 5)),
and it still display wrong number!
could someone please advise on this?
Thanks
Part of the Code you use I found in a Non-working demo from sitepoint., digging a bit deeper there are two different errors/ problems to solve the fortune-wheel behavior:
First: How to define the degree:
// existing code fragment (wrong)
var deg = 1500 + Math.round(Math.random() * 1500);
This would cause the wheel to stop at a totally random position, but that is not what you need. The wheel should always stop at the marker position, it should just turn around by a random number of segments.
// supposing you have a wheel with 4 segments (here the items array):
var deg = 0, /* basic degree */
spinbase = 1080, /* basic spinning of the wheel, here 3 times full turn */
items = [1,2,3,4];
// your spinning function...
spin: function () {
var min = 1,
max = 10,
rand = Math.floor(min + Math.random()*(max+1-min));
[...]
// like this you'll stop at the same position,
// but the wheel moved by a random number of segments
deg = deg + ( Math.round( 360 / items.length ) * rand) + spinbase;
[...]
}
Second: How to get the correct segment:
In short:
// where deg is the current degree, and items the array from above.
var segmentIndex = Math.ceil(
(deg - (360 * parseInt(deg / 360))) /
Math.round(360/items.length)
);
And when filling the algorithm..
// e.g. deg is (degree of each segment) * random (here 5) + 1080
// deg = 1530 (1080 + ( (360/4) * 5) )
// (1530 - (360 * parseInt( 1530 / 360))) / Math.round(360 / 4);
// (1530 - (360 * 4)) / 90;
// 90 / 90 = 1
// since we have 4 segments only and the random number is higher,
// the wheel did another full turn + 1 (from the starting number)
// so we get items[ 1 ] = (result: 2);
// due to the ceil/floor/round methods in calculation it can happen
// that you reach the extrem values segments.length or less than 0,
// to fix this:
var segmentIndex = Math.ceil(
(deg - (360 * parseInt(deg / 360))) /
Math.round(360/items.length)
);
if(target < 0 ) { target = segment.length - 1; }
if(target === segments.length ) { target = 0; }
alert( 'Winning: ' + items[target] );
Putting this together you'll get a working fortune-wheel. I allowed myself to create a new variant of the fortune wheel, which is able to handle different amounts of segments to make it easier to prove the algorithm.
Related
I have a video being used as a background of a mobile device to show a reactive animation for when the phone is rotated its works (sort of) but when the rotation requires it to loop from start to end or end to start it does not loop and I have no clue why as the value it's trying to be set as should work.
this is the function that subscribes to the gyroscope and updates the angle with some maths
this.gyroscope.watch(this.options)
.subscribe((orientation: GyroscopeOrientation) => {
// need delta time to correctly calculate angle per update
this.time.now = new Date().getTime();
this.time.delta = this.time.now - this.time.last;
if (this.videoLoaded) {
// convert radians/sec to degree/sec and times by deltaTime
const degree = 180 / Math.PI * orientation.z;
this.targetAngle -= (this.time.delta / 1000) * degree;
// lerp target angle no clipping applied
this.angle = (1 - .1) * this.angle + .1 * this.targetAngle;
// convert lerped angle into clipped 0-360
let displayAngle = this.angle % 360;
if (displayAngle < 0) { displayAngle = 360 + displayAngle; }
// convert angle to time of video round to tenths dec
this.frame = Math.round((displayAngle * this.axeVideo.duration / 360) * 10) / 10;
// set video time
this.axeVideo.currentTime = this.frame;
} else {
// clear angle as gyro spits out large values at first
this.angle = this.targetAngle = 0;
}
// update last time for deltaTime calc
this.time.last = this.time.now;
});
this is all correct maths and logically works however when testing the video is going to either edge and locking up no matter how many rotations the phone does and to "unlock" it i must rotate the phone back the same amount.
Screen Capture of issue recording is a little laggy but normally super smooth (hence why i use this solution).
It is the ion-range that has [(ngModel)] on it overriding the set time.
I have a hero character in the middle of the screen and I want to spawn zombies all around him in random positions but some distance away from him. heroDistance defines this distance.
It does not matter if they are pushed outside the boundaries of the screen when they are spawned, they all come towards him. It would not matter if this did not happen, but it just seemed easier.
At the moment the random location of the zombie is created for the x axis with random(screenWidth) and y axis random(screenHeight), and those values are fed into the spawnLocation function that depending on where they are in relation to the hero are either increased or decreased to move they away.
My code seems far too verbose, even though I have worked really hard on it. Am I missing some obvious technique to make it simpler?
const state = {
options: {
numberOfZombies: 10,
},
characters: {
hero: {
xPosition: 150,
yPosition: 150,
},
},
};
const screenWidth = 400;
const screenHeight = 400;
const random = range => Math.floor(Math.random() * range);
function createZombies(state) {
const heroDistance = 10;
const spawnLocation = (zomPos, heroPos, axisLength) => {
return zomPos > heroPos
? zomPos + axisLength / heroDistance
: zomPos - axisLength / heroDistance;
};
for (let index = 0; index < state.options.numberOfZombies; index += 1) {
console.log({
xPosition: spawnLocation(
random(screenWidth),
state.characters.hero.xPosition,
screenWidth,
),
yPosition: spawnLocation(
random(screenHeight),
state.characters.hero.yPosition,
screenHeight,
),
});
}
}
createZombies(state);
Generate a random angle and radius, and then transform these values into Cartesian coordinates.
let theta = Math.random() * (2 * Math.PI)
let r = Math.random() * variationInR + minimumR
let zombieX = Math.cos(theta) * r + heroX
let zombieY = Math.sin(theta) * r + heroY
If you want these to be integers, then make them so. This generates zombies uniformly radially from the hero at least minimumR units away (Pythagorean distance). If you want to maintain the Manhattan distance behavior, then generate your dX and dY and add them to the hero's position.
After I saw a video from the Coding Train on youtube about fractal trees, I tried to build one myself. Which worked great and I played with some variables to get different results.
I would love to see the tree moving like it got hit by some wind. I tried different approaches like rotating the branches a little bit or some minor physics implementations but that failed miserably.
So my question is: What would be the best approach to render a fractal tree and give it some sort of "life" like little shakes from wind.
Is there some sort of good reference ?
Do I need physics ? -> If so where do I have to look ?
If not -> How could I fake such an effect?
I am glad about every help I can get.
Source for the idea: https://www.youtube.com/watch?v=0jjeOYMjmDU
Tree in the wind.
The following are some short points re bending a branch in the wind. As the whole solution is complex you will have to get what you can from the code.
The code includes a seeded random number functions. A random recursive tree renderer, a poor quality random wind generator, all drawn on canvas using an animation loop.
Wind
To apply wind you need to add a bending force to each branch that is proportional to the angle of the branch to the wind.
So if you have a branch in direction dir and a wind in the direct wDir the amount of scaling the bending force needs is
var x = Math.cos(dir); // get normalize vector for the branch
var y = Math.sin(dir);
var wx = Math.cos(wDir); // get normalize vector for the wind
var wy = Math.sin(wDir);
var forceScale = x * wy - y * wx;
The length of the branch also effects the amount of force to include that you lengthen the vector of the branch to be proportional to its length
var x = Math.cos(dir) * length; // get normalize vector for the branch
var y = Math.sin(dir) * length;
var wx = Math.cos(wDir); // get normalize vector for the wind
var wy = Math.sin(wDir);
var forceScale = x * wy - y * wx;
Using this method ensures that the branches do not bend into the wind.
There is also the thickness of the branch, this is a polynomial relationship related to the cross sectional area. This is unknown so is scaled to the max thickness of the tree (an approximation that assumes the tree base can not bend, but the end branches can bend a lot.)
Then the elastic force of the bent branch will have a force that moves the branch back to its normal position. This acts like a spring and is very much the same as the wind force. As the computational and memory load would start to overwhelm the CPU we can cheat and use the wind to also recoil with a little bit of springiness.
And the tree.
The tree needs to be random, yet being fractal you don't want to store each branch. So you will also need a seeded random generator that can be reset at the start of each rendering pass. The tree is rendered randomly with each iteration but because the random numbers start at the same seed each time you get the same tree.
The example
Draws random tree and wind in gusts. Wind is random so tree may not move right away.
Click tree image to reseed the random seed value for the tree.
I did not watch the video, but these things are quite standard so the recursive function should not be to far removed from what you may have. I did see the youTube cover image and it looked like the tree had no randomness. To remove randomness set the leng, ang, width min, max to be the same. eg angMin = angMax = 0.4; will remove random branch angles.
The wind strength will max out to cyclone strength (hurricane for those in the US) to see the max effect.
There are a zillion magic numbers the most important are as constants with comments.
const ctx = canvas.getContext("2d");
// click function to reseed random tree
canvas.addEventListener("click",()=> {
treeSeed = Math.random() * 10000 | 0;
treeGrow = 0.1; // regrow tree
});
/* Seeded random functions
randSeed(int) int is a seed value
randSI() random integer 0 or 1
randSI(max) random integer from 0 <= random < max
randSI(min, max) random integer from min <= random < max
randS() like Math.random
randS(max) random float 0 <= random < max
randS(min, max) random float min <= random < max
*/
const seededRandom = (() => {
var seed = 1;
return { max : 2576436549074795, reseed (s) { seed = s }, random () { return seed = ((8765432352450986 * seed) + 8507698654323524) % this.max }}
})();
const randSeed = (seed) => seededRandom.reseed(seed|0);
const randSI = (min = 2, max = min + (min = 0)) => (seededRandom.random() % (max - min)) + min;
const randS = (min = 1, max = min + (min = 0)) => (seededRandom.random() / seededRandom.max) * (max - min) + min;
/* TREE CONSTANTS all angles in radians and lengths/widths are in pixels */
const angMin = 0.01; // branching angle min and max
const angMax= 0.6;
const lengMin = 0.8; // length reduction per branch min and max
const lengMax = 0.9;
const widthMin = 0.6; // width reduction per branch min max
const widthMax = 0.8;
const trunkMin = 6; // trunk base width ,min and max
const trunkMax = 10;
const maxBranches = 200; // max number of branches
const windX = -1; // wind direction vector
const windY = 0;
const bendability = 8; // greater than 1. The bigger this number the more the thin branches will bend first
// the canvas height you are scaling up or down to a different sized canvas
const windStrength = 0.01 * bendability * ((200 ** 2) / (canvas.height ** 2)); // wind strength
// The wind is used to simulate branch spring back the following
// two number control that. Note that the sum on the two following should
// be below 1 or the function will oscillate out of control
const windBendRectSpeed = 0.01; // how fast the tree reacts to the wing
const windBranchSpring = 0.98; // the amount and speed of the branch spring back
const gustProbability = 1/100; // how often there is a gust of wind
// Values trying to have a gusty wind effect
var windCycle = 0;
var windCycleGust = 0;
var windCycleGustTime = 0;
var currentWind = 0;
var windFollow = 0;
var windActual = 0;
// The seed value for the tree
var treeSeed = Math.random() * 10000 | 0;
// Vars to build tree with
var branchCount = 0;
var maxTrunk = 0;
var treeGrow = 0.01; // this value should not be zero
// Starts a new tree
function drawTree(seed) {
branchCount = 0;
treeGrow += 0.02;
randSeed(seed);
maxTrunk = randSI(trunkMin, trunkMax);
drawBranch(canvas.width / 2, canvas.height, -Math.PI / 2, canvas.height / 5, maxTrunk);
}
// Recusive tree
function drawBranch(x, y, dir, leng, width) {
branchCount ++;
const treeGrowVal = (treeGrow > 1 ? 1 : treeGrow < 0.1 ? 0.1 : treeGrow) ** 2 ;
// get wind bending force and turn branch direction
const xx = Math.cos(dir) * leng * treeGrowVal;
const yy = Math.sin(dir) * leng * treeGrowVal;
const windSideWayForce = windX * yy - windY * xx;
// change direction by addition based on the wind and scale to
// (windStrength * windActual) the wind force
// ((1 - width / maxTrunk) ** bendability) the amount of bending due to branch thickness
// windSideWayForce the force depending on the branch angle to the wind
dir += (windStrength * windActual) * ((1 - width / maxTrunk) ** bendability) * windSideWayForce;
// draw the branch
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(x, y);
x += Math.cos(dir) * leng * treeGrowVal;
y += Math.sin(dir) * leng * treeGrowVal;
ctx.lineTo(x, y);
ctx.stroke();
// if not to thing, not to short and not to many
if (branchCount < maxBranches && leng > 5 && width > 1) {
// to stop recusive bias (due to branch count limit)
// random select direction of first recusive bend
const rDir = randSI() ? -1 : 1;
treeGrow -= 0.2;
drawBranch(
x,y,
dir + randS(angMin, angMax) * rDir,
leng * randS(lengMin, lengMax),
width * randS(widthMin, widthMax)
);
// bend next branch the other way
drawBranch(
x,y,
dir + randS(angMin, angMax) * -rDir,
leng * randS(lengMin, lengMax),
width * randS(widthMin, widthMax)
);
treeGrow += 0.2;
}
}
// Dont ask this is a quick try at wind gusts
// Wind needs a spacial component this sim does not include that.
function updateWind() {
if (Math.random() < gustProbability) {
windCycleGustTime = (Math.random() * 10 + 1) | 0;
}
if (windCycleGustTime > 0) {
windCycleGustTime --;
windCycleGust += windCycleGustTime/20
} else {
windCycleGust *= 0.99;
}
windCycle += windCycleGust;
currentWind = (Math.sin(windCycle/40) * 0.6 + 0.4) ** 2;
currentWind = currentWind < 0 ? 0 : currentWind;
windFollow += (currentWind - windActual) * windBendRectSpeed;
windFollow *= windBranchSpring ;
windActual += windFollow;
}
requestAnimationFrame(update);
function update() {
ctx.clearRect(0,0,canvas.width,canvas.height);
updateWind();
drawTree(treeSeed);
requestAnimationFrame(update);
}
body {
font-family : arial;
}
<canvas id="canvas" width="250" heigth="200"></canvas>
Click tree to reseed.
Update
I just noticed that the wind and branch length are absolute thus drawing the tree on a larger canvas will create a bending force too great and the branches will bend past the wind vector.
To scale the sim up either do it via a global scale transform, or reduce the windStrength constant to some smaller value. You will have to play with the value as its a 2nd order polynomial relation. My guess is multiply it with (200 ** 2) / (canvas.height ** 2) where the 200 is the size of the example canvas and the canvas.height is the new canvas size.
I have added the calculations to the example, but its not perfect so when you scale you will have to change the value windStrength (the first number) down or up if the bending is too far or not enough.
I'm trying to get an object that moves in a different direction when you click on it, and each time you click on it it goes faster. I have it almost functioning, but I can't get the program to exclude 0 or do only -1 or 1; I can only do a random number between -1 and 1. This means that if it hits zero, it can't progress.
(The following code is built with a Javascript engine called "Crafty". Non-javascript parts are commented as best as I can.)
Crafty.init(400,320, document.getElementById('game')); // Creates canvas
// Create variables
var speed = 10;
var min = -1;
var max = 1;
// Create a 32px by 32px red box
var square = Crafty.e('2D, Canvas, Color, Mouse, Motion')
.attr({x: 50, y: 50, w: 32, h: 32})
.color('red')
// When the red box is clicked, move it in a random direction. Make it go faster each time.
.bind('Click', function(MouseEvent){
speed *= 2;
var vel = square.velocity();
var direction = ((Math.random() * (max - min)) + min);
vel.x;
vel.y;
vel.x = (speed *= direction);
vel.y = (speed *= direction);
});
Change to this line
var direction = (Math.random()) > .5 ? 1 : -1;
It really comes down to this line:
var direction = ((Math.random() * (max - min)) + min);
If you store the acceptable values (-1 and 1) in an array, you can make the random choose one of those based on the length of the array. By storing the values in an array, you not only make the process simpler, but it is extensible because you can always add new values later, if desired.
function getRandom(){
var acceptable = [-1, 1];
// Get a random number from 0 to 1 (the length of the array, 2, will never be reached)
var direction = Math.floor(Math.random() * acceptable.length);
console.log(acceptable[direction]); // Choose either array element 0 or element 1
}
// Run this code snippet a few times and you'll see that you only get -1 and 1
getRandom();
getRandom();
getRandom();
getRandom();
You can also remove the two lines declaring the max and min variables as they are no longer needed.
My plan is to give a slight tint to a web page based on the current local time (from javascript). I don't need something as specific as current lumens or anything, but I'd like to get the approximate time for peak sunlight, sunrise, sunset, and mid-night +-2 hours or so. I realize the exact times would vary greatly based on latitude & longitude and also timezone data, which I could potentially have access to. But to start off, I was wondering if there were just a formula for something like [northern] hemisphere and current local time.
How does f.lux do it?
Update 1: Most of my searches have just returned daylight savings related info, which isn't very helpful. I did find this JS: http://www.esrl.noaa.gov/gmd/grad/solcalc/main.js (from here http://www.esrl.noaa.gov/gmd/grad/solcalc/) but it is laden with unexplained magic constants. For example:
function calcGeomMeanLongSun(t)
{
var L0 = 280.46646 + t * (36000.76983 + t*(0.0003032))
while(L0 > 360.0)
{
L0 -= 360.0
}
while(L0 < 0.0)
{
L0 += 360.0
}
return L0 // in degrees
}
function calcGeomMeanAnomalySun(t)
{
var M = 357.52911 + t * (35999.05029 - 0.0001537 * t);
return M; // in degrees
}
function calcEccentricityEarthOrbit(t)
{
var e = 0.016708634 - t * (0.000042037 + 0.0000001267 * t);
return e; // unitless
}
Update 2: I think the "cost" of determining a locale of the user via gps or whatever is too great (especially since this is purely for cosmetic reasons and serves no other functional purpose), so I'm probably just going to stick with the 12am-6am-12pm-6pm cycle of whatever the local time is via javascript.
Update 3: I just went with a slightly modified sine-wave with a small preference towards day-time:
var x, fx, hour,
// starting hsl value for midnight:
h = 220,
s = 42,
l = 75;
for (hour = 0; hour < 24; hour++) {
// 0 for midnight, up to 12 for noon
x = 12 - Math.abs(hour - 12);
// 0.0 to 1.0
fx = x / 12;
// factor of pi, shift x axis by 1 half pi
fx = (Math.PI * (fx - (1 / 2)));
// sine function
fx = Math.sin(fx);
// +1 to start at 0, take half to max out at one
fx = (fx + 1) / 2;
// skew the values just slightly for daytime
fx = Math.pow(fx, 0.75);
// change range back to top out at 12
fx = fx * 12;
// base of 220 degrees, 18.25 provided a nice color rage from bluish to yellowish
h = Math.floor((220 + (18.25 * fx)));
// rotate on 360 degrees
while (h >= 360) {
h = h - 360;
}
// base of 42% saturated, multiplied x for a linear slope up to 100%
s = Math.floor(42 + (5.5 * x));
// 100 max
if (s > 100) {
s = 100;
}
// base of 75% lightness, 1.85 factor was a nice linear slope stopping short of 100%
l = Math.floor(75 + (1.85 * x));
// 100 max
if (l > 100) {
l = 100;
}
// "style='background-color: hsl(" + h + ", " + s + "%, " + l + "%);'"
}
Here it is on JSBin. I may play around with getting the actual amount in the future, but this gets me close enough for now.
Is not this equation from Wikipedia enough:
http://en.wikipedia.org/wiki/Sunrise_equation
There is no magic in it, just a bit of math.
Or do you need something more?