5.6.5 Coordinates, Answer In Comments (CodeHS) - javascript

The prompt of the assignment is "Write a program that shows the X and Y coordinates of the mouse in a label on the top left of the screen. You should update the values of the coordinates whenever the mouse moves." The basic code I have laid out is:
var pos;
function start(){
mouseMoveMethod(mousePos);
}
function mousePos(e){
pos = new Text("((" + e.getX() + "," + e.getY() + ")");
pos.setPosition(75, 75)
add(pos);
}
It "works" but it just keeps adding text over top of the new text instead of updating the existing text. I know I'm missing something, but I just cannot figure out what to implement to make it work the way it needs to. I've been stuck for days :(

I got it!!! I just needed to think smarter LOL
var pos;
function start(){
pos = new Text(" ");
pos.setPosition(75, 75)
add(pos);
mouseMoveMethod(mousePos);
}
function mousePos(e){
pos.setText("(" + e.getX() + "," + e.getY() + ")");
}

Related

Get crosshair values across multiple Flot Charts

I'm using the jQuery Flot Charts plugin in one of my projects. I have several charts standing in the same column and what I'm trying to do is: Show the crosshair on all of the charts if you hover on any of them. I'm doing this successfully using the following code.
//graphs - this is an object which contains the references to all of my graphs.
$.each(graphs, function(key, value) {
$(key).bind("plothover", function (event, pos, item) {
$.each(graphs, function(innerKey, innerValue) {
if(key != innerKey) {
innerValue.setCrosshair({x: pos.x});
}
});
if(item) {
var x = item.datapoint[0].toFixed(2),
y = item.datapoint[1].toFixed(2);
console.log("x:" + x + ", " + "y:" + y);
}
});
});
I'm iterating over the graphs, adding the crosshair and bind it to each other. So, now, when you hover over one of the graphs you'll see the crosshair in the same position on all of the others.
No problems with this. However I'm having problems with the second part of my code:
if(item) {
var x = item.datapoint[0].toFixed(2),
y = item.datapoint[1].toFixed(2);
console.log("x:" + x + ", " + "y:" + y);
}
And the problem is that I'm getting the console.log to print values only when I hover the actual point with my mouse while I want to get that value whenever the crosshair crosses that point, not necessarily the mouse pointer. Any clues what I'm doing wrong or maybe there's a setting in the graph options for that to work?
And another thing is that I can get the value for one graph only - the one my mouse is on, I don't seem to be able to get the values for the rest of the graphs where the crosshair is also moving.
The highlighting with
if(item) {
var x = item.datapoint[0].toFixed(2),
y = item.datapoint[1].toFixed(2);
console.log("x:" + x + ", " + "y:" + y);
}
only works when the cursor is near a point (otherwise item is null).
To get the nearest point to the crosshair, you have to do the highlighting manually by searching the nearest point and interpolate (for every graph). The code for that could look like this:
var axes = value.getAxes();
if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
pos.y < axes.yaxis.min || pos.y > axes.yaxis.max) {
return;
}
$('#output').html("x: " + pos.x.toPrecision(2));
$.each(graphs, function(innerKey, innerValue) {
var i, series = innerValue.getData()[0];
// Find the nearest points, x-wise
for (i = 0; i < series.data.length; ++i) {
if (series.data[i][0] > pos.x) {
break;
}
}
// Now Interpolate
var y,
p1 = series.data[i - 1],
p2 = series.data[i];
if (p1 == null) {
y = p2[1];
} else if (p2 == null) {
y = p1[1];
} else {
y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
}
$('#output').html($('#output').html() + "<br />" + "y (" + innerValue.getData()[0].label + "): " + y.toPrecision(2));
See this fiddle for a full working example. Some Remarks to the new code and fiddle:
has sine and cosine values as example data, so uses floating point numbers, change accordingly for int numbers and/or date values
uses a <p> element for output instead of the console
point-finding and interpolation code can be optimized further if needed (basic version here taken from the example on the Flot page)
works only if there is only one data series per graph

SVG Grid of rects translucent in Firefox

I have a problem with a grid of rects in an SVG.
Here is my code over at jsFiddle: https://jsfiddle.net/swpcpvxL/
It is supposed to make a square by plotting one pixel at a time. I use a 1 by 1 SVG rect to plot a pixel.
var svg = document.getElementById("mysvg");
for (var y = 50; y <= 150; ++y) {
for (var x = 50; x <= 150; ++x) {
var r = Math.floor((x + y) / 250);
var g = Math.floor((Math.sin(x/10.0) + 1) * x);
var b = Math.floor((Math.sin(y/10.0) + 1) * x);
var color = "rgb(" + r + "," + g + "," + b + ")";
var k = document.createElementNS("http://www.w3.org/2000/svg", "rect");
k.setAttribute("x", x);
k.setAttribute("y", y);
k.setAttribute("width", "1");
k.setAttribute("height", "1");
k.setAttribute("style", "fill: " + color);
svg.appendChild(k);
}
}
My issue is that on Firefox the rect don't plot correctly. They show up the wrong color (washed out) and are actually translucent. I think the issue is that Firefox is doing anti-aliasing or something on the rects instead of just plotting the rect right on the pixel I want. I also tested on IE - it doesn't have this problem and the code works correctly. I don't have Chrome to test with.
I uploaded an image of what it looks like for me in Firefox here.
As you can see in the image, I can see the circles through the rects. This is not what I want at all!
How can I fix the Firefox problem? Or is there a better way to generate and plot a bitmap in a SVG like this? I've noticed that this method is a bit slow, so maybe there is a better approach.
Thanks!
I see the problem in my Firefox too. It does look like a blending problem of some sort. You can also see the image "flicker" if you move the window around or resize it.
A work around is to plot each rect as a 2x2 box, instead of a 1x1. So the only change is this:
k.setAttribute("width", "2");
k.setAttribute("height", "2");
You still step on the X and Y by one pixel at a time.
That way each rect overlaps the one on each side by 1 pixel. It will make your entire 100 square one pixel bigger to the right and bottom. You may want to shift the origin to compensate, if you use this method and care about that.

Can't get mouse coordinates through javascript

Recently I have been trying to get a grasp of javascript. I've been experimenting through the past couple of months with different code to see what all is possible through javascript. Recently I've been trying to find various ways to capture the mouse coordinates through javascript with a canvas. Here's my attempt: http://jsfiddle.net/f8n2one4/
As you can see, there's a MouseHandler which is supposed to capture the mouse coordinates through the ClientX and ClientY variables. However, when I try to display these variables, nothing comes up. Why is that?
document.getElementById("test").innerHTML = "x: " + x + " y: " + y;
Shouldn't it show the x and y values?
The x and y variable are out of the scope of your draw() method.
try the following:
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
player();
MouseHandler.init(document);
var clientPosition = MouseHandler.getPos();
document.getElementById("test").innerHTML = "x: " + clientPosition.x + " y: " + clientPosition.y;
}
See it working here.
I would recommend not to initialize the whole MouseHandler every interval, just getting the position on every interval.
Also if you are animating use .requestanimationframe() instead of setInterval, you'll get better performance.
In your example are you are initializing the mouse handler (with MouseHandler.init(element)) but the x and y values have to be accessed using the getPos() method:
document.getElementById("test").innerHTML =
"x: " + MouseHandler.getPos().x +
" y: " + MouseHandler.getPos().y;
You can see a working update to your fiddle here
The x and y do not exist. You need to use:
document.getElementById("test").innerHTML = "x: " + MouseHandler.getPos().x + " y: " + MouseHandler.getPos().y;
Fiddle: http://jsfiddle.net/f8n2one4/3/
It's actually really simple, your x, y are out of scope.
You could access them via your MouseHandler variable :
MouseHandler.getPos().x
MouseHandler.getPos().y
Or try OOP Javascript and instantiating the MouseHandler with a 'new' operator
var MouseHandler = function() {
this.x = 0;
this.y = 0;
}
var myMouseHandler = new MouseHandler();
console.log(myMouseHandler.x + myMouseHandler.y);

Snap SVG: Dragging group doesn't update elements

JSFiddle here: JSFiddle
When dragging a group of objects, the individual objects' location attributes don't seem to be getting updated. This occurs whether I use the default drag() handler or define my own. Even the group BBox operation doesn't seem to update. Code:
var s = Snap("#svg");
var move = function (dx, dy, posx, posy) {
this.attr({
x: posx,
y: posy
});
//this.transform("t" + dx + "," + dy);
};
var block = s.rect(100, 100, 100, 100);
var circle = s.circle(100, 100, 50);
var group = s.g(block, circle);
//group.drag(move, function () {}, function () {});
group.drag();
//block.drag(move, function () {}, function () {});
//just a way to keep info coming w/o an interminable script
document.addEventListener('mousemove', function (e) {
bbox = block.getBBox();
block_x = block.attr("x");
block_y = block.attr("y");
gbbox = group.getBBox();
console.log("block is at " + block_x + "," + block_y,
" Block Bbbox is at " + bbox.x + "," + bbox.y,
" Group Bbbox is at " + gbbox.x + "," + gbbox.y);
}, false);
If I define only one object (say, a rect) and leave it out of a group, and pass my own "move" function to the call to drag, and include setting the "x" and "y" attributes explicitly, then that works. But if I include the rect in a group, then...I can't figure out how to do it, and I've tried a few ways (see the multiple commented-out lines showing things I've tried). I need to know where the rect sub-group element ends up after the drag, or at least the BBox of the whole group. Neither of these seem to be getting updated -- i.e. the console log I put in shows the same numbers forever, no matter where I move the object(s).
Can anyone help?
JSFiddle here: JSFiddle
I think this is because they are two different things, so they aren't actually interchangable.
The drag handler uses transforms. A transform doesn't affect any other attributes, its just an attribute on an element (in this case the group element).
getBBox will work in its current transform space, note this may be different to the clients (eg if the svg were zoomed in/out). So they are two slightly different methods, that do different things.
Use getBoundingClientRect if you need a bounding box relative to the client window. Use getBBox if you need a bounding box in the elements current coordinate space.
Code is using snap.svg.zpd as well, so zoom is possible. Problem is at onStopMove function. Events are fired when group is moved arround. In group is one circle(this.select('#main-inner-circle')) which does not have predefined location inside group. Im trying to get correct cx and cy of that inner circle after moving group.
self.onMove = function (dx, dy, ev, x, y) {
var clientX, clientY;
var tdx, tdy;
if ((typeof dx == 'object') && (dx.type == 'touchmove')) {
clientX = dx.changedTouches[0].clientX;
clientY = dx.changedTouches[0].clientY;
dx = clientX - this.data('ox');
dy = clientY - this.data('oy');
}
var snapInvMatrix = this.transform().diffMatrix.invert();
snapInvMatrix.e = snapInvMatrix.f = 0;
tdx = snapInvMatrix.x(dx, dy);
tdy = snapInvMatrix.y(dx, dy);
this.transform("t" + [tdx, tdy] + this.data('ot'));
}
self.onStartMove = function (x, y, ev) {
if ((typeof x == 'object') && (x.type == 'touchstart')) {
x.preventDefault();
this.data('ox', x.changedTouches[0].clientX);
this.data('oy', x.changedTouches[0].clientY);
}
this.data('ot', this.transform().local);
if (callbacks.onStartMove) {
callbacks.onStartMove();
}
}
self.onStopMove = function () {
var self = this.select('#main-inner-circle');
this.data('ot', this.transform().local);
//self.data('ot', self.transform().local);
console.log(self.getTransformedBBox());
console.log(this.getBBox());
//console.log($(self.node).offset().left - $(self.node).parent().offset().left);
var bBox = this.getBBox();
//var x = bBox.x + $(self.node).offset().left - $(self.node).parent().offset().left + self.getBBox().width / 2;
//var y = bBox.y + $(self.node).offset().top - $(self.node).parent().offset().top + self.getBBox().height / 2;
model.updateElementCoordinates(index, $(this.node).attr("rel"), { x: self.getTransformedBBox().cx, y: self.getTransformedBBox().cy });
if (callbacks.onStopMove) {
callbacks.onStopMove();
}
}
In order to post this question, I'd created the JSFiddle but left out the crucial snap.svg definitions...
<script src="http://snapsvg.io/assets/js/snap.svg-min.js"></script>
...with that, then indeed the group.getBBox() method actually works. However:
Apparently, using getBBox() is incredibly slow -- much slower than just accessing a "x" attribute of something like I was doing before grouping objects. All I know is that my code slows to a crawl if I use getBBox() (I have a lot of objects on the screen).
Further down in the same post mentioned earier ["Get coordinates of svg group on drag with snap.svg"1 recommended getBoundingClientRect(), which also works fine AND is fast enough! My new, working Fiddle showing all of these methods is here: New JSFiddle.
So, future users: use .node.getBoundingClientRect().

Strange behaviour of GestureEvent.rotation on iOS webkit

I am using javascript Gesture events to detect multitouch pan/scale/rotation applied to an element in a HTML document.
Visit this URL with an iPad:
http://www.merkwelt.com/people/stan/rotate_test/
You can touch the element with two finger and rotate it, but sometimes the rotation property goes go astray and my element flips around many full rotations.
Here is part of my code, I am really only taking the value directly from the event object:
...bind("gesturechange",function(e){
e.preventDefault();
curX = e.originalEvent.pageX - startX;
curY = e.originalEvent.pageY - startY;
node.style.webkitTransform = "rotate(" + (e.originalEvent.rotation) + "deg)" +
" scale(" + e.originalEvent.scale + ") translate3D(" + curX + "px, " + curY + "px, 0px)";
}...
What happens is that the value gets either 360 degrees added or subtracted, so I could monitor the value and react to sudden large changes, but this feels like a last resort.
Am I missing something obvious?
I found a solution.
In order to avoid sudden changes in the rotation that don't reflect real finger moves you need to test for that. I do that testing if the rotation changed more then 300 degrees in either direction, if it does then you need to add or subtract 360 depending on the direction. Not really intuitive, but it works.
Fixed page is here:
http://www.merkwelt.com/people/stan/rotate_test/index2.html
Here is the code
<script type="text/javascript">
var node;
var node_rotation=0;
var node_last_rotation=0;
$('.frame').bind("gesturestart",function(e){
e.preventDefault();
node=e.currentTarget;
startX=e.originalEvent.pageX;
startY=e.originalEvent.pageY;
node_rotation=e.originalEvent.rotation;
node_last_rotation=node_rotation;
}).bind("gesturechange",function(e){
e.preventDefault();
//whats the difference to the last given rotation?
var diff=(e.originalEvent.rotation-node_last_rotation)%360;
//test for the outliers and correct if needed
if( diff<-300)
{
diff+=360;
}
else if(diff>300)
{
diff-=360;
}
node_rotation+=diff;
node_last_rotation=e.originalEvent.rotation;
node.style.webkitTransform = "rotate(" + (node_rotation) + "deg)" +
" scale(" + (e.originalEvent.scale) +
") translate3D(" + (e.originalEvent.pageX - startX) + "px, " + (e.originalEvent.pageY - startY) + "px, 0px)";
}).bind("gestureend",function(e){
e.preventDefault();
});
</script>

Categories