How do I calculate logrithmic labels for a VU meter scale? - javascript

I writing a meter widget using canvas and need to calculate the label values for the scale. No problem except when I'm trying to re-create the scale for a VU meter. I understand it's logrithmic, but the values aren't powers of 10 on that type of meter.
see: https://en.wikipedia.org/wiki/VU_meter
The function I have is given the min and max values for the scale. For normal scales, it also is given the step between values. For example, given -20 and 30 with a step of 10, it would produce labels:
-20 -10 0 10 20 30
For a VU meter given -20 and 6, I need to produce labels:
-20 -10 -5 -3 0 3 6
And, the spacing isn't the same on the scale between those values.
I am not asking for actual code examples, but instead for ideas on how to best approach implementing this.
Should I write the function so one of the parameters is a list of labels, then plot them on a logarithmic scale? That doesn't appear to work properly because the numbers do not end up in the right places as seen in the image above of a proper VU meter.
Is there some special formula just for dB levels that isn't a simple log function?
Again, I'm not asking for code examples, just for some help understanding the best approach to use.
Thanks!

I suppose you have a value-to pixel function. What you need to write is the inverse function of that.
When you have the inverse function, you just divide the screen area to N equal parts (in the picture you have 6 regions). One region will be X pixels in width. Now you can use your inverse function to get the value for that pixel-position.
This will not be an integer, it will be something like 3.434 or 11.34 - you need a prettyfier function which will generate the closest "pretty" number (let's say just chop off the parts after the decimal).
Now you take the pretty value and calculate the pixel position for it with your original function.
Some code:
function value2px(value, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin);
var pixelWidth = pxMax - pxMin;
var ratio = pixelWidth / valueWidth;
return ratio * (sigLog(value) - sigLog(valueMin)) + pxMin;
}
function px2value(px, valueMin, valueMax, pxMin, pxMax) {
var valueWidth = sigLog(valueMax) - sigLog(valueMin);
var pixelWidth = pxMax - pxMin;
var ratio = pixelWidth / valueWidth;
return sigExp((px - pxMin) / ratio + sigLog(valueMin));
}
and the demo:
http://jsfiddle.net/ambcwoLg/1/

Related

Bubble chart c3js

Following the c3js documentation there is no option for Bubble chart. One workaround for that is to setup scatter plot and specify point radius, but all of the bubbles will be the same height.
point = {
r: function(d) {
var num = d.value;
return num
},
Adding the value of axis inside the r solve the problem, but now the problem is how to setup very high or very low values ? For e.g if there is 1 000 000 value the whole chart will be colored. Is there any simple workarounds for that ?
First of all, set r to return the square root of your chosen variable e.g. return sqrt(num), that way a circle representing a data point 100 times the size of another has 100, not 10,000, times the area (area=pi r2 and all that)
If the numbers are still too big use a linear scale to restrict them to a usable size:
rscale = d3.scale.linear().domain([1,1000]).range([0,10])
and then return rscale(sqrt(num))
If your problem is to represent large and small values on the same chart so small values don't disappear and large values don't exceed the chart size look at using a d3 log scale:
rscale = d3.scale.log().base(10).domain([1,1000]).range([0,10])
Of course on a log scale the areas aren't linearly proportionate any more so whether the sqrt step is necessary is debatable. If you don't just remember to adjust the domain to account for this - change it to domain([1,1000000])
if you don't know the size of your numbers beforehand it will be worthwhile looping through your dataset to pick out the min and max to plug into the domain value: domain([your_min, your_max]). my examples above all assume a max of one million.
Here's an example I forked on jsfiddle, numbers from a few hundred to over a hundred thousand are displayed using a log scale and all are visible but the differences are still obvious:
http://jsfiddle.net/m9gcno5n/

How to plot this type of "binary matrix" graphic (I honestly don't know if it has a name) using PHP and HTML

I'm trying to plot this type of "binary matrix" graphic:
Disregard the two colors from the sample image; I want to either color a dot blue for, let's say, "complete" values or leave it uncolored/gray for "incomplete" values as a way to track daily task completion for a certain amount of dots/days. The dots represent a day where a task was completed or not completed. Showing the full amount of dots/days gives perspective on % of completion as days go by.
I would like to use a combination of HTML/Javascript and PHP + MySQL. But the hardest part for me is figuring out a good algorithm to render this visualization. Thanks for your help.
Just treat each dot like it's a pixel. Also, imagine that the image has been rotated 90° CCW. Then, you simply draw a square that takes up less room that is allocated to it - this way, you get the separating lines.
Here'e a quick something to have a play with.
A few notes:
0) I just halved your image dimensions
1) 4 pixels and 5 pixels were chosen arbitrarily
2) I didn't bother with setting the colour of the dot - you can
easily do this.
3) I've simply treated the drawing area like a normal top-bottom
bitmap, while your image seems to show that all of the Y values will
be used before the next X value is needed. (This is like a 90° CCW
rotation).
4) I'm addressing the pixels with an X and a Y - perhaps you'd be
more interested in addressing them with a single number? If so, you
could easily write a function that would map two coords to a single
number - the pixels index, if you like.
I.e if an image is 100 x 100, there are 10,000 pixels. You could address them by specifying a number from 0 - 9,999
E.g
function 10k_to_100x100(index)
{
var x = index % 100;
var y = (index / 100).toFixed(0);
plotPixelDot(x, y);
}
X is simply the remainder when dividing by the width
Y is the whole number answer when dividing by the width
Here's a snippet you can try right here on the page:
function byId(id){return document.getElementById(id);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
var x, y;
for (y=0; y<20; y++)
{
for (x=0; x<100; x++)
{
drawDot(x, y, 'output');
}
}
}
function drawDot(xPos, yPos, canvasId)
{
var actualX=xPos*5, actualY=yPos*5;
var ctx = byId(canvasId).getContext('2d');
ctx.fillRect(actualX, actualY, 4, 4);
}
<canvas width=558 height=122 id='output'></canvas>

calculating rotate and translate position based on scroll value of window

I want to move the object in my case its a plane along the shown curve on page scroll step by step taking into consideration the amount of scroll value.firstly the object moves in straight line and then after a point it changes its direction and move in that direction.How to calculate those co-ordinates?
There are two ways you could get this one. I'll try to explain both in detail.
Scenario 1: Simple path like in the question.
Scenario 2: Arbitrary complex path.
Scenario 1:
In this case you can use a simple formula. Let's go with y = -x^2. This will yield a parabola, which has a similar shape as the path in the question. Here are the steps for what to do next (we assume your scrolling element is the body tag and I assume you have jquery):
Get the "y" value of the body using the following code:
var y = $("body").scrollTop();
Plug this value into the formula. I will give 3 examples where y is 0, 100 and 225 respectively.
//y=0
0 = -x^2
-x = sqrt(0)
x = +/- 0
So if we scroll and we are at the top of the page, then x will be zero.
//y=100
100 = -x^2
-x = sqrt(100)
x = +/- 10
The equation yieldsx as either positive of negative x but we only want positive so be sure to Math.abs() the result.
//y=225
225= -x^2
-x = sqrt(225)
x = +/- 15
From this you can see that the further we scroll down the more the object moves to the right.
Now set the "left" css of your object to the calculated value. This should be enough for this method.
Scenario 2
For more complex paths (or even random paths) you should rather put the x-values into an array ahead of time. Lets say you generate the array randomly and you end up with the following x-values:
var xvals = [0, 0.5, 1, 0.5, 0];
We use normalized x-values so that we can later calculate the position independent from screen size. This particular series of values will cause the object to zig-zag across the screen from left to right, then back to left.
The next step is to determine where our scroll position is at relative to the total scroll possibility. Lets say our page is 1000px in height. So if the scoll position is at zero then x = 0. If scroll = 500 then x = screenWidth. If scroll = 250 then x = 0.5 * screenWidth etc.
In the example I won't multiply with screen width for the sake of simplicity. But given the x value this should be simple.
The first thing you might want to get ready now is a lerping function. There is plenty of example code and so on so I trust that part to you. Basically it is a function that looks like this:
function lerp(from, to, prog);
Where from and to are any values imaginable and prog is a value between 0 and 1. If from is 100 and to is 200, a prog value of 0.5 will yield a return of 150.
So from here we proceed:
Get the scroll value as a normalized value
// scrollval = 200
var totalScroll = 1000;
var normScroll = scrollval/totalScroll; // answer is 0.2
Before we get to lerp we first need to get the x-values to lerp from and to. To do this we have to do a sort of lerping to get the correct index for the xvals array:
// normScroll = 0.2
var len = xvals.length; // 5
var indexMax = Math.ceil((len-1) * normScroll); // index = 1
var indexMin = Math.floor((len-1) * normScroll); // index = 0
Now we know the 2 x values to lerp between. They are xvals[0] which is 0, and xvals[1] which is 0.5;
But this is still not enough information. We also need the exact lerping "prog" value:
// We continue from the x indeces
scrollRange.x = totalScroll / len * indexMin; // 0
scrollRange.y = totalScroll / len * indexMax; // 250
var lerpingvalue = (scrollVal - scrollRange.x) / (scrollRange.y - scrollRange.x);// 0.8
Now we finally have everything we need. Now we know we need a value between xvals[0] and xvals[1] and that this value lies at 80% between these two values.
So finally we lerp:
var finalX = lerp(xvals[0], xvals[1], lerpingvalue);// 0.4
Now we know that the x coordinate is at 0.4 of the total screen size.
Trigger these calculations on each scroll event and you should be on your way.
I hope this was clear enough. If you try and try and can't get results and can show how hard you tried then I'll be happy to write a complete index.html sample for you to work from. Good luck!
EDIT: I made a mistake with the lerpingval calculation. Fixed now.

Simple algorithm for generating random numbers with bigger/smaller probability

I'm currently working on a game, with scrollable screen and I need to find a simple algorithm for placing obstacles in the game. I have a gameSpeed, that is increased in time (from 1 to 12, increased by 0.005 each 1/60s) and a range of available positions between 200 and 600 (ints). I'd like to achieve a bigger probability of receiving smaller number when the speed is bigger, but it's my 14th hour straight coding and I cannot come up with anything usable and not overcomplicated. I'd like to minimize Math and random functions so that the rendering loop won't take too long. Any help appreciated !
You could square or square-root the random number to shift the density in one direction. Math.random()*Math.random() will have a higher probability to produce smaller numbers (near 0) than higher ones (near 1).
Your formula could be like
var position = Math.pow(Math.random(), gameSpeed / 3) * 400 + 200;
The simplest answer I can think of is to create an array having more lower numbers compared to higher ones, for example, for producing random between [1,5] (both inclusive). So your array may look like [1,1,1,1,1,2,2,2,2,3,3,3,4,4,5]
And when you randomly pick an element from that array you will have a higher chance of picking up low number compared to high one.
Another way might be to have two (or more) percentages:
say, start with 10% of the time we access 90% of the range, and 90% of the time we access the other 10%. Then we gradually flip those numbers as the speed increases. For example,
var lBound = 200,
uBound = 600,
range = uBound - lBound,
gameSpeed = 1,
initialMarker = 0.1,
percentageRange = 1 - 2 * initialMarker,
marker = (gameSpeed - 1) / 11 * percentageRange + initialMarker,
position
Math.random() <= marker ? position = Math.floor(Math.random() * (1 - marker) * range) + lBound
: position = uBound - Math.floor(Math.random() * marker * range)
console.log(position)
Try changing gameSpeed and see what happens. Change initialMarker for a different set of percentages (currently set at 0.1, which means 10% / 90%).

Math: I need to normalize some bar graphs

I'm generating bar graphs. The range of data generating said graphs is very wide, which means some areas of the graph are always low, and some areas go off the chart.
What's the math to "normalize" this towards a certain number (e.g. 200), so large values are shrunk the larger they are, and smaller values are increased?
If you are talking about actually changing the data for display purposes, then there are a few basic approaches to bring values closer to a target value. The simplest is to just do a weighted average with that value: A' = (1-α)*A + α*B where alpha is a weight between 0 and 1, A is a number on your graph, and B is the target value.
For instance, if you were trying to 'normalize' to 200 and your numbers were 100 120 200 220 400 then plugging in each for A, 200 for B, and .5 for alpha, you would get 150 160 200 210 300
You can choose a different alpha to adjust how much you want to stretch the data towards the target value. Higher numbers like .9 will stretch the data more and lower numbers like .1 will stretch the data less.
I dont know if you are willing to read a little but I found the the scaling tutorial for d3.js framework (http://d3js.org/) is a very solid introduction to the scaling part of visualisation:
http://alignedleft.com/tutorials/d3/scales/
For a zero-based graph : compute the max of your value, then display for each bar :
barHeight[i] = (maxBarHeight*value[i])/maxVal;
If you want your graph to be based on the minimum value and not zero, you might still want the
graph to have a non-zero height for the bar near the min value. So compute the minimum value, and display :
barHeight[i] = minBarHeight +
(maxBarHeight - minBarHeight ) * (value[i] - minVal) / ( maxVal - minVal );
( Rq : if minVal is Zero or 'near' zero, set minVal = minBarHeigth = 0 and you have the first case )

Categories