I am trying to get X/Y coordinates from a div with a mouseclick.
I allready use this script:
Now I want to collect more X/Y coordinates, not just one.
so if I click in the div twice or more times, I want to list the coordinates under the div.
<div>"click"
"click"</div>
------------------------
coordinates 1: X/Y
coordinates 2: X/Y
.
.
.
Does anyone know how I do that?
Here's exactly what you asked for.
Fiddle: http://jsfiddle.net/ZZEk8/118/
Add to HTML:
<span class="log"></span>
JS:
var clicks = [],
updatedClicks = "";
$('.clickable').on('click', function (ev) { //We don't use .bind() after jQuery 1.7, use .on() now.
var $div = $(ev.target);
var $display = $div.find('.display');
var offset = $div.offset();
var x = ev.clientX - offset.left;
var y = ev.clientY - offset.top;
$display.text('x: ' + x + ', y: ' + y);
clicks.push(x + "/" + y);
updatedClicks += "coordinates" + " " + clicks.length + ":" + " " + clicks[clicks.length -1] + "<br />";
$('.log').html(updatedClicks);
});
UPDATE:
OP requested a way to limit the coords and delete one.
Fiddle: http://jsfiddle.net/ZZEk8/125/
var clicks = [],
updatedClicks = [],
limit = 5;
$('.clickable').on('click', function (ev) {
var $div = $(ev.target);
var $display = $div.find('.display');
var offset = $div.offset();
var x = ev.clientX - offset.left;
var y = ev.clientY - offset.top;
$display.text('x: ' + x + ', y: ' + y);
//Stops adding at limit
if (clicks.length < limit){
addCoord(x,y);
}
});
$('.delete').on('change', function(ev) {
if(clicks.length){
var selection = this.value -1;
deleteCoord(selection);
} else { //If there are no coords to delete run this
return false;
}
});
function addCoord (x,y){
clicks.push(x + "/" + y);
updatedClicks.push("Coordinates" + ":" + " " + clicks[clicks.length -1] + "<br />");
$('.log').html(updatedClicks.join(" "));
}
function deleteCoord(selection) {
clicks.splice(selection, 1);
updatedClicks.splice(selection, 1);
$('.log').html(updatedClicks.join(" "));
}
Add a new element <div id="log"></div> after your existing element.
In your JavaScript code add
document.getElementById("log").innerHTML += "<br/>Coordinates: X=" + x + "; Y=" + y;
In your jsfiddle example:
$display.html($display.html() + '<br/> x: ' + x + ', y: ' + y);
I do it using div elements, but you can change it.
See fiddle
My JS change is
$display.append($('<div />').text('x: ' + x + ', y: ' + y));
And in HTML
<div class='clickable'>
<div class='display'></div>
</div>
Or this one, with a srollbar when needed.
If you want to save coordinates, you can collect them in an array, like this:
//Declare an array with 0 length
var arr = new Array(0);
$('.clickable').bind('click', function (ev) {
var $div = $(ev.target);
var $display = $div.find('.display');
var offset = $div.offset();
var x = ev.clientX - offset.left;
var y = ev.clientY - offset.top;
$display.text('x: ' + x + ', y: ' + y);
//increase the length of array before insert the value of coords
arr.length = arr.length+1;
//insert the value
arr[arr.length-1] = "coordinates" + arr.length + ":" + x +"/" + y;
});
Then, to operate coordinates you can tour your array with for-loop
Related
Now there is a map of custom tile rules locally. There is already a custom JavaScript library that can be called normally. Now I need to replace this library with leaflet. How to use the algorithm in the old JavaScript library and leaflet to make the tile map Normal call?
The tile map projection rule is Mercator projection. The tile size is irregular. The width is 256 pixels. The height is the same on each line, but the different line heights are different. The old JavaScript library defines the ellipsoid parameters. Various levels of scale, rank number calculation rules, etc., now want to use leaflet to load these tile maps, how to use the old rules and leaflet combination?
MapBase defines various basic parameters, loadMapImage is a key function
function LoadMapImage() {
var tileLoadInfo = mapBase.getViewInfo();
MapInfo.Map.basemapslicedlayer.empty();
for (var i = 0; i < tileLoadInfo.TileInfo.length; i++) {
if (MapInfo.Map.Tiles[tileLoadInfo.TileInfo[i].Col + "_" + tileLoadInfo.TileInfo[i].Row + "_" + tileLoadInfo.Mode] == undefined) {
if (tileLoadInfo.Mode == 6) {
var src = DNCOptions.url + "&" + DNCOptions.paramX + "=" + tileLoadInfo.TileInfo[i].Row + "&" + DNCOptions.paramY + "=" + tileLoadInfo.TileInfo[i].Col + "&" + DNCOptions.paramZ + "=" + tileLoadInfo.TileInfo[i].Level + "&SessionID=" + WinfoDNCSessionID
} else if (tileLoadInfo.Mode == 8 || tileLoadInfo.Mode == 9) {
var level = tileLoadInfo.Level + 2;
if (tileLoadInfo.Mode == 9) {
level = tileLoadInfo.Level - 3
}
src = MapInfo.ServicePath + "?REQUEST=GetMap&SERVICE=CacheMap&Y=" + tileLoadInfo.TileInfo[i].Col + "&X=" + tileLoadInfo.TileInfo[i].Row + "&LEVEL=" + level + "&LAYERS=" + DNCOptions.layername + "&SessionID=" + WinfoDNCSessionID
} else {
var src = MapInfo.ServicePath + "?REQUEST=GetMap&SERVICE=WINFODNC&X=" + tileLoadInfo.TileInfo[i].Col + "&Y=" + tileLoadInfo.TileInfo[i].Row + "&LEVEL=" + tileLoadInfo.Level + "&LAYERS=" + tileLoadInfo.Mode + "&SessionID=" + WinfoDNCSessionID
}
MapInfo.Map.Tiles[tileLoadInfo.TileInfo[i].Col + "_" + tileLoadInfo.TileInfo[i].Row + "_" + tileLoadInfo.Mode] = w$("<img>").css({
position: "absolute",
left: tileLoadInfo.TileInfo[i].Offset_x,
top: tileLoadInfo.TileInfo[i].Offset_y
}).attr("src", src)
}
MapInfo.Map.basemapslicedlayer.append(MapInfo.Map.Tiles[tileLoadInfo.TileInfo[i].Col + "_" + tileLoadInfo.TileInfo[i].Row + "_" + tileLoadInfo.Mode].css({
position: "absolute",
left: tileLoadInfo.TileInfo[i].Offset_x,
top: tileLoadInfo.TileInfo[i].Offset_y
}))
}
}
function GetTileInfoByViewportParam(vp) {
var Box = {};
var i, row1, row2, col1, col2, hTileSize;
var L, R, T, B;
var LT = ScreenPoint2Coordinate(vp, 0, 0);
Box.Top = LT[0];
Box.Left = LT[1];
var RB = ScreenPoint2Coordinate(vp, vp.Width, vp.Height);
Box.Bottom = RB[0];
Box.Right = RB[1];
var rc = CalculateTile(LevelZeroTileSizeDegrees, Box, vp.Level);
row1 = rc[0];
row2 = rc[2];
col1 = rc[1];
col2 = rc[3];
var LRTB = CalculateTileExtend(LevelZeroTileSizeDegrees, vp.Level, row1, col1);
L = LRTB[0];
R = LRTB[1];
T = LRTB[2];
B = LRTB[3];
var Offset = Coordinate2ScreenPoint(vp, T, L);
vp.Offset_x = Offset[0];
vp.Offset_y = Offset[1];
MapViewInfo.Level = vp.Level;
MapViewInfo.Box = Box;
i = 0;
var offsety = vp.Offset_y;
MapViewInfo.TileInfo = [];
for (var j = row1; j >= row2; j--) {
hTileSize = CalculateTileSize(vp.Level, j, col1);
var offsetx = vp.Offset_x;
for (var z = col1; z <= col2; z++) {
var tileInfo = {};
tileInfo.Row = j;
tileInfo.Col = z;
tileInfo.Height = hTileSize;
tileInfo.Widht = TileSize;
tileInfo.Offset_x = offsetx;
tileInfo.Offset_y = offsety;
offsetx += TileSize;
MapViewInfo.TileInfo[i] = tileInfo;
i++
}
offsety += hTileSize
}
return MapViewInfo
};
According to the default initialization map method of leaflet, the parameters can only be retrieved to the blank tile.
I have a d3 stacked area visualization that consists of a main chart (national) and small multiples drawn therefrom (i.e. state charts). Here's the Plunker for the viz I'm working on.
The tooltip currently displays the x and y values of the selected path. What I'm trying to achieve is this: For the state charts only, I want the tooltip to display the values of the non-selected paths, as well as the value for the selected path.
I've partly managed to achieve this on an earlier version of the visualization that I'm working on. Here's the Plunker from which I'm trying to adapt the tooltip. Very similar.
This is the code that I've been struggling for several days to integrate into my existing tooltip:
paths.on('mousemove', function(d, i) {
let mousePos = d3.mouse(this);
d3.select(this).classed('hover', true);
MouseOverChart(d, dataset, mousePos, xScale);
function MouseOverChart(d, dataset, mousePos, xScale) {
var xPosition = (d3.event.pageX),
yPosition = (d3.event.pageY - 28);
let mouseX = mousePos[0];
var invertedX = xScale.invert(mouseX),
bisect = d3.bisector(function(d) { return new Date(d.x); }).left,
idx = bisect(d.values, invertedX);
var content = getTooltipHeader(d,idx);
content += '<ul class="record-list" >'
for (var i = 0; i < dataset.length; i++) {
content += getRecordContent(dataset[i], idx);
}
content += '</ul>';
showTooltip(content, xPosition, yPosition);
}
function showTooltip(content) {
d3.select(".tooltip")
.html(content);
d3.select(".tooltip");//.classed("none", false);
}
function getRecordContent(obj, pos) {
return '<li><span class="record-label">' + obj.record + '</span><span class="record-value">' + obj.values[pos].value + '</span></li>'
}
function getTooltipHeader(data, pos) {
var html = '<div class="tooltip-label"><span>' + data.values[pos].x +'</span><h3>' + data.record + '</h3></div>';
return html;
}
The problems:
I haven't been able to get the non-selected values to display inside my existing tooltip, or even as a separate tooltip.
When mousing over the state charts, the current configuration displays the selected value twice -- once in the tooltip header, and again in <record-list>. I've tested various filter conditions to suppress the value and its label from being displayed in <record-list> if it already appears in <tooltip-header>, but I haven't been successful.
Here, again, is the Plunker for the viz I'm working on.
And here's the Plunker from which I'm adapting the tooltip
Thanks in advance for any help you're able to offer.
Edit, 29 November 2017:
I've made a little progress; the tooltip does not appear — albeit without any values — when mousing over the dates of 29 January 2009 and 1 March 2009, but not on any other dates:
I'm continuing to work on this, but I'm definitely stuck, and would still appreciate any help.
For those still following along at home, I managed to solve this.
Here's an updated Plunker: http://plnkr.co/edit/NfMeTpXzXGTxgNFKPFJe?p=preview
The relevant code:
paths.on('mousemove', function(d, i) {
let mousePos = d3.mouse(this);
d3.select(this).classed('hover', true);
MouseOverChart(d, dataset, mousePos, xScale);
function MouseOverChart(d, dataset, mousePos, xScale) {
//Get this bar's x/y values, then augment for the tooltip
var xPosition = (d3.event.pageX),
yPosition = (d3.event.pageY - 28);
let mouseX = mousePos[0];// + 1;
var invertedX = xScale.invert(mouseX),
bisect = d3.bisector(function(d) { return new Date(d.x); }).left,
idx = bisect(d.values, invertedX);
function getMonth(date) {
var month = date.getMonth() + 1;
return month < 10 ? '0' + month : '' + month; // ('' + month) for string result
}
invertedX = ("" + (invertedX.getMonth() + 1)).slice(-2) + '/' + invertedX.getFullYear();
var selected = (d.values);
for (var k = 0; k < selected.length; k++) {
dates[k] = selected[k].x
dates[k] = ("" + (dates[k].getMonth() + 1)).slice(-2) + '/' + dates[k].getFullYear();
}
idx = dates.indexOf(invertedX);
var content = getTooltipHeader(d,idx);
content += '<ul class="record-list" >'
for (var i = 0; i < dataset.length; i++) {
content += getRecordContent(dataset[i], idx);
}
content += '</ul>';
showTooltip(content, xPosition, yPosition);
} //closes MouseOverChart function
function getTooltipHeader(data, pos) {
var hoverdate = data.values[pos].x;
var invertedxmo = data.values[pos].x;
var invertedxyr = data.values[pos].x;
function getMonth(date) {
var month = date.getMonth() + 1;
return month < 10 ? '0' + month : '' + month; // ('' + month) for string result
}
hoverdate = ("" + (hoverdate.getMonth() + 1)).slice(-2) + '/' + hoverdate.getFullYear();
var selected = (d.values);
for (var k = 0; k < selected.length; k++) {
dates[k] = selected[k].x
dates[k] = ("" + (dates[k].getMonth() + 1)).slice(-2) + '/' + dates[k].getFullYear();
}
invertedxmo = ("" + (invertedxmo.getMonth() + 1)).slice(-2) ;
var selectedmo = (d.values);
for (var m = 0; k < selectedmo.length; k++) {
dates[m] = selectedmo[m].x
dates[m] = ("" + (dates[m].getMonth() + 1)).slice(-2) ;
}
invertedxyr = invertedxyr.getFullYear();
var monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
var html = '<div class="tooltip-label"><span>' + monthNames[invertedxmo-1] + " " + invertedxyr + '</span><h3>' + " " + data.state + '<br/>' + data.record.toLowerCase() + " " + numFormat(data.values[pos].y) + '</h3></div>';
return html;
} //closes getTooltipHeader function
function getRecordContent(obj, pos) {
return '<li><span class="record-label">' + obj.record + '</span><span class="record-value">' + numFormat(obj.values[pos].y) + '</span></li>'
} //closes getRecordContent function
and
function showTooltip(content, xPosition, yPosition) {
tt.html('<span class="record">' + d.state + "</span>" + '<br/>' + '<br/>' + '<span class="dataNum">' + '</span>' + " " + d.record.toLowerCase() )
.style('top', d3.event.pageY - 12 + 'px')
.style('visibility', 'visible')
.html(content);
}
This code could use some cleanup, but it's functional.
I'm still looking for a way of eliminating the redundant presentation of the selected value. Currently, if you hover over an area, the values of the selected path (at the bisection of a given month) appear both in the tooltip's header div and in its record-list div.
Does anyone has a suggestion for a way of implementing, perhaps, a filter function that removes the selected value from record-list — or alternatively, a way of introducing a condition for record-list such that it displays the selected value in bold font (thereby making clear that it is the "selected" one, and obviating the same value to appear again in the header)?
I am trying to create a circular page with tabs around it and the SVG path are not being appended to the html.
Any help would be grateful. I have not worked with JS in a long time since I have moved on to Java so my skills are rusty.
var tabs = 10;
var radius = 500;
var xcords = [];
for (var i = 1; i <= tabs; i++) {
xcords[xcords.length] = radius + Math.cos(36 * i + 18) * radius;
}
var ycords = [];
for (var i = 1; i <= tabs; i++) {
ycords[ycords.length] = radius + Math.sin(36 * i + 18) * radius;
}
$(document).ready(function(){
for (var i = 1; i < tabs; i++) {
$(".svg").prepend("<path class='piece' />");
$(".piece").attr({
"d" : "M" + xcords[i] + "," + ycords[i] + "L500,500 L" + xcords[i + 1] + "," + ycords[i + 1] " A500,500 0 0,0 " + xcords[i] + "," + ycords[i] + " Z"
});
}
$(".piece").mouseenter(function() {
$(this).fadeTo(100, 0.7);
});
$(".piece").mouseleave(function() {
$(this).fadeTo(100, 1);
});
$(".piece").click(function() {
$(".center").attr("fill",$(this).attr("fill"));
});
});
I know that the array id not large enough to get xcords[11] but a solution to it would be helpful.
I have a for loop that take too long to execute large amount of data:
for (var itm = 0; itm < itmCount; itm++) {
var curObj = $('[aria-describedby=' + gridName + '_' + columnNames[itm].name + ']');
var thisCell = $('#' + gridName + '_' + columnNames[itm].name + ' div');
$('#widthTest').html(thisCell.text()).css({
'font-family': thisCell.css('font-family'),
'font-size': thisCell.css('font-size'),
'font-weight': thisCell.css('font-weight')
});
var maxWidth = Width = $('#widthTest').elementRealWidth() + 17;
var itm2Count = curObj.length;
// Loop through Rows
for (var itm2 = 0; itm2 < itm2Count; itm2++) {
var thisCell = $(curObj[itm2]);
$('#widthTest').html(thisCell.html()).css({
'font-family': thisCell.css('font-family'),
'font-size': thisCell.css('font-size'),
'font-weight': thisCell.css('font-weight')
});
thisWidth = $('#widthTest').elementRealWidth();
if (thisWidth > maxWidth) {maxWidth = thisWidth+10;}
}
$('#' + gridName + ' .jqgfirstrow td:eq(' + itm + '), #' + gridName + '_' + columnNames[itm].name).width(maxWidth).css('min-width', maxWidth+17);
$('#' + gridName + ' .jqgfirstrow td:eq(' + 0 + '), #' + gridName + '_' + columnNames[0].name).width('30').css('min-width', '30px');
I get this issue from firefox:
A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.
and the Chrome kills the page. Any idea?
UPDATE:
Here is my code after doing chunk:
var itmCount = columnNames.length;
var numOfElements = itmCount;
var elementsPerChunk = 50;
var numOfChunks = numOfElements / elementsPerChunk; //divide it into chunks
for (var x = 0; x < numOfChunks; x++) {
setTimeout(function() {
for (var y = 0; y < elementsPerChunk; y++) {
var curObj = $('[aria-describedby=' + gridName + '_' + columnNames[elementsPerChunk].name + ']');
var thisCell = $('#' + gridName + '_' + columnNames[elementsPerChunk].name + ' div');
$('#widthTest').html(thisCell.text()).css({
'font-family': thisCell.css('font-family'),
'font-size': thisCell.css('font-size'),
'font-weight': thisCell.css('font-weight')
});
var maxWidth = Width = $('#widthTest').elementRealWidth() + 17;
var itm2Count = curObj.length;
// Loop through Rows
for (var itm2 = 0; itm2 < itm2Count; itm2++) {
var thisCell = $(curObj[itm2]);
$('#widthTest').html(thisCell.html()).css({
'font-family': thisCell.css('font-family'),
'font-size': thisCell.css('font-size'),
'font-weight': thisCell.css('font-weight')
});
thisWidth = $('#widthTest').elementRealWidth();
if (thisWidth > maxWidth) {maxWidth = thisWidth+10;}
}
$('#' + gridName + ' .jqgfirstrow td:eq(' + elementsPerChunk + '), #' + gridName + '_' + columnNames[elementsPerChunk].name).width(maxWidth).css('min-width', maxWidth+17);
$('#' + gridName + ' .jqgfirstrow td:eq(' + 0 + '), #' + gridName + '_' + columnNames[0].name).width('30').css('min-width', '30px');
//grid.setRowData ( iids[itm], false, {height: 30} );
}
}, 0);
}
Try to keep in mind that JavaScript is entirely browser sided. Each browser will respond differently when it thinks your code times out. Furthermore, you can't bypass these errors. A great example would be chromes option to "stop this website from displaying anymore pop-ups." These features are added for the convenience of the end user and usually fix security holes or inform the user that the website is simply taking a while (which most users don't like)
One idea is to find a way to split up the amount of data you process. it seems like the issue, as you stated, is with large amounts of data. Is there a way to split the data up into "pages" and process, say, 50 items at a time?
If you can create stop points while it's updating that would work as well. The browser locks up while JavaScript runs which is a big part of the problem.
Finally, consider processing data on the server side and sending/receiving it with Ajax. This will let the browser/user work while your code is processed elsewhere and only stops to receive new data.
EDIT:
To address your comment:
Using math you could use nested for-loops to split the processing load into chunks of 50:
var numOfElements = /*how ever you count the records*/;
var elementsPerChunk = 50;
var numOfChunks = numOfElements / elementsPerChunk; //divide it into chunks
for (x = 0; x < numOfChunks; x++) {
//Set Time out
for (y = 0; y < elementsPerChunk; y++) {
//Rest of code
}
}
Note:
The above isn't perfect, for instance, you have to run the loop 1 more time to account for any sets of records that is not evenly divisible by 50 but you do not want to loop again if it is divisible by 50 (probably us mod operator to determine if there is a remainder and then add 1 if there is).
why doesnt this work?
//I removed the 'for loops' for a second and then the script does something, what wrong with the loops?//
var openWindows= new Array[50]();
function resize(x){
//changed boolean to var
var open = false;
for(var i = 0; i < openWindows.length; i++){
if(openWindows[i] == x){
open = true;
openWindows[i] = "";
}
}
if(open == false){
for(var i = 0; i < openWindows.length; i++){
if(openWindows[i] == ""){
openWindows[i] = x;
break;
}
}
var t = setTimeout("document.getElementById('" + x + "').style.height='200px'",20);
var t = setTimeout("document.getElementById('" + x + "').style.height='220px'",40);
var t = setTimeout("document.getElementById('" + x + "').style.height='240px'",60);
var t = setTimeout("document.getElementById('" + x + "').style.height='260px'",80);
var t = setTimeout("document.getElementById('" + x + "').style.height='280px'",100);
var t = setTimeout("document.getElementById('" + x + "').style.height='300px'",120);
var t = setTimeout("document.getElementById('" + x + "').style.height='320px'",140);
var t = setTimeout("document.getElementById('" + x + "').style.height='340px'",160);
var t = setTimeout("document.getElementById('" + x + "').style.height='360px'",180);
var t = setTimeout("document.getElementById('" + x + "').style.height='380px'",200);
var t = setTimeout("document.getElementById('" + x + "').style.height='400px'",220);
var t = setTimeout("document.getElementById('" + x + "').style.height='420px'",240);
var t = setTimeout("document.getElementById('" + x + "').style.height='440px'",260);
var t = setTimeout("document.getElementById('" + x + "').style.height='460px'",280);
var t = setTimeout("document.getElementById('" + x + "').style.height='480px'",300);
var t = setTimeout("document.getElementById('" + x + "').style.height='500px'",320);
var t = setTimeout("document.getElementById('" + x + "').style.height='520px'",340);
var t = setTimeout("document.getElementById('" + x + "').style.height='540px'",360);
var t = setTimeout("document.getElementById('" + x + "').style.height='560px'",380);
var t = setTimeout("document.getElementById('" + x + "').style.height='580px'",400);
}else{
var t = setTimeout("document.getElementById('" + x + "').style.height='560px'",40);
var t = setTimeout("document.getElementById('" + x + "').style.height='540px'",60);
var t = setTimeout("document.getElementById('" + x + "').style.height='520px'",80);
var t = setTimeout("document.getElementById('" + x + "').style.height='500px'",100);
var t = setTimeout("document.getElementById('" + x + "').style.height='480px'",120);
var t = setTimeout("document.getElementById('" + x + "').style.height='460px'",140);
var t = setTimeout("document.getElementById('" + x + "').style.height='440px'",160);
var t = setTimeout("document.getElementById('" + x + "').style.height='420px'",180);
var t = setTimeout("document.getElementById('" + x + "').style.height='400px'",200);
var t = setTimeout("document.getElementById('" + x + "').style.height='380px'",220);
var t = setTimeout("document.getElementById('" + x + "').style.height='360px'",240);
var t = setTimeout("document.getElementById('" + x + "').style.height='340px'",160);
var t = setTimeout("document.getElementById('" + x + "').style.height='320px'",260);
var t = setTimeout("document.getElementById('" + x + "').style.height='300px'",280);
var t = setTimeout("document.getElementById('" + x + "').style.height='280px'",300);
var t = setTimeout("document.getElementById('" + x + "').style.height='260px'",320);
var t = setTimeout("document.getElementById('" + x + "').style.height='240px'",340);
var t = setTimeout("document.getElementById('" + x + "').style.height='220px'",360);
var t = setTimeout("document.getElementById('" + x + "').style.height='200px'",380);
var t = setTimeout("document.getElementById('" + x + "').style.height='180px'",400);
}
}
It's not really clear enough what your code is supposed to do, but I can see a few issues.
The first line has a syntax error:
var openWindows= new Array[50](); // Should be `Array(50)`
Javascript is a dynamically typed language, you do not need to assert types when declaring variables:
boolean open = false;
// Should be
var open = false;
You should only use the var keyword once for each variable declaration. In this case, every time you declare var t = window.setTimeout(...); you're redeclaring the variable. In fact, you don't need the var t = at all.
Also, you can check to see if a window is closed using the .closed property:
if (windowVar.closed == true) { /* ... */ };