Javascript variable not showing expected value [duplicate] - javascript

This question already has answers here:
Javascript 0 in beginning of number
(3 answers)
Number with leading zero in JavaScript
(3 answers)
Closed 11 days ago.
I have a very basic page. It takes a value that's set in PHP, then I put that value in a Javascript variable to use in my script.
The idea is just to draw a circle on a canvas at this stage
Here is the code that matters
<?php
$ballposition = '2000770';
$ballx = substr($ballposition, 0, 3); //should be 200
$bally = substr($ballposition, 3, 3); //should be 077
$ballz = substr($ballposition, 6, 1); //should be 0
print($bally);
?>
<html>
<head>
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>
<canvas id="mycanvas" width="400" height="600" style="border:1px solid black;"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
var x = <?php print($ballx); ?>;
var y = <?php print($bally); ?>;
var radius = 4;
console.log(y);
var r = 255;
var g = 255;
var b = 255;
ctx.beginPath();
ctx.arc(x,y,radius,Math.PI*2,0,false);
ctx.fillStyle = "rgba(" + r + "," + g + "," + b + ",1)";
ctx.fill();
ctx.closePath();
You can see that I print the PHP variable at the top of the page, and it gives the value I expect (77) but when I then put it in the Javascript and log that value to the console, it gives something else (63).
What's weirder, is that if the number is higher than 77, things seem to work fine. But numbers 77 or below do not (I've not tried them all, but have quite a few).
I know that in this version the PHP part is not necessary, but in the full page it calls stuff from a database. I just cut that part out as the value is correctly loading in to the PHP variable.
What on earth am I missing? Do I need to do something to handle numbers correctly?

Related

Canvas fillRect() stops working after two iterations [duplicate]

This question already has answers here:
Get canvas width and height using javascript
(2 answers)
Closed 1 year ago.
I saw an interesting creative maths plotting script using the modulo of the result of powers and wanted to experiment with it, changing the modulo iteratively.
Here we're drawing a 256x256 pattern and then after an interval changing the modulo value and redrawing (for simplicity just toggling the modulo between two values in an attempt to debug the problem).
It only draws two iterations before apparently the Canvas stops updating and we get stuck on the second pattern. I thought context.clearRect() might solve it but it makes no difference. The function keeps running because I get the console.debug() output but nothing updates visually.
I have the same result in both Chrome and Safari
What am I doing wrong?
https://jsbin.com/zacoperuho/edit?html,console,output
<canvas id="container"></canvas>
<script>
container.width = 1024;
container.height = 1024;
const context = container.getContext("2d");
var modulo = 9;
function draw(){
context.clearRect(0, 0, context.width, context.height);
console.debug("modulo " + modulo)
for (let x = 0; x < 256; x++) {
for (let y = 0; y < 256; y++) {
if ((x ^ y) % modulo) {
context.fillRect(x*4, y*4, 4, 4);
}
}
}
if(modulo == 9){
modulo = 7;
} else {
modulo = 9;
}
}
draw();
setInterval(draw, 5000);
</script>
You're right, you need to clear the canvas's context and context.clearRect is the regular way to do it.
The problem are the parameters you're feeding it: context.width, context.height
The constantcontext is set to getContext("2d") thus it's an instance of
CanvasRenderingContext2D. This interface doesn't offer any properties called width or height. Instead you need to query the width & height on the Canvas element itself.
So simply change
context.clearRect(0, 0, context.width, context.height);
to
context.clearRect(0, 0, container.width, container.height);

Display value in canvas during mouseover

Dear JavaScript users,
I need to be able to:
load a png image and display it on a canvas
store its original pixel values
transform the pixel values to represent new colours
display the original values on the screen when the user moves their cursor over the image
This may sound like a slightly odd thing to do, but the original pixel values in my live system will contain encoded data that I need to retain, and display on the screen after whatever pixel value manipulation is subsequently carried out. I need to change the colour mapping after the initial loading of the image to make it more pleasing to the eye, but need to display the original values on the screen.
My method works when displaying some simple geometrical shapes on the canvas, but as soon as I try to use a png image it stops working. Can anyone help me to understand why this is?
An example (without the pixel value transformation) that works with the simple shapes is here:
http://jsfiddle.net/DV9Bw/1219/
If you comment out lines 24 - 29, and uncomment lines 32 - 40 so that it loads in a png, it stops working. The png file loads, but the data values are no longer shown on the screen.
Any suggestions as to why it breaks when I use a png would be welcome; any suggestions on how to fix it would be even more welcome!
Many thanks in advance for any help.
David
function findPos(obj) {
var curleft = 0, curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return { x: curleft, y: curtop };
}
return undefined;
}
function rgbToHex(r, g, b) {
if (r > 255 || g > 255 || b > 255)
throw "Invalid color component";
return ((r << 16) | (g << 8) | b).toString(16);
}
var example = document.getElementById('example');
var context = example.getContext('2d');
// The squares works
context.fillStyle = "rgb(255,0,0)";
context.fillRect(0, 0, 50, 50);
context.fillStyle = "rgb(0,0,255)";
context.fillRect(55, 0, 50, 50);
// End of squares
/*
// Replacing the squares section above with this
// png image stops the mouseOver from working, Why?
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height, 0, 0, imageObj.width*4, imageObj.height*4);
};
imageObj.src = 'http://dplatten.co.uk/mouseOver/skin_dose_map.png';
*/
var originalValues = new Array();
originalValues = context.getImageData(0,0,280,360).data;
$('#example').mousemove(function(e) {
var pos = findPos(this);
var x = e.pageX - pos.x;
var y = e.pageY - pos.y;
var coord = "x=" + x + ", y=" + y;
var c = this.getContext('2d');
var r = originalValues[(y*280 + x)*4];
var g = originalValues[(y*280 + x)*4+1];
var b = originalValues[(y*280 + x)*4+2];
$('#status').html(coord + "<br>" + r + "," + g + "," + b);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="example" width="280" height="360"></canvas>
<div id="status"></div>
The problem is two-fold
First of all, these two line:
var originalValues = new Array();
originalValues = context.getImageData(0,0,280,360).data;
are being run before you paint the image since it's waiting for the image to load still.
Then, if would move the context.getImageData() to inside the imgObject.onload-function, you'd run into another problem namely, you can't run getImageData() on an image that is not on the same location as the file that is running the script. You will get the following message:
Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
If you put the image on the same server and move the getImageData() call inside the onload-function, it should work.

Chose scale in coordinate system

what I am currently trying to create is a coordinate system that visualizes some data. I don't want to use an existing framework, but would like to create it from scratch.
What I have are three points, e.g. (15, 20), (-5,1), (120,-17). They define the scale of the coordinate system with x-min = -5 and x-max = 120 and y-min = -17 and x-max = 20. This scale is what I cant quite find as it should be meaningful. In this example it wouldn't make sense to have the coordinate system reaching from (-100, -100) to (100,100) with one mark every 10.
<html>
<head>
<script type="text/javascript">
function drawShape(){
var canvas = document.getElementById('mycanvas');
if (canvas.getContext){
//draw canvas
var context = canvas.getContext('2d');
var canvasBorder = Math.floor(canvas.scrollHeight * 0.1);
var xLength = Math.floor(canvas.scrollWidth - (canvasBorder * 2));
var yLength = Math.floor(canvas.scrollHeight - (canvasBorder * 2));
//draw coordinate system
context.beginPath();
context.moveTo(canvasBorder, canvasBorder); //30,30
context.lineTo(canvasBorder, canvasBorder + yLength); //30,270
context.lineTo(canvasBorder + xLength, canvasBorder + yLength); //370,30
context.stroke();
//easy: define 5 values for x-axis
var xMaxValue = 5;
var tmp = Math.floor(xLength / xMaxValue);
for(i = 0; i <= xMaxValue; i++){
context.beginPath();
context.moveTo(canvasBorder + tmp*i, canvasBorder + yLength);
context.lineTo(canvasBorder + tmp*i, canvasBorder + yLength+10);
context.fillText(i, canvasBorder + tmp*i, canvasBorder + yLength+10);
context.stroke();
}
//difficult: have a max value for y-axis
//too much space between 117 and 200, should display 120 or 150 instead
//next level, what happens with -20 instead of 0 for min-y
var yMaxValue = 117;
var yIncrement = Math.pow(10, (Math.abs(Math.floor(yMaxValue)).toString().length)) / 10;
var topValue = Math.floor(yMaxValue / yIncrement) + 1;
var tmp = parseInt(yLength / topValue);
for(i = 0; i <= topValue; i++){
context.beginPath();
context.moveTo(canvasBorder, yLength + canvasBorder - tmp*i);
context.lineTo(canvasBorder - 10, yLength + canvasBorder - tmp*i);
context.fillText(yIncrement * i, canvasBorder - 10, yLength + canvasBorder - tmp*i);
context.stroke();
}
} else {
alert('You need Safari or Firefox 1.5+ to see this demo.');
}
}
</script>
</head>
<body onload="drawShape();">
<canvas id="mycanvas" width="400" height="300"
style="border:1px solid #ddd;">
</canvas>
</body>
</html>
Or is there a better way to take data create a coordinate system accordingly?
Cheers,
Florian
Sounds like you want to map your actual values into a more traditional range for display on your chart.
For example, assume:
Your actual values range from -17 to 120.
You want to map these actual values into a more traditional range of 0 to 100.
Here's a function that maps a value from your actual range into a different range.
function remap(value, actualMin, actualMax, newMin, newMax) {
return(newMin + (newMax - newMin) * (value - actualMin) / (actualMax - actualMin);
}
For example, to remap your actual value of 33 (range -17 to 120) into the range of 0-100:
remappedValue = remap( 33, -17,120, 0,100 );
Note that the example new range of 0-100 is just an example.
You could use any range you desire for newMin to newMax.

javascript setTimeout and issues with a bunch of circles

I have a small program that I am supposed to write that makes a bouncy ball in a canvas. I can get a wireframe of a ball bouncing, but can't seem to get the setTimeout to fire at all. I have read, read and read about the function, but can't figure this out (new).
<!DOCTYPE HTML>
<html>
<head>
<title>basic Canvas</title>
<style>
#canvas1{
border:1px solid #9C9898;
}
body{
margin:0px;
padding:0px;
}
</style>
<script>
function drawMe(){
//Set x,y,radius
var x = 60;
var y = 60;
var radius = 70;
drawLoop(x,y,radius);
}
function drawLoop(x,y,radius){
var canvas2=document.getElementById("canvas1");
var ctx=canvas2.getContext("2d");
for(i=1;i<100;i++){
if(y + radius >= canvas2.height){
d = 1;
}
if(y - radius <= 0){
d = 0;
}
if (d==0){
x = x + 10;
y = y + 10;
}
else if (d==1){
x = x + 10;
y = y - 10;
}
draw(x,y,radius);
window.setTimeout(function() {draw(x,y,radius)},3000);
}
}
function draw(x,y,radius){
var canvas2=document.getElementById("canvas1");
var ctx=canvas2.getContext("2d");
ctx.beginPath();
ctx.arc(x,y,radius,0,2*Math.PI,false);
var gradient = ctx.createRadialGradient(x, y, 1, x, y, radius);
gradient.addColorStop(0,"blue");
gradient.addColorStop(1,"white");
ctx.fillStyle=gradient;
ctx.lineWidth=1;
ctx.strokeStyle="blue";
ctx.fill();
ctx.stroke();
}
</script>
</head>
<body onload="drawMe()">
<canvas id="canvas1" width=1000" height="400">
</canvas>
</body>
</html>
A little function called 'drawMe()' which sets x, y, and radius, then calls a little drawing loop that fires 100 times that draws the bouncy ball ('drawLoop'). at the bottom of the function drawLoop, I call draw, which actually drawls the circles. From what I've read, the line 'setTimeout(function(){draw(x,y,radius)};,3000); should call the draw function every three seconds. But it doesn't. What the heck am I doing wrong?
setTimeouts are counted from the time they are created. The loop runs almost instantly and creates the setTimeouts at almost the same time. They are then all ran 3 seconds later.
One way to get around this is in the solution below. This does not increment the loop until the current timeout has been completed.
http://jsfiddle.net/x8PWg/14/
This is only one of the many potential solutions to this.

Speed up my complex function plotter (canvas+javascript)

I have the following code for a complex function plotter. It creates a phase plot of the complex function f(z) = z*(z+5)(z-v) where v is where your mouse is pointing. As you can see, it is pretty slow. Is there any way to speed this up and get a smooth animation? Just pointing me in the right direction would be helpful.
<html>
<head>
<script type="text/javascript" src="jquery-1.8.1.js"></script>
<script type="application/javascript">
function draw() {
var canvas = document.getElementById("canvas");
var ctx;// = canvas.getContext("2d");
//The following functions convert pixel Xs and Ys to real and imaginary
//parts of a complex number, and back again
var pixToReal = function(n){return n/15.0-10.0};
var pixToImag = function(n){return - n/15.0+10}
var realToPix = function(x){return Math.round((x+10.0)*15)}
var imagToPix = function(y){return Math.round((-y+10.0)*15)}
//Storing the complex number a+bi as [a,b], the following functions add,
//multiply, and find the modulus of the complex number
var add = function(z1,z2){return [z1[0]+z2[0],z1[1] + z2[1]]}
var mult = function(z1,z2){return [z1[0]*z2[0]-z1[1]*z2[1],z1[0]*z2[1]+z1[1]*z2[0]]}
var modulus = function(z){
if (z[1]>0){return Math.atan2(z[1],z[0])}
else {return Math.atan2(z[1],z[0])+2*Math.PI}
};
//Takes a complex number and returns the RGB value of the corresponding
//point on the color wheel.
var complexToRGB = function(z){
var theta = modulus(z)%(2*Math.PI)
var Hp = (theta/(2*Math.PI))*6
var X = Math.abs(Math.round((1 - Math.abs(Hp%2 -1))*255))
var C = "rgb(0,0,0)"
if (Hp>=0 && Hp<1){
C = "rgb("+255+","+X+",0)"
};
if (1<=Hp && Hp<2){
C = "rgb("+X+","+255+",0)"}
if (2<=Hp && Hp<3){
C = "rgb("+0+","+255+","+X+")"}
if (3<=Hp && Hp<4){
C = "rgb("+0+","+X+","+255+")"}
if (4<=Hp && Hp<5){
C = "rgb("+X+","+0+","+255+")"}
if (5<=Hp && Hp<6){
C = "rgb("+255+","+0+","+X+")"}
return C
}
//a complex number
var v = [0,4]
//the function f(z) = z*(z+5)*(z+v)
var f = function(z){return mult(add(mult(z,z),mult([5,5],z)),add(z,v))}
//makes v the opposite complex number your mouse is pointing at,
//i.e. your mouse points at a root of f
function onMouseMove(evt) {
v = [-pixToReal(evt.pageX), -pixToImag(evt.pageY)];
}
$(document).mousemove(onMouseMove);
makeFrame = function(){
ctx.clearRect(0,0,300,300);
for (var n =0;n<300;n++){
for (var m=0;m<300;m++){
var x = pixToReal(n)
var y = pixToImag(m)
var z = [x,y]
var w = f(z)
ctx.fillStyle = complexToRGB(w)
ctx.fillRect(n,m,1,1)
}
}
}
function animate() {
ctx = canvas.getContext("2d");
return setInterval(makeFrame, 1);
}
animate();
}
</script>
</head>
<body onload="draw()">
<canvas id="canvas" width="300" height="300"></canvas>
</body>
I have made some quick optimizations that speeds it up about 500%. I think you could speed it up further but it would require a bit more work.
What I have done is:
Instead of setting the pixel values using fillStyle and fillRect, all pixel values are retrieved as an array (imageData), and then makeFrame() manipulates the imageData array and then set all pixels at once using putImageData().
The change above required that complexToRGB() retuns an array with the red, green and blue color values instead of a string.
in the complexToRGB() function the list of if-cases has been changed to a chain of if-else (which is faster since the conditions after a true condition will not be evaluted).
Changed the setInterval from 1000 fps to 25. There's no way the algorithm will be able to keep up with that framerate, so it's better to set it to a more realistic frame rate.
Here's the code as a jsFiddle.
Next steps: I would also try to remove as many function calls as possible, for instance inline the pixToReal() and pixToImag() formulas in the inner for loop:
for (var m = 0; m < 300; m++) {
var x = n / 15.0 - 10.0;
var y = -m / 15.0 + 10;
And then optimize the code in complexToRGB() and consider doing the same to that function to remove that function call.
I made a fiddle here, using requestAnimationFrame and drawing with ImageData. Works pretty well, maybe you can merge mine with strille's approach.

Categories