var specPaths =
[ [ ['RT01','34 St
Herald Sq', '23 St', 'single-route' ],
['RT02','149 St-Grand Concourse', '145 St', 'multiple-route' ],
['RT03','Fort Hamilton
Pkwy', 'Union St', 'multiple-route'],
['RT04','Fort Hamilton
Pkwy', 'Atlantic Av
Barclays Ctr', 'single-route' ]
],
[ ['RA01','104 St', 'Aqueduct
North Conduit Av'],
['RA02','Beach 90 St', 'Beach
44 St' ],
['RA03','Nereid Av', 'Eastchester
Dyre Av' ],
['RA04','138 St-Grand
Concourse', '3 Av-138 St' ],
['RA05','72 St', '5 Av-53 St' ],
['RA06','175 St', '155 St' ],
['RA07','Prince St', 'Queensboro
Plaza' ],
['RA08','Coney Island
Stillwell Av','Wood-
haven
Blvd' ],
['RA09','Coney Island
Stillwell Av','Forest Hills-
71 Av' ],
['RA10','Spring St', 'Lafayette
Av' ],
['RA11','Spring St', 'Nostrand Av' ],
['RA12','New Lots Av', 'Harlem
148 St' ],
['RA13','New Lots Av', '149 St-Grand Concourse' ],
['RA14','Jamaica-179 St', 'Court Sq
23 St' ],
['RA15','Jamaica-179 St', 'Roosevelt
Island' ],
['RA16','City Hall', 'Queensboro
Plaza' ],
['RA17','168 St', '157 St' ],
['RX18','Euclid Av', 'Grant Av' ],
['RX19','Kings Hwy', 'Coney Island
Stillwell Av'],
['RX20','Fulton
St', 'Clark
St' ],
['RX21','Kingsbridge
Rd', 'Woodlawn' ]
],
[ ['JT01','145 St', '86 St', "'96 St'" ],
['JT02','High
St', 'Spring St', "'Fulton
St', 'Bklyn Br
City
Hall'" ],
['JT03','Church Av','Church Av', "'4 Av-9 St', 'Atlantic Av
Barclays Ctr'" ],
['JT04','72 St', '5 Av-53 St', "'59 St
Columbus Circle', '47-50 Sts
Rockefeller
Ctr'"]
],
[ ['JA01','Harlem
148 St', '47-50 Sts
Rockefeller
Ctr'],
['JA02','Metropolitan
Av', '2 Av' ],
['JA03','Bway-Lafayette St', 'Fulton
St' ],
['JA04','Wall
St', '2 Av' ],
['JX05','Central Av', 'Kosciuszko
St' ], // Attention exercise
['JX06','Grand Central
42 St
Metro-North','34 St
Penn Stn' ] // Attention exercise
],
[ ['GA01','Midtown Manhattan', 'JFK' ],
['GA02','Lower Manhattan', 'Harlem
148 St' ],
['GA03','Midtown Manhattan', 'Jamaica-179 St' ],
['GA04','Upper Manhattan', 'Coney Island
Stillwell Av' ]
]
];
var stationLabels;
var nStationLabels;
var thisLabel='noLabel'; // Current station label, used by functions disambiguateStations and checkDisambiguation
// --- DISAMBIGUATION OF STATION NAMES ---
function disambiguateStations()
{
var disambiguation =
[
[ '7 Av', '', '', '' ],
[ '8 Av', '', '' ],
[ '14 St', '', '', '' ],
[ '18 Av', '', '', '' ],
[ '20 Av', '', '' ],
[ '23 St', '', '', '', '' ],
[ '28 St', '', '', '' ],
[ '34 St
Penn Stn', '', '' ],
[ '36 St', '', '' ],
[ '50 St', '', '' ],
[ '72 St', '', '' ],
[ '77 St', '', '' ],
[ '79 St', '', '' ],
[ '86 St', '', '', '', '', '' ],
[ '96 St', '', '', '' ],
[ '103 St', '', '', '' ],
[ '104 St', '', '' ],
[ '111 St', '', '', '' ],
[ '116 St', '', '', '' ],
[ '125 St', '', '', '', '' ],
[ '135 St', '', '' ],
[ '145 St', '', '', '' ],
[ '167 St', '', '' ],
[ '170 St', '', '' ],
[ '181 St', '', '' ],
[ 'Avenue U', '', '', '' ],
[ 'Broadway', '', '' ],
[ 'Canal St', '', '', '', '' ],
[ 'Chambers St', '', '', '' ],
[ 'Church Av', '', '', '' ],
[ 'Dyckman
St', '', '' ],
[ 'Fordham Rd', '', '' ],
['Fort Hamilton
Pkwy', '', '' ],
[ 'Fulton
St', '', '', '','' ],
[ 'Gun Hill Rd', '', '' ],
[ 'Kings Hwy', '', '', '' ],
[ 'Kingsbridge
Rd', '', '' ],
[ 'Lorimer
St', '', '' ],
[ 'New Lots Av', '', '' ],
[ 'Nostrand Av', '', '' ],
[ 'Pelham Pkwy', '', '' ],
[ 'Rector St', '', '' ],
[ 'Spring St', '', '' ],
[ 'Van Siclen Av', '', '' ],
[ 'Wall
St', '', '' ]
];
var iLoop;
var iDisambiguation;
var iDisambiguand;
var iDisambiguandNext;
var iDisambiguator;
var nAmbiguous=0;
var disambiguand=[[]];
var item;
var targetItem;
var transformArgs;
var args;
var labelX, labelY;
var iBeg, iEnd;
var nodeIndex;
var nSubNodes;
for (iDisambiguation=0; iDisambiguation < disambiguation.length; iDisambiguation++)
{ disambiguand[iDisambiguation]=[]; }
//-- Carry out two initialisations on the set of station labels
// (a) Make all station labels transparent
// (b) Build up a list of ambiguands, indexed by the corresponding row in the disambiguation table
// (An 'ambiguand' is an ambiguous station name that we need to disambiguate.)
for (iLoop=0; iLoop < nStationLabels; iLoop++)
// stationLabels.childNodes.forEach
// ( function(item,index)
{ item=stationLabels.childNodes[iLoop];
if (item.nodeName == "text" || item.nodeName == "tspan")
{ // Make the station label transparent
transpare(item);
thisLabel = extractLabel(item);
// Look for extractLabel in the disambiguation table
iDisambiguation = disambiguation.findIndex(checkDisambiguation);
if (iDisambiguation >= 0)
{ iDisambiguand = disambiguand[iDisambiguation].length;
if (item.nodeName == "text")
{ targetItem = item; }
else
{ targetItem = item.parent; };
transformArgs = targetItem.getAttribute("transform");
iBeg = transformArgs.indexOf('(');
iEnd = transformArgs.indexOf(')');
transformArgs = transformArgs.substring(iBeg+1,iEnd);
var args = transformArgs.split(' ');
var labelX = parseInt(args[4]);
var labelY = parseInt(args[5]);
disambiguand[iDisambiguation][iDisambiguand] =
{ x:labelX,
y:labelY,
candidate:true,
stationLabelIndex:iLoop
};
}
}
}
// Reality check: for each disambiguation, we should have the same number of disambiguators as disambiguands
for (iDisambiguation = 0; iDisambiguation < disambiguation.length; iDisambiguation++)
{ if (disambiguation[iDisambiguation].length - 1 != disambiguand[iDisambiguation].length)
errorLog('disambiguation['+iDisambiguation+'].length ='+disambiguation[iDisambiguation].length
+', disambiguand['+iDisambiguation+'].length = '+disambiguand[iDisambiguation].length
+' ('+disambiguation[iDisambiguation][0]+')');
}
// Execute disambiguation
// Outer loop: go through all the disambiguations (i.e. rows of the disambiguation table)
for (iDisambiguation = 0; iDisambiguation < disambiguation.length; iDisambiguation++)
// Inner loop: go through all the disambiguators (i.e. columns of the disambiguation table)
{ for (iDisambiguator = 1; iDisambiguator < disambiguation[iDisambiguation].length; iDisambiguator++)
// We now have to reconcile the two rows:
// (a) the vector of disambiguators (i.e. disambiguation[idisambiguation][*])
// (b) the vector of disambiguands (i.e. disambiguands[idisambiguation][*])
// using the fact that the disambiguators are in a hard-coded order of X-coordinate, then Y-coordinate
// while the disambiguands are in haphazard order but with X,Y coordinates attached.
// Find next disambiguand to process. Start by assuming it is the first one:
{ iDisambiguandNext = -1;
// Loop through all the other disambiguands in this row, looking for a prior one:
for (iDisambiguand = 0; iDisambiguand < disambiguand[iDisambiguation].length; iDisambiguand++)
// If this disambiguand is still a candidate (i.e. it has not yet been processed),
// then check whether it should be done next
{ if ( disambiguand[iDisambiguation][iDisambiguand].candidate)
// Disambguands are ordered first by X-coordinate, second by Y-coordinate
{ if ( (iDisambiguandNext == -1)
|| (disambiguand[iDisambiguation][iDisambiguand].x <= disambiguandNext.x)
|| (disambiguand[iDisambiguation][iDisambiguand].x == disambiguandNext.x
&& disambiguand[iDisambiguation][iDisambiguand].y <= disambiguandNext.y)
)
{ disambiguandNext = disambiguand[iDisambiguation][iDisambiguand];
iDisambiguandNext = iDisambiguand;
}
}
};
// We have now identified the next disambiguand to be processed, so let us do it: store the hard-coded
// text string for this disambiguator into the SVG object
var nodeIndex = disambiguand[iDisambiguation][iDisambiguandNext].stationLabelIndex;
var nSubNodes = stationLabels.childNodes[nodeIndex].childNodes.length;
if (nSubNodes == 1)
{ stationLabels.childNodes[nodeIndex].innerHTML += disambiguation[iDisambiguation][iDisambiguator]; }
else
{ stationLabels.childNodes[nodeIndex].childNodes[nSubNodes-1].innerHTML += disambiguation[iDisambiguation][iDisambiguator]; }
stationLabels.childNodes[nodeIndex].style.fill = "transparent";
// and mark this disambiguator as 'done'
disambiguand[iDisambiguation][iDisambiguandNext].candidate = false;
}
};
}
// Check disambiguation
function checkDisambiguation(disambiguationRow)
{ return (disambiguationRow[0] == thisLabel); }
// --- VALIDATE PATHS ---
function validatePaths(iBlock,iJourneyPlan,resultListRaw)
{ var resultList = resultListRaw;
var routesDirect = [];
var routesIndirect = [];
var routesRegion = [];
var journeyType = specPaths[iBlock][iJourneyPlan][0].substring(0,1);
var begStation = specPaths[iBlock][iJourneyPlan][1];
var endStation = specPaths[iBlock][iJourneyPlan][2];
// Add the end station to the list of the clicked transfers
resultList[resultList.length] = endStation;
if (journeyType == 'G')
{ begRegion = begStation;
begStation = resultList[0];
}
// Find out what routes the start station is on
for (var iStation = 0; iStation < topology.length; iStation++)
{ try
{ if (topology[iStation][0] == begStation)
{ routesDirect = topology[iStation][1];
routesIndirect = topology[iStation][2];
routesRegion = topology[iStation][3];
break;
}
} catch (err) { alert('ERROR: '+err+' at station '+iStation); }
}
if (journeyType == "G")
{ // alert(iBlock+', '+iJourneyPlan+': '+begRegion+' - v - '+routesRegion);
var validStart = false;
for (var iRegion = 0; iRegion < routesRegion.length; iRegion++)
{ if (begRegion == routesRegion[iRegion])
{ validStart = true;
break;
}
}
if (!validStart)
{ journeyClass = 10;
return journeyClass;
}
iClickedBeg = 1;
}
else
{ iClickedBeg = 0; }
if (routesDirect.length == 0) alert('ERROR: start station not found');
// Default value 10 = no result
var journeyClass = -1;
// Loop through all clicked stations
for (var iClicked = iClickedBeg; iClicked < resultList.length; iClicked++)
{ var nextStation = resultList[iClicked];
// Go to next clicked transfer station
// Loop through every station in the network to find the one that the user clicked on
for (var iStation = 0; iStation < topology.length; iStation++)
{ if (topology[iStation][0] == nextStation)
{ var routesDirectNew = topology[iStation][1];
var routesIndirectNew = topology[iStation][2];
var routesRegionNew = topology[iStation][3];
var validTransfer = false;
var thisJourneyClass = 10;
// Search through all direct routes of clicked station and test station
for (iRoute = 0; iRoute < routesDirect.length; iRoute++)
{ for (jRoute = 0; jRoute < routesDirectNew.length; jRoute++)
{ if (routesDirect[iRoute] == routesDirectNew[jRoute])
{ validTransfer = true;
thisJourneyClass = 1;
break;
}
}
if (validTransfer) break;
}
// Not a direct transfer: maybe semi-direct
if (!validTransfer)
{ for (iRoute = 0; iRoute < routesDirect.length; iRoute++)
{ for (jRoute = 0; jRoute < routesIndirectNew.length; jRoute++)
{ if (routesDirect[iRoute] == routesIndirectNew[jRoute])
{ validTransfer = true;
thisJourneyClass = 2;
break;
}
}
if (validTransfer) break;
}
for (iRoute = 0; iRoute < routesIndirect.length; iRoute++)
{ for (jRoute = 0; jRoute < routesDirectNew.length; jRoute++)
{ if (routesIndirect[iRoute] == routesDirectNew[jRoute])
{ validTransfer = true;
thisJourneyClass = 2;
break;
}
}
for (jRoute = 0; jRoute < routesIndirectNew.length; jRoute++)
{ if (routesIndirect[iRoute] == routesIndirectNew[jRoute])
{ validTransfer = true;
thisJourneyClass = 2;
break;
}
}
}
}
if (validTransfer)
{ routesDirect = routesDirectNew;
routesIndirect = routesIndirectNew;
routesRegion = routesRegionNew;
journeyClass = Math.max(journeyClass,thisJourneyClass);
}
else
{ journeyClass = 3;
}
break;
}
}
}
return journeyClass;
}
// --- UTILITIES ---
// Open up the SVG map for use
function initStations()
{ // Get reference to the document root
var documentSVG = mapExperiment.contentDocument;
stationLabels = documentSVG.getElementById('_x31_.4_Station_Names__x28_font_x29_'); // _x31_.4_Station_Names__x28_font_x29_
if (stationLabels == null) errorLog('Station names not found');
nStationLabels = stationLabels.childNodes.length;
}
// Extract a station name as a single string from multiple nodes (on possibly multiple lines)
function extractLabel(textNode)
{ var iWheelchair=181;
var iEscape =182;
var charWheelchair = String.fromCharCode(iWheelchair);
var charEscape = String.fromCharCode(iEscape);
var nSpan = textNode.childNodes.length;
var yPrevious = "";
var stationLabel="";
if (nSpan == 2)
var secondNodeName = textNode.childNodes[1].nodeName;
else
var secondNodeName = "";
if (nSpan == 1) // || (nSpan == 2 && textNode.childNodes[1].nodeName == "#comment"))
{ stationLabel = textNode.innerHTML; }
else if (nSpan == 2 && secondNodeName == "#comment")
{ stationLabel = textNode.childNodes[0].nodeValue+''; } // ?nodeValue
else if (nSpan > 0)
{ var yCurrent = textNode.childNodes[0].attributes[1].nodeValue; // ?nodeValue
for (i=0; i" + stationLabelFragment; }
else if (stationLabelInitial == stationLabelInitial.toUpperCase())
{ stationLabel += " " + stationLabelFragment; }
else
{ stationLabel += stationLabelFragment; }
}
}
};
// A station name may have a rogue character appended
var iGlyph = stationLabel.indexOf(charWheelchair);
if (iGlyph > 0)
{ if (iGlyph == stationLabel.length-1)
{ stationLabel = stationLabel.substring(0,iGlyph); }
else
{ var iComment = stationLabel.indexOf('