Skip to content

Instantly share code, notes, and snippets.

@SidShenoy
Last active July 18, 2017 11:29
Show Gist options
  • Save SidShenoy/e13385b034d903976f34083b87be8794 to your computer and use it in GitHub Desktop.
Save SidShenoy/e13385b034d903976f34083b87be8794 to your computer and use it in GitHub Desktop.
Atlas of Learning - Live Example
license: AGPL-3.0

NOTE: Currently single-click feature will land on a dummy page.

Features of the graph

  1. Hover fade.
  2. Hover highlight.
  3. Drag and drop (toggle switch)
  4. Single-click for opening an overlay with current node's context.
  5. Double-click for centre alignment of the current node.
  6. Hover content box.
  7. Zoom/Pan (toggle switch).
  8. Ability to change the global degree of all nodes (number of levels that will get highlighted upon hover).

Configurations

  1. Single-click and double-click are distinguished by a 500 msec time-gap between successive clicks( < 500 for double-click,> 500 for single-click).

  2. Single-click and drag-drop are also distinguished by a similar time-gap as above. This means that if a user drags and drops a node in less than 500 msec, then it is considered a 'single-click' event.

  3. To complete a single 'mouseover' and 'mouseleave' successive pair event, a time-gap of 100 msec is used. This means that a 2 successive mouse-hovers on 2 different nodes will take place with the expected behaviour only if they differ by 100 msec. If not, unexpected behaviour may take place and the user is advised to refresh the page.

.forZoom{
fill: white;
pointer-events: all;
}
.overlay{
position: absolute;
y: 20%;
x: 20%;
width: 60vw;
height: 62vh;
z-index: 10;
background-color: #FFDAB9; /*dim the background*/
display: none;
}
.degreeBox{
position: absolute;
y: 5%;
x: 85%;
width: 25vh;
height: 23vh;
z-index: 9;
background-color: #FFDAB9; /*dim the background*/
/*display: none;*/
}
.off {
pointer-events: none;
opacity: 0.2;
}
.on {
pointer-events: all;
opacity: 1;
}
.iframe {
display: block;
border: none;
height: 50vh;
width: 100%;
}
.text{
font-family: sans-serif;
font-size: 14px;
}
.switch {
position: relative;
display: block;
vertical-align: top;
width: 140px;
height: 30px;
padding: 3px;
margin: 0 10px 10px 0;
background: linear-gradient(to bottom, #eeeeee, #FFFFFF 25px);
background-image: -webkit-linear-gradient(top, #eeeeee, #FFFFFF 25px);
border-radius: 18px;
box-shadow: inset 0 -1px white, inset 0 1px 1px rgba(0, 0, 0, 0.05);
cursor: pointer;
box-sizing:content-box;
}
.switch-input {
position: absolute;
top: 0;
left: 0;
opacity: 0;
box-sizing:content-box;
}
.switch-label {
position: relative;
display: block;
height: inherit;
font-size: 10px;
text-transform: uppercase;
background: #FF7700;
border-radius: inherit;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12), inset 0 0 2px rgba(0, 0, 0, 0.15);
box-sizing:content-box;
}
.switch-label:before, .switch-label:after {
position: absolute;
top: 50%;
margin-top: -.5em;
line-height: 1;
-webkit-transition: inherit;
-moz-transition: inherit;
-o-transition: inherit;
transition: inherit;
box-sizing:content-box;
}
.switch-label:before {
content: attr(data-off);
right: 11px;
color: #FFFFFF;
text-shadow: 0 1px rgba(255, 255, 255, 0.5);
}
.switch-label:after {
content: attr(data-on);
left: 11px;
color: #FFFFFF;
text-shadow: 0 1px rgba(0, 0, 0, 0.2);
opacity: 0;
}
.switch-input:checked ~ .switch-label {
background: #00BB00;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15), inset 0 0 3px rgba(0, 0, 0, 0.2);
}
.switch-input:checked ~ .switch-label:before {
opacity: 0;
}
.switch-input:checked ~ .switch-label:after {
opacity: 1;
}
.switch-handle {
position: absolute;
top: 4px;
left: 4px;
width: 28px;
height: 28px;
background: linear-gradient(to bottom, #FFFFFF 40%, #f0f0f0);
background-image: -webkit-linear-gradient(top, #FFFFFF 40%, #f0f0f0);
border-radius: 100%;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
}
.switch-handle:before {
content: "";
position: absolute;
top: 50%;
left: 50%;
margin: -6px 0 0 -6px;
width: 12px;
height: 12px;
background: linear-gradient(to bottom, #eeeeee, #FFFFFF);
background-image: -webkit-linear-gradient(top, #eeeeee, #FFFFFF);
border-radius: 6px;
box-shadow: inset 0 1px rgba(0, 0, 0, 0.02);
}
.switch-input:checked ~ .switch-handle {
left: 114px;
box-shadow: -1px 1px 5px rgba(0, 0, 0, 0.2);
}
/* Transition
========================== */
.switch-label, .switch-handle {
transition: All 0.3s ease;
-webkit-transition: All 0.3s ease;
-moz-transition: All 0.3s ease;
-o-transition: All 0.3s ease;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link type="text/css" rel="stylesheet" href="custom.css"/>
</head>
<body>
<label for="graphCheckBox">Graph</label>
<input id="graphCheckBox" type="checkbox" checked="true"></input>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src='http://code.jquery.com/jquery-latest.js'></script>
<script>
//The dataset contains the actual data that is graphically displayed
let dataset = {
'nodes': [
{'name': 'CIRCULAR MOTION', 'description': 'CIRCULAR MOTION', 'label': 'LO', 'url': '', 'level': 1},
{'name': 'MOTION', 'description': 'MOTION', 'label': 'LO', 'url': '', 'level': 1},
{'name': 'DD1', 'description': 'DD1', 'label': 'Resource', 'level': 2, 'url': 'uurl1'},
{'name': 'DD4', 'description': 'DD4', 'label': 'Resource', 'level': 2, 'url': 'uurl4'},
{'name': 'DD3', 'description': 'DD3', 'label': 'Resource', 'level': 2, 'url': 'uurl3'},
{'name': 'UNITS', 'description': 'UNITS', 'label': 'LO', 'url': '', 'level': 1},
{'name': 'D3', 'description': 'D3', 'label': 'Resource', 'level': 2, 'url': 'url3'},
{'name': 'D2', 'description': 'D2', 'label': 'Resource', 'level': 2, 'url': 'url2'},
{'name': 'D1', 'description': 'D1', 'label': 'Resource', 'level': 2, 'url': 'url1'},
{'name': 'LINEAR MOTION', 'description': 'LINEAR MOTION', 'label': 'LO', 'url': '', 'level': 1},
{'name': 'DD2', 'description': 'DD2', 'label': 'Resource', 'level': 2, 'url': 'uurl2'}],
'links': [{'source': 1, 'target': 0},
{'source': 2, 'target': 0},
{'source': 3, 'target': 0},
{'source': 4, 'target': 0},
{'source': 5, 'target': 1},
{'source': 6, 'target': 1},
{'source': 7, 'target': 1},
{'source': 8, 'target': 1},
{'source': 1, 'target': 9},
{'source': 10, 'target': 9},
{'source': 2, 'target': 9}]
}
// var nodes = [
// { id: "mammal", group: 0, label: "Mammals", level: 1 },
// { id: "dog" , group: 0, label: "Dogs" , level: 2 },
// { id: "cat" , group: 0, label: "Cats" , level: 2 },
// { id: "fox" , group: 0, label: "Foxes" , level: 2 },
// { id: "elk" , group: 0, label: "Elk" , level: 2 },
// { id: "insect", group: 1, label: "Insects", level: 1 },
// { id: "ant" , group: 1, label: "Ants" , level: 2 },
// { id: "bee" , group: 1, label: "Bees" , level: 2 },
// { id: "fish" , group: 2, label: "Fish" , level: 1 },
// { id: "carp" , group: 2, label: "Carp" , level: 2 },
// { id: "pike" , group: 2, label: "Pikes" , level: 2 }
// ]
// var links = [
// { target: 0, source: 1 , strength: 0.7 },
// { target: 0, source: 2 , strength: 0.7 },
// { target: 0, source: 3 , strength: 0.7 },
// { target: 0, source: 4 , strength: 0.7 },
// { target: 5, source: 6 , strength: 0.7 },
// { target: 5, source: 7 , strength: 0.7 },
// { target: 8 , source: 9, strength: 0.7 },
// { target: 8 , source: 10, strength: 0.7 },
// { target: 2 , source: 4 , strength: 0.1 },
// { target: 9 , source: 6 , strength: 0.1 },
// { target: 4 , source: 7 , strength: 0.1 },
// { target: 1 , source: 2 , strength: 0.1 },
// { target: 3 , source: 6 , strength: 0.1 },
// { target: 10 , source: 2 , strength: 0.1 }
// ]
function getNodeColor(node) {
return node.level === 1 ? 'red' : 'gray'
}
var width = window.innerWidth
var height = window.innerHeight
var time1 = 0, time2 = 0, time3 = 0, time4 = 0, toggle = true, mouseState = "leave", degree = 2;
var zoom = d3.behavior.zoom().scaleExtent([0, 8]).on("zoom",zoomed);
//this svg contains everything that is rendered
let minX=0,minY=0,maxX=width,maxY=height;
var svg1 = d3.select('svg')
.attr('width', width)
.attr('height', height)
.attr('viewBox','0 0 '+width+' '+height)
.attr("preserveAspectRatio","xMidYMid meet")
.style("position","relative")
.append('g')
.call(zoom)
zoom.on("zoom",null); //zoom is disabled by default (initially)
var svg = svg1.append('g')
.classed("container",true);
//the zoom event listener
function zoomed() {
svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
var xTrans = (-1) * d3.event.translate[0];
var yTrans = (-1) * d3.event.translate[1];
d3.selectAll("foreignObject").attr("transform","scale(" + 1/d3.event.scale + ")translate("+xTrans+","+yTrans+")");
//console.log(d3.event.translate);
}
// simulation setup with all forces
// var linkForce = d3
// .forceLink()
// .id(function (link) { return link.id })
// .strength(function (link) { return link.strength })
// var simulation = d3
// .forceSimulation()
// .force('link', linkForce)
// .force('charge', d3.forceManyBody().strength(-120))
// .force('center', d3.forceCenter(width / 2, height / 2))
//let org_color_node, org_color_link;
//Force setup used to mimic forces in physics,
//mainly attractive 'spring' forces and repulsive 'electostatic forces'
var force = d3.layout.force()
.nodes(dataset.nodes)
.links(dataset.links)
.linkDistance(60)
//.friction(0.5)
.charge(-500)
.size([width, height])
.start();
//this rect allows user to use zoom feature if the corresponding checkbox is enabled
svg.append("rect")
.classed("forZoom",true)
.attr("width",width)
.attr("height",height);
var linkElements = svg.append("g")
.attr("class", "links")
//.style('z-index',3)
.selectAll("line")
.data(dataset.links)
.enter().append("line")
.attr("stroke-width",2)
.attr("stroke","rgba(50, 50, 50, 0.2)")
.attr("data-orgcolor","rgba(50, 50, 50, 0.2)")
.attr('x1', function (link) { return link.source.x })
.attr('y1', function (link) { return link.source.y })
.attr('x2', function (link) { return link.target.x })
.attr('y2', function (link) { return link.target.y })
.attr("pointer-events","none")
var nodeElements = svg.append("g")
.attr("class", "nodes")
//.style('z-index',3)
.selectAll("circle")
.data(dataset.nodes)
.enter().append("circle")
.attr("r",18)
.attr("fill", getNodeColor)
.attr("data-orgcolor",getNodeColor)
.on("mousedown",function(){
time3 = new Date().getTime();
console.log("time3 = "+time3);
})
.on("mouseup",function(){
time4 = new Date().getTime();
console.log("time4 = "+time4);
})
.on("mouseover",function(){
// t1 = new Date().getTime();
if(mouseState == "leave"){
d3.selectAll("circle")
.transition()
.duration(100)
.attr("opacity","0.2");
d3.selectAll("text")
.transition()
.duration(100)
.attr("opacity","0.2");
d3.selectAll("line")
.transition()
.duration(100)
.attr("opacity","0.2");
d3.select(this)
.transition()
.duration(100)
.attr("r",22)
.attr("opacity","1")
.attr("cursor","pointer");
//console.log("mouseover");
var x = d3.select(this).attr("cx");
var y = d3.select(this).attr("cy");
d3.select("text[x='"+x+"'][y='"+y+"']")
.transition()
.duration(100)
.style("font-size",18)
.style("font-weight","bold")
.attr("opacity","1");
var highlight = function(x,y,degree)
{
if(degree>=1)
{
d3.selectAll("line[x2='"+x+"'][y2='"+y+"']")
.each(function(){
var x1 = d3.select(this).attr("x1");
var y1 = d3.select(this).attr("y1");
//org_color_link = d3.select(this).attr("stroke");
d3.select(this)
.transition()
.duration(100)
.attr("stroke-width",4)
.attr("stroke","blue")
.attr("opacity","1");
//org_color_node = d3.select("circle[cx='"+x1+"'][cy='"+y1+"']").attr("fill");
d3.select("circle[cx='"+x1+"'][cy='"+y1+"']")
.transition()
.duration(100)
.attr("r",22)
.attr("fill",function(){
if(d3.select(this).attr("data-orgcolor") == "red")
return "red";
else
return "green";
})
.attr("opacity","1");
d3.select("text[x='"+x1+"'][y='"+y1+"']")
.transition()
.duration(100)
.style("font-size",18)
.style("font-weight","bold")
.attr("opacity","1");
highlight(x1,y1,degree-1);
});
}
};
highlight(x,y,degree);
window.setTimeout(function(){
mouseState = "over";
console.log("mouseState = "+mouseState);},100);
}
})
.on("mouseleave",function(){
// t2 = new Date().getTime();
// console.log(t2-t1);
if(mouseState == "over"){
d3.selectAll("circle")
.transition()
.duration(100)
.attr("opacity","1");
d3.selectAll("text")
.transition()
.duration(100)
.attr("opacity","1");
d3.selectAll("line")
.transition()
.duration(100)
.attr("opacity","1");
d3.select(this)
.transition()
.duration(100)
.attr("r",18)
.attr("fill",function(){
//console.log(d3.select(this).attr("data-orgcolor"));
return d3.select(this).attr("data-orgcolor");
});
//console.log("mouseleave"+d3.select(this).attr("data-orgcolor"));
var x = d3.select(this).attr("cx");
var y = d3.select(this).attr("cy");
d3.select("text[x='"+x+"'][y='"+y+"']")
.transition()
.duration(100)
.style("font-size",14)
.style("font-weight","normal");
var dehighlight = function(x,y,degree)
{
if(degree>=1)
{
d3.selectAll("line[x2='"+x+"'][y2='"+y+"']")
.each(function(){
var x1 = d3.select(this).attr("x1");
var y1 = d3.select(this).attr("y1");
d3.select(this)
.transition()
.duration(100)
.attr("stroke-width",2)
.attr("stroke",function(){
//console.log(d3.select(this).attr("data-orgcolor"));
return d3.select(this).attr("data-orgcolor");
});
d3.select("circle[cx='"+x1+"'][cy='"+y1+"']")
.transition()
.duration(100)
.attr("r",18)
.attr("fill",function(){
//console.log(d3.select(this).attr("data-orgcolor"));
return d3.select(this).attr("data-orgcolor");
});
d3.select("text[x='"+x1+"'][y='"+y1+"']")
.transition()
.duration(100)
.style("font-size",14)
.style("font-weight","normal");
dehighlight(x1,y1,degree-1);
});
}
};
dehighlight(x,y,degree);
window.setTimeout(function(){
mouseState = "leave";
console.log("mouseState = "+mouseState);},100);
}
})
.on("click",function(d){
if(toggle == true){
time1 = new Date().getTime();
console.log("time1 = "+time1);
}
else{
time2 = new Date().getTime();
console.log("time2 = "+time2);
}
window.setTimeout(function(){
if((time1 - time2 > 500 || time1 - time2 < (-500)) && time4 - time3 < 500){
d3.selectAll("g.container > :not(.overlay)")
.classed("on", false)
.classed("off", true);
d3.select("label.switch")
.style("opacity",0.2);
d3.select("foreignObject.overlay").style("display","block");
d3.select("foreignObject.overlay iframe").attr("src","overlay.html");
}
},500);
toggle = !toggle;
})
.on("dblclick",function(){
var xDisp = width/2 - parseFloat(d3.select(this).attr("cx"));
var yDisp = height/2 - parseFloat(d3.select(this).attr("cy"));
d3.selectAll('g.links,.nodes,.texts')
.attr("transform","translate("+xDisp+","+yDisp+")");
d3.selectAll("circle")
.each(function(){
d3.select(this)
.transition()
.duration(100)
.attr("r",18)
.attr("fill",function(){
//console.log(d3.select(this).attr("data-orgcolor"));
return d3.select(this).attr("data-orgcolor");
});
})
d3.selectAll("line")
.each(function(){
d3.select(this)
.transition()
.duration(100)
.attr("stroke-width",2)
.attr("stroke",function(){
//console.log(d3.select(this).attr("data-orgcolor"));
return d3.select(this).attr("data-orgcolor");
});
})
d3.selectAll("text")
.transition()
.duration(100)
.style("font-size",14)
.style("font-weight","normal");
})
//drawback of 'adjacent nodes turning green' feature
//is that adjacent nodes of the hovered node must have the same color, otherwise this won't work.
//Another drawback of all events is that if another event is triggered before the current one
//finishes then the later event occurs and the current one pauses midway.
.html(function(d){
return "<title>"+`
${d.name}
${d.description}
`+"</title>";
})
.call(force.drag);
//var overlay_html; //html for 'overlay' element
var textElements = svg.append("g")
.attr("class", "texts")
//.style('z-index',3)
.selectAll("text")
.data(dataset.nodes)
.enter().append("text")
.text(function (node) { return node.name.substring(0, 3) })
.style("fill", "white")
.attr("font-size", 14)
.attr("dx", 0)
.attr("dy", ".35em")
.attr("text-anchor","middle")
.attr("pointer-events","none");
//this line is new
// var svg2 = svg.append("svg")
// .attr("tansform","");
var degreeBox = svg.append("foreignObject")
.classed("degreeBox", true)
.append("xhtml:body");
var showDegree = degreeBox.append("b")
.classed("text",true)
.text("Enter degree");
degreeBox.append("br");
degreeBox.append("input")
.attr("type","number")
.attr("min",1)
.attr("step",1)
.style("width","4em");
degreeBox.append("br");
degreeBox.append("input")
.attr("type","button")
.attr("value","apply")
.on('click',function(){
var num = $('foreignObject.degreeBox input').val();
if(Number.isInteger(parseFloat(num)) && parseFloat(num)>0)
{
degree = parseInt(num);
showDegree.text("degree now is "+degree);
}
else {
showDegree.text("Invalid degree (must be a +ve Integer)");
}
});
degreeBox.append("br")
degreeBox.append("br")
degreeBox.append("label")
.attr("for","zoomCheckBox")
.classed("text",true)
.append("b")
.text("Zoom in/out");
// var sliderSwitch = degreeBox.append("label")
// .classed("switch",true);
degreeBox.append("input")
.attr({"type":"checkbox"})
//.attr("checked","checked")
.attr("id","zoomCheckBox")
.on("change",function(){
if(!$(this).is(":checked")){
zoom.on("zoom",null); //disable zooming
nodeElements.call(force.drag); //enable dragging
d3.select("svg rect.forZoom")
.on("mouseover",function(){
d3.select(this).attr("cursor", "default");
})
.on("mousedown",function(){
d3.select(this).attr("cursor", "default");
})
.on("mouseup",function(){
d3.select(this).attr("cursor", "default");
});
}
else {
d3.selectAll('circle').on('mousedown.drag', null); //disable dragging
//svg.attr('viewBox',minX+' '+minY+' '+maxX+' '+maxY)
console.log('minX = '+minX+' minY = '+minY+' maxX = '+maxX+' maxY = '+maxY);
zoom.on("zoom",zoomed); //enable zooming
d3.select("svg rect.forZoom")
.on("mouseover",function(){
d3.select(this).attr("cursor", "zoom-in");
})
.on("mousedown",function(){
d3.select(this).attr("cursor", "move");
})
.on("mouseup",function(){
d3.select(this).attr("cursor", "zoom-in");
});
}
});
// sliderSwitch.append("span")
// .attr({"class":"switch-label",
// "data-on":"Drag is On",
// "data-off":"Zoom/Pan is On"});
//
// sliderSwitch.append("span")
// .classed("switch-handle",true);
var overlay = svg.append("foreignObject")
.classed("overlay", true)
.style("border",0);
overlay.append("xhtml:head")
.append("link")
.attr("rel","stylesheet")
.attr("href","http://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css");
var overlayBody = overlay.append("xhtml:body");
overlayBody.append("i")
.classed("fa fa-window-close",true)
.attr("aria-hidden","true")
.style("float","right")
.style("background-color","white")
.on("mouseover", function(){
d3.select(this).style({ "background-color": "lightgray" });
})
.on("mouseout", function(){
d3.select(this).style({ "background-color": "white" });
})
.on("click", function(d){
d3.select(this)
.style({ "background-color": "gray" });
d3.selectAll("g.container > :not(.overlay)")
.classed("off", false)
.classed("on", true);
d3.select("label.switch")
.style("opacity",1);
d3.select("foreignObject.overlay").style("display","none");
});
overlayBody.append("br");
overlayBody.append("br");
overlayBody.append("iframe")
.classed("iframe",true);
d3.select("input#graphCheckBox")
.on("change",function(){
$("svg").toggle();
})
force.on("tick", function() {
nodeElements
.attr('cx', function (node) { return node.x })
.attr('cy', function (node) { return node.y })
textElements
.attr('x', function (node) { return node.x })
.attr('y', function (node) { return node.y })
linkElements
.attr('x1', function (link) { return link.source.x })
.attr('y1', function (link) { return link.source.y })
.attr('x2', function (link) { return link.target.x })
.attr('y2', function (link) { return link.target.y })
});
force.on("end", function(){
d3.selectAll("svg circle")
.each(function(){
var cx = parseFloat(d3.select(this).attr("cx"));
var cy = parseFloat(d3.select(this).attr("cy"));
if(cx > maxX){maxX = cx;}
else if (cx < minX) {
minX = cx;
}
if(cy > maxY){maxY = cy;}
else if (cy < minY) {
minY = cy;
}
});
var xForRect = minX;
var yForRect = minY;
var widthForRect = maxX - minX;
var heightForRect = maxY - minY;
console.log("minX calc = "+minX+" minY calc = "+minY);
d3.select("svg rect")
.attr("x",xForRect)
.attr("y",yForRect)
.attr("width",widthForRect)
.attr("height",heightForRect);
})
</script>
</body>
</html>
<html>
<body>
<h3>JUST SOME RANDOM DATA</h3>
The Mumbai–Ahmedabad corridor, along with 5 other high-speed rail corridors, was introduced for feasibility study in the 2009–2010 Rail Budget. A 650 km long high-speed rail corridor was proposed to run from Pune railway station to Ahmedabad railway station via Mumbai. The point at which this route would touch Mumbai was to be decided when the feasibility report was prepared. The pre-feasibility study for the Ahmedabad–Mumbai–Pune corridor was completed by a consortium of RITES, Italferr and Systra.[2] The top speed expected for the corridor was up to 350 km/h.[3] The proposed stations included Lonavala on Mumbai–Pune section and Surat, Bharuch and Vadodara on Mumbai–Ahmedabad section. It was proposed to have 32 services between Mumbai and Ahmedabad. Railway officials also proposed extending the corridor up to Bangalore.[4]
A MoU was signed in New Delhi on 14 February 2013 between the Ministry of Railways and the Société Nationale des Chemins de Fer Français (SNCF), the French national railways, for technical cooperation in the field of railways. The parties agreed to carry out jointly an "operations and development" feasibility project on the Mumbai–Ahmedabad high-speed rail corridor. The project was funded by the SNCF with support from the French Ministry of Finance.[5] In March 2013, the Railway Board decided to drop the Mumbai-Pune section and operate the high-speed rail service only between Mumbai and Ahmedabad. The Board took the decision due to financial constraints, because the ghat section between Pune and Mumbai would escalate the budget for the project. According to V.A. Malegaonkar, Chief Public Relations Officer (PRO), Western Railway, "It's basically a Western Railway project and very little portion of Maharashtra was being covered under it. Hence, the Maharashtra government was showing little interest in the project and was also reluctant to bear a financial burden. That is the reason why the Railway Board has decided against including the Pune-Mumbai portion in the high-speed corridor".[6]
India and Japan signed a Memorandum of Understanding (MoU) to undertake a joint feasibility study of the Mumbai-Ahmedabad route in New Delhi in September 2013.[7] This was in pursuance of the Joint Statement between then Prime Minister of India Manmohan Singh and the Prime Minister of Japan Shinzō Abe on 29 May 2013, which provided that the two sides would co-finance a joint feasibility study of the route. The objective of the joint study was to prepare a feasibility report of the system with a speed of 300–350 km/h. The cost of the study (¥500 million)[8] was borne equally by India and Japan. The study was scheduled to be completed within 18 months from its commencement, i.e. it would complete by July 2015. The study carried out traffic forecasting, alignment surveys and undertook a comparative Study of high-speed railway technology and systems.[5][9]
Japanese International Cooperation Agency (JICA) and the SNCF carried out studies on the project. JICA researched the technology, alignment and traffic-related aspects, while SNCF worked on business projections.[5][10] The feasibility study included an alignment survey concerning aspects such as land acquisition, environmental challenges and building of tunnels and bridges, etc. It also suggested a financial model based on fare and non-fare box revenue.[11]
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment