How am I able to prevent jQuery from using scientific notation - 1.2e+07 instead of 12,000,000 within the jQuery.animate() function?
Using: $('body').css({ backgroundPositionX: 12000000 + 'px' });
Converts to: background-position-x: 1.2e+07px;
Desired results: background-position-x: 12000000px;
This starts occuring as soon as the number hits 1 million (1,000,000):
This, in turn, causes my application to behave strangely. I want pure, simple integer numbers -- none of this scientific nonsense! I've looked around but I cannot find anything related to the jQuery library. Only pure JS functions.
Note 1: It's not just animate, but $.css() as well. I assume other jQuery functions are similar also.
Note 2: I don't think it's the browser that does it because if I enter the value in manually it works just fine until you hit the usual max 32 bit integer
Why is this a problem:
12000321 converts to: 1.20003e+07
When I then convert 1.20003e+07 back to an integer I get: 12000300
When you get to Scientific Notation, the step size is in the 100s & not 1s and not specific enough.
Thank you for considering my question
Wow... took me a long time but I finally managed to work out a way of doing this.
After lots of testing I noticed that passing a direct string to $.attr() did not convert the numbers to the scientific notation.
I created a custom animation and manually set the style attribute as a string.
Seems to be working & going up in single digits not 100s!!
$({
x: this.x,
y: this.y
}).animate({
x: x,
y: y
}, {
easing: this.motion_type,
duration: this.duration,
step: function(now, fx) {
var current_styles = $('.area').attr('style'),
current_styles = string = current_styles.split(" ");
var x = parseFloat(current_styles[1].replace('px', '').replace(';', ''));
var y = parseFloat(current_styles[2].replace('px', '').replace(';', ''));
if ('x' === fx.prop) {
x = now;
} else if ('y' === fx.prop) {
y = now;
}
$('.area').attr({ style: 'background-position: ' + x + 'px ' + y + 'px;' });
},
complete: function() {
t.stopNow();
}
});
Related
I came across some code recently that was like this:
const element = document.getElementById("myId")
const rect = element.getBoundingClientRect()
const height = +-(rect.height / 1)
First of all, what is the deal with the division by 1? And second, what does +- do?
I put that logic into a Fiddle and it appears that it flips the sign of whatever is in the parentheses (from positive to negative and from negative to positive). However, if I wanted to flip a sign, why wouldn't I just do -(myvariable)?
Regarding the division by 1, it appears that the type of rect.height is already a number with floating-point precision and the divide operator is also floating-point division so we're not trying to generate an int or anything.
I just need some help trying to understand what that's trying to do.
Edit: The code was found here: Check if element is partially in viewport
Using division / will implicitly convert both operands to numbers:
const str = "10.5"
const division = str / 1;
console.log(division);
console.log(typeof division);
Using a unary minus - will implicitly convert the operand and change its sign:
const str = "10.5";
const minusStr = -str;
console.log(minusStr);
console.log(typeof minusStr);
const negativeNum = -3;
const minusNegativeNum = -negativeNum;
console.log(minusNegativeNum);
Using a unary plus + will convert anything to a number. If supplied with a number, it leaves it as it is:
const str = "10.5";
const plusStr = +str;
console.log(plusStr);
console.log(typeof plusStr);
const negativeNum = -3;
const plusNegativeNum = +negativeNum;
console.log(plusNegativeNum);
The above is also the order of how the expression +-(rect.height / 1) would be evaluated.
So, what does +-(rect.height / 1) do? The same as -rect.height but tacks on two useless operators.
It should be noted, that none of the conversions are really needed - not because a unary minus already does it, but because the height property produces a number anyway:
const element = document.getElementById("myId")
const rect = element.getBoundingClientRect()
console.log(rect.height);
console.log(typeof rect.height);
const height = +-(rect.height / 1);
console.log(height);
#myId {
width: 400px;
height: 200px;
background: red;
}
<div id="myId"></div>
So the whole expression just gets the height and inverts its sign.
Can you provide the link where you found this code?
But from what you provided, I would agree with you. The + operator and the dividing by one wouldn't do anything. So I would say that it's a typo, bit of temporary code, or the developer having one too many drinks.
I think it´s a trap. I´m not shure but if you get numbers from document you get strings instead of numbers. this + before a number in a string (example "10") would turn it in type number.
For example
"11" + 1 = "111"
because javascript concanate this as 2 strings.
but
var a = "11"
+a makes it = 11
but the restit sadly out of context i think
Edit:
ah okay.
Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100)) < percentVisible
+-(rect.height / 1)) * 100
I think this parts makes this number to a percent value.JS don´t know percent. Everything is value / 100, but to get the right value, you should value / 1.
I've been racking my head as to trying to understand why when using Number.prototype.toLocaleString, it is multiplying my number by 100.
var num = 5;
alert(num + ' vs ' + num.toLocaleString('en-GB', { style: 'percent' }));
Reading through all the reference guides, I have not seen anything that suggests it should be.
Have I completely missed the point?
From the spec:
If the value of numberFormat.[[style]] is "percent", let x be 100 × x.
it expects a number in the range of [0, 1] which then would be formated to something between 0% and 100%
It's percent not toLocaleString that is causing this, and the reason is that the percentage is measured by numbers from 0 to 1 as 0% to 100%, so if you want 5%, use :
var num = .05;
alert(num + ' vs ' + num.toLocaleString('en-GB', { style: 'percent' }));
More # Number.prototype.toLocaleString()
As many other systems do, toLocaleString's percent style interprets 1 as 100 %.
This is a common way of expressing percentages (such as in probability theory where a 100 % probability is 1).
I need something to increment string values representing length (css margins)
the current solution is:
function incPx(a,b){
return parseInt(a) + parseInt(b) +'px';
}
incPx($(el).css('margin-left'), '10px')
but there may be a jQuery thing for that maybe? to work with other units that 'px'
With jQuery 1.6+, you can pass relative amounts to .css(), indicated by += or -=, similar to .animate():
$(el).css('margin-left', '+=10px');
Others have already suggested jQuery.css()'s relative values, but keep in mind that you can easily use parseInt to convert a string like 50px to a Number, like so:
console.log(parseInt('50px', 10));
// 50
function incPx(a, b){
a = parseInt(a, 10) || 0;
b = parseInt(b, 10) || 0;
return (a + b) +'px';
}
Don't forget to pass a radix of 10, though. More examples: Example: Using parseInt (MDN)
As of jQuery 1.6, .css() accepts relative values similar to .animate(). Relative values are a string starting with += or -= to increment or decrement the current value. For example, if an element's padding-left was 10px, .css( "padding-left", "+=15" ) would result in a total padding-left of 25px.
Source: http://api.jquery.com/css/
The other answers here, discussing the "jQuery way", are perfectly valid. However, I wanted to include a method that uses an approach similar to the one that the OP is using, which could be used with "vanilla" javascript too.
Note that the OP's code would, as it stands, work just fine -- this is basically the same thing with a little more care paid to giving defaults
function incPx (val, amt) {
var nv = parseInt(val.replace(/[^0-9]/, ''), 10);
return (
(nv ? nv : 0) + (amt || 1)
)+'px';
};
console.log(incPx('10px')); // 11px
console.log(incPx('let us hasten to the zoo, post haste!')); // 1px
console.log(incPx('10px', 10)); // 20px
console.log(incPx('10px', -2)); // 8px
Try it: http://jsfiddle.net/jxU6Q/2/
Documentation
parseInt on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt
String.replace on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/replace
Context: multi-user app (node.js) - 1 painter, n clients
Canvas size: 650x400 px (= 260,000 px)
For the canvas to be updated frequently (I'm thinking about 10 times a second), I need to keep the data size as small as possible, especially when thinking about upload rates.
The toDataURL() method returning a base64 string is fine but it contains masses of data I don't even need (23 bit per pixel). Its length is 8,088 (without the preceding MIME information), and assuming the JavaScript strings have 8-bit encoding that would be 8.1 kilobytes of data, 10 times per second.
My next try was using JS objects for the different context actions like moveTo(x, y) or lineTo(x, y), sending them to the server and have the clients receive the data in delta updates (via timestamps). However, this turned out to be even less efficient than the base64 string.
{
"timestamp": 0,
"what": {
"name": LINE_TO,
"args": {"x": x, "y": y}
}
}
It doesn't work fluently nor precisely because there are nearly 300 lineTo commands already when you swipe your brush shortly. Sometimes there's a part of the movement missing (making a line straight instead of rounded), sometimes the events aren't even recognized by the script client-side because it seems to be "overwhelmed" by the mass of events triggered already.
So I have to end up using the base64 string with its 8.1 KB. I don't want to worry about this much - but even if done asynchronously with delta updates, there will be major lags on a real server, let alone the occasional bandwidth overrun.
The only colors I am using are #000 and #FFF, so I was thinking about a 1-bit data structure with delta updates only. This would basically suffice and I wouldn't mind any "color" precision losses (it is black after all).
With most of the canvas being white, you could think of additional Huffman run-length encoding to reduce size even further, too. Like a canvas with a size of 50x2 px and a single black pixel at (26, 2) would return the following string: 75W1B74W (50 + 25 white pixels, then 1 black pixel, then 24 more white pixels)
It would even help if the canvas consisted of a 1-bit string like this:
00000000000000000000000000000000000000000000000000
00000000000000000000000001000000000000000000000000
That would help a lot already.
My first question is: How to write an algorithm to get this data efficiently?
The second is: How could I pass the pure binary canvas data to the clients (via node server)? How do I even send a 1-bit data structure to the server? Would I have to convert my bits to a hexadecimal (or more) number and re-parse?
Would it be possible to use this as a data structure?
Thanks in advance,
Harti
I need to keep the data size as small as possible
Then don't send the entire data. Send only the changes, close to what you propose yourself.
Make the framework such that every user can only do "actions" such as "draw black strokeWidth 2 from X1,Y1 to X2,Y2".
I wouldn't bother with some pure binary thing. If there's only two colors then that's easy to send as the string "1,2,x,y,x2,y2", which the other people will parse precisely the same way the local client will, and it will get drawn the same way.
I wouldn't overthink this. Get it working with simple strings before you worry about any clever encoding. It's worth trying the simple thing first. Maybe the performance will be quite good without going through a lot of trouble!
I sorted it out, finally. I used an algorithm to get the image data within a specified area (i.e. the area currently drawn on), and then paste the image data to the same coordinates.
While drawing, I keep my application informed about how big the modified area is and where it starts (stored in currentDrawingCoords).
pixels is an ImageData Array obtained by calling context.getImageData(left, top, width, height) with the stored drawing coordinates.
getDeltaUpdate is called upon onmouseup (yeah, that's the drawback of the area idea):
getDeltaUpdate = function(pixels, currentDrawingCoords) {
var image = "" +
currentDrawingCoords.left + "," + // x
currentDrawingCoords.top + "," + // y
(currentDrawingCoords.right - currentDrawingCoords.left) + "," + // width
(currentDrawingCoords.bottom - currentDrawingCoords.top) + ""; // height
var blk = 0, wht = 0, d = "|";
// http://stackoverflow.com/questions/667045/getpixel-from-html-canvas
for (var i=0, n=pixels.length; i < n; i += 4) {
if(
pixels[i] > 0 ||
pixels[i+1] > 0 ||
pixels[i+2] > 0 ||
pixels[i+3] > 0
) {
// pixel is black
if(wht > 0 || (i == 0 && wht == 0)) {
image = image + d + wht;
wht = 0;
d = ",";
}
blk++;
//console.log("Pixel " + i + " is BLACK (" + blk + "-th in a row)");
} else {
// pixel is white
if(blk > 0) {
image = image + d + blk;
blk = 0;
d = ",";
}
wht++;
//console.log("Pixel " + i + " is WHITE (" + blk + "-th in a row)");
}
}
return image;
}
image is a string with a header part (x,y,width,height|...) and a data body part (...|w,b,w,b,w,[...])
The result is a string with less characters than the base64 string has (as opposed to the 8k characters string, the delta updates have 1k-6k characters, depending on how many things have been drawn into the modification area)
That string is sent to the server, pushed to all the other clients and reverted to ImageData by using getImageData:
getImageData = function(imagestring) {
var data = imagestring.split("|");
var header = data[0].split(",");
var body = data[1].split(",");
var where = {"x": header[0], "y": header[1]};
var image = context.createImageData(header[2], header[3]); // create ImageData object (width, height)
var currentpixel = 0,
pos = 0,
until = 0,
alpha = 0,
white = true;
for(var i=0, n=body.length; i < n; i++) {
var pixelamount = parseInt(body[i]); // amount of pixels with the same color in a row
if(pixelamount > 0) {
pos = (currentpixel * 4);
until = pos + (pixelamount * 4); // exclude
if(white) alpha = 0;
else alpha = 255;
while(pos < until) {
image.data[pos] = 0;
image.data[pos+1] = 0;
image.data[pos+2] = 0;
image.data[pos+3] = alpha;
pos += 4;
}
currentpixel += pixelamount;
white = (white ? false : true);
} else {
white = false;
}
}
return {"image": image, "where": where};
}
Call context.putImageData(data.image, data.where.x, data.where.y); to put the area on top of everything there is!
As previously mentioned, this may not be the perfect suit for every kind of monochrome canvas drawing application since the modification area is only submit onmouseup. However, I can live with this trade-off because it's far less stressful for the server than all the other methods presented in the question.
I hope I was able to help the people to follow this question.
I was trying to get the top position of the element and the margin-bottom value.
that worked:
var top = -$('elem').postion().top; // lets say its -54
var margin = $('elem').css('margin-top'); // lets say its 0
Bud I need to add these up for my animate function. so top+margin but jQuery gives -540 px but it need to return -54 px.. or when its negative it just gives -54-10px when I need -64 px.
Is there someting to get this fixed? I can't come up with it and it annoys me!
My code:
var top = -$('#id1').position().top;
var margin = $('.scrollable').css('margin-top');
var combine = top+margin;
$('.animate').animate({'margin-top' : combine});
Bud i need to add these up for my animate function. so top+margin but jQuery gives 540 p
css values are strings, so since one of your operands is a string, the + is being interpreted as a concatenation operator (54 + "0" = "540"), not an addition operator. (Details) To turn them into numbers, use parseInt(str, 10), e.g.:
// I believe `top` will already be a number; check and if not, use parseInt here too,
// e.g. var top = -parseInt($('#id1').position().top, 10);
var top = -$('#id1').position().top;
// This will definitely be a string that needs parsing; note that we're assuming
// here that the margin has been given in `px` units.
var margin = parseInt($('.scrollable').css('margin-top'), 10);
// Now this + is an addition, not a concatenation
var combine = top+margin;
$('.animate').animate({'margin-top' : -combine});
It's because it returns the values as strings, and using the + operator on them concatenates. You can use parseInt to get a number from a string. It'll even work if there is a px suffix, though it will stop at that.
var top = $('elem').postion().top;
var margin = $('elem').css('margin-top');
var total = parseInt(top, 10) + parseInt(margin, 10);
Try this
var combine = parseInt(top) + parseInt(margin);