Skip to content

Instantly share code, notes, and snippets.

@lhoang
Last active March 24, 2017 13:50
Show Gist options
  • Save lhoang/1419eedcf986ec0c62396cff8f0b9e76 to your computer and use it in GitHub Desktop.
Save lhoang/1419eedcf986ec0c62396cff8f0b9e76 to your computer and use it in GitHub Desktop.
Retournements RER
license: mit
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Retournement RER</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.7.3/d3.min.js"></script>
</head>
<body>
<style>
body {
font-family: Helvetica Neue;
}
svg {
border: solid 1px #ccc;
background-color: #fff;
}
.axis path,
.axis line {
fill: none;
stroke: #ccc;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.route {
fill: none;
stroke: red;
stroke-width: 2px;
}
/* Points */
circle.main {
fill: #EDC951;
stroke: #CC333F;
stroke-width: 1px;
}
circle.control {
fill: white;
stroke: #00A0B0;
}
.control-line {
stroke-width: 1px;
stroke: #00A0B0;
stroke-dasharray: 1,1;
}
.curve {
fill: none;
/* stroke: #CC333F; */
/* stroke-width: 2px; */
}
#canvas {
display: none;
}
pre {
font-family: Courier;
}
</style>
<h3>Retournement RER</h3>
<p>
<button>svg to png</button>
</p>
<p>
<svg width="400" height="400">
<g class="xaxis axis"></g>
<g class="yaxis axis"></g>
<g class="retournements"></g>
</svg>
</p>
<p>
<canvas id="canvas"></canvas>
</p>
<script>
// Données
var missions = [
{ mission1: "ODET54",
mission2: "TPUR71",
start : 0,
circuit : "m1"
},
{ mission1: "ODET56",
mission2: "TPUR73",
start : 5,
circuit : "m2",
}
];
var s1 = {
nom: "NP015",
couleur: "red",
segments: [
{type: "COM",
circuit: "m1",
retPart: "QA"},
{type: "RE1",
circuit: "m1",
retPart: "RE1",
info: "10"},
{type: "GTR"},
{type: "RE2",
circuit: "m2",
retPart: "RE2"},
{type: "COM",
circuit: "m2",
retPart: "QD"}
]
};
var s2 = {
nom: "NP014",
couleur: "green",
segments: [
{type: "ION"},
{type: "RE2",
circuit: "m1",
retPart: "RE2",
info: "10"},
{type: "COM",
circuit: "m1",
retPart: "QD"}
]
};
var s3 = {
nom: "TM031",
couleur: "blue",
segments: [
{type: "COM",
circuit: "m2",
retPart: "QA"},
{type: "RE1",
circuit: "m2",
retPart: "RE1",
info: "543"},
{type: "FNG"}
]
};
var services = [s1, s2, s3];
</script>
<script>
// Grid and SVG Setup
// ------------------
var width = 400,
height = 400,
margin = 0;
var xMin =-20,
xMax = 20;
var lines = d3.range(xMin, xMax);
var svg = d3.select('svg'),
xaxis = svg.select('g.xaxis'),
yaxis = svg.select('g.yaxis');
var x = d3.scaleLinear()
.domain(d3.extent(lines))
.range([0, width]);
var y = d3.scaleLinear()
.domain(d3.extent(lines))
.range([0, height]);
var xAxis = d3.axisBottom(x)
.tickSize(-width + 2 * margin);
var yAxis = d3.axisRight(y)
.tickSize(-height + 2 * margin);
// xaxis.call(xAxis);
// yaxis.call(yAxis);
// Compute the path string
function computePath(points, xOffset) {
// console.log(points);
function p(point) {
return x(point.x + xOffset) + ' ' + y(point.y);
}
var p1 = p(points[0]),
p2 = p(points[1]);
return 'M ' + p1 + 'L ' + p2;
}
// Ajout des codes missions
function addMissionCode(elt, materiel, pos, code) {
elt.append("text")
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("dy","-2px")
.append("textPath")
.attr("xlink:href", function() {return "#"+ materiel + "-" + pos;})
.attr("startOffset", "90%")
.attr("text-anchor", "end")
.text(function() {return code;});
}
// trancode partie de retournement
function getRetournementPart(retPart) {
var code;
switch(retPart) {
case "QA":
code = 0;
break;
case "RE1":
code = 1;
break;
case "RE2":
code = 2;
break;
case "QD":
code = 3;
break;
}
return code;
}
// Quais
var quais = [
{name : "QA",
y: -5},
{name : "Trottoir",
y: -10},
{name : "QD",
y: 0}
];
var lieux = svg.selectAll("g.lieux")
.data(quais)
.enter();
lieux.append("line")
.attr("x1", x(xMin))
.attr("y1", function(d){return y(d.y)})
.attr("x2", x(xMax))
.attr("y2", function(d){return y(d.y)})
.attr("stroke", "DeepSkyBlue")
.attr("stroke-dasharray","5, 5")
lieux.append("text")
.attr("x", function(d) { return x(xMin); })
.attr("y", function(d) { return y(d.y-1); })
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.text(function(d) { return d.name; });
// forme d'un retournement
var retournement = [
{points:[
{x: -15, y: 5},
{x: -10, y: -5}]
},
{points:[
{x: -10, y: -5},
{x: -5, y: -10}]
},
{points:[
{x: -5, y: -10},
{x: 2, y: 0}]
},
{points:[
{x: 2, y: 0},
{x: 6, y: 5}]
}
];
// Concatenation des données
var res = [];
missions.forEach(function(each) {
retournement.forEach(function(segment, index) {
res.push({
id: index,
part: segment.points,
circuit: each.circuit,
start: each.start
});
});
});
//console.log(missions);
var gPaths = svg.select('g.retournements');
// Affichage train
var trains = gPaths.selectAll('trains')
.data(res);
trains.enter()
.append('path')
.classed('curve', true)
.attr('id', function(d){return d.circuit + '-' + d.id })
.attr("stroke", "black")
.attr('d', function(d) {return computePath(d.part, d.start);})
.attr('x1', function(d){return d.part[0].x + d.start;})
.attr('x2', function(d){return d.part[1].x + d.start;});
// Affichage missions
var missionTexts = gPaths.append("g")
.classed("missions", true);
missions.forEach(function(mission) {
addMissionCode(missionTexts, mission.circuit, 0, mission.mission1);
addMissionCode(missionTexts, mission.circuit, 3, mission.mission2);
});
// services
services.forEach(function(service, index){
// Couleurs et timing
service.segments.filter(function(seg){
return seg.retPart == 'QA' ||
seg.retPart == 'RE1' ||
seg.retPart == 'RE2' ||
seg.retPart == 'QD';
})
.forEach(function(seg){
var part = svg.select('#' + seg.circuit + '-' + getRetournementPart(seg.retPart))
.attr("stroke", service.couleur)
.attr("stroke-width", "2px");
seg.x1 = part.attr("x1");
seg.x2 = part.attr("x2");
});
// remplissage timing restant
var segData = service.segments;
segData.forEach(function (seg, i){
if (!seg.x1){
if (i>0){
seg.x1 = segData[i-1].x2;
} else {
seg.x1=xMin+5;
}
}
if (!seg.x2){
if (i<segData.length-1){
seg.x2 = segData[i+1].x1;
} else {
seg.x2=seg.x1+3;
}
}
});
// segments
var segments = svg.append('g')
.classed("segments",true);
segments.append("text")
.attr("x", x(-20))
.attr("y", y(10+index*2))
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("stroke", service.couleur)
.text(service.nom);
var segEnter = segments.selectAll("g.segment")
.data(segData)
.enter();
segEnter.append("line")
.attr("x1", function(d,i){return x(d.x1);})
.attr("y1", y(10+index*2))
.attr("x2", function(d){return x(d.x2);})
.attr("y2", y(10+index*2))
.attr("stroke", service.couleur)
.attr("stroke-dasharray","1, 1")
.attr("type", function(d){return d.type;});
segEnter
.append("line")
.classed("tick", true)
.attr("x1", function(d){return x(d.x1);})
.attr("y1", y(10+index*2+0.5))
.attr("x2", function(d){return x(d.x1);})
.attr("y2", y(10+index*2-0.5))
.attr("stroke", service.couleur)
//last tick
var lastSeg = segData[segData.length - 1];
segments.append("line")
.classed("tick", true)
.attr("x1", x(lastSeg.x2))
.attr("y1", y(10+index*2+0.5))
.attr("x2", x(lastSeg.x2))
.attr("y2", y(10+index*2-0.5))
.attr("stroke", service.couleur)
//Type
segEnter.append("text")
.attr("x", function(d){return x(d.x1*0.97);})
.attr("y", y(10+index*2-0.5))
.attr("font-family", "sans-serif")
.attr("font-size", "9px")
.attr("stroke", service.couleur)
.text(function(d){return d.type;});
});
</script>
<script>
// Téléchargement de l'image
// http://stackoverflow.com/questions/28226677/save-inline-svg-as-jpeg-png-svg
var btn = document.querySelector('button');
var svgImg = document.querySelector('svg');
var canvas = document.querySelector('canvas');
function triggerDownload (imgURI) {
var evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
var a = document.createElement('a');
a.setAttribute('download', 'retournement.png');
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');
a.dispatchEvent(evt);
}
btn.addEventListener('click', function () {
var canvas = document.getElementById('canvas');
canvas.width = 400;
canvas.height = 400;
// canvas.style.width = '800px';
// canvas.style.height = '600px';
var ctx = canvas.getContext('2d');
var data = (new XMLSerializer()).serializeToString(svgImg);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svgBlob);
img.onload = function () {
ctx.drawImage(img, 0, 0, 400, 400);
DOMURL.revokeObjectURL(url);
var imgURI = canvas
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');
triggerDownload(imgURI);
};
img.src = url;
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment