Built with blockbuilder.org
Voir code sur https://blockbuilder.org/Cynnexis/a11afbe4507e300bbdee4d595b0587bf
BACCUET-Anthony
BERGER-Valentin
| license: mit |
Built with blockbuilder.org
Voir code sur https://blockbuilder.org/Cynnexis/a11afbe4507e300bbdee4d595b0587bf
BACCUET-Anthony
BERGER-Valentin
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | |
| <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> | |
| <link href="https://fonts.googleapis.com/css?family=Raleway:300,400,700&display=swap" rel="stylesheet"> | |
| <style lang="css"> | |
| .mini text { | |
| font: 9px sans-serif; | |
| } | |
| div.tooltip { | |
| position: absolute; | |
| text-align: center; | |
| width: 100px; | |
| height: 50px; | |
| padding: 2px; | |
| font: 12px sans-serif; | |
| background: lightsteelblue; | |
| border: 0; | |
| border-radius: 8px; | |
| pointer-events: none; | |
| } | |
| .navbar + .container { | |
| margin-top: 100px; | |
| } | |
| .row > h1 { | |
| margin-bottom: 30px; | |
| } | |
| </style> | |
| <title>Introduction to D3</title> | |
| </head> | |
| <body> | |
| <div class="navbar navbar-expand-lg fixed-top navbar-dark bg-primary"> | |
| <div class="container"> | |
| <h1 class="navbar-brand">TP2 - Introduction to D3</h1> | |
| </div> | |
| </div> | |
| <div class="container"> | |
| <div class="row"> | |
| <h1 class="col-12">Création d'une timeline</h1> | |
| <div id="student-placeholder" class="col-12"></div> | |
| </div> | |
| </div> | |
| <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> | |
| <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> | |
| <script src="https://d3js.org/d3.v5.min.js"></script> | |
| <script src="https://d3js.org/d3-selection-multi.v1.min.js"></script> | |
| <script type="text/javascript"> | |
| /** | |
| * Lighten or darken the given color. | |
| * Source code inspired from https://stackoverflow.com/a/57401891/7347145. | |
| * @param color The color to change. | |
| * @param amount The amount to change (positive = lighten, negative = darken). | |
| * @returns {string} The new color. | |
| */ | |
| function adjust(color, amount) { | |
| return '#' + color.replace(/^#/, '').replace(/../g, color => ('0'+Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2)); | |
| } | |
| $(document).ready(function() { | |
| //data | |
| let prenoms = ["Etudiant 1", "Etudiant 2", "Etudiant 3"]; | |
| let nbEtudiants = prenoms.length; | |
| let prenomsColor = ["#F79174", "#839868", "#97A6B2"]; | |
| let weekdays = ["lundi", "mardi", "mercredi", "jeudi", "vendredi"]; | |
| let items = [ | |
| { id: 0, jour: weekdays[0], start: 0, end: 70 }, | |
| { id: 0, jour: weekdays[1], start: 230, end: 350 }, | |
| { id: 0, jour: weekdays[2], start: 485, end: 600 }, | |
| { id: 0, jour: weekdays[3], start: 670, end: 800 }, | |
| { id: 0, jour: weekdays[4], start: 880, end: 1000 }, | |
| { id: 1, jour: weekdays[0], start: 0, end: 120 }, | |
| { id: 1, jour: weekdays[1], start: 250, end: 400 }, | |
| { id: 1, jour: weekdays[2], start: 500, end: 600 }, | |
| { id: 1, jour: weekdays[3], start: 700, end: 850 }, | |
| { id: 1, jour: weekdays[4], start: 1000, end: 1110 }, | |
| { id: 2, jour: weekdays[0], start: 0, end: 60 }, | |
| { id: 2, jour: weekdays[1], start: 230, end: 400 }, | |
| { id: 2, jour: weekdays[2], start: 440, end: 600 }, | |
| { id: 2, jour: weekdays[3], start: 690, end: 800 }, | |
| { id: 2, jour: weekdays[4], start: 920, end: 1200 }, | |
| ]; | |
| let timeBegin = 0; | |
| let timeEnd = 1200; //5 jours * 24h * 10 | |
| let w = 960; | |
| let h = 100; | |
| let height = nbEtudiants * 12 + 50; | |
| let defaultFonts = "'Raleway', monospace, sans-serif"; | |
| let defaultTransition = "easeQuad"; | |
| let defaultTransitionDuration = 200; | |
| // Define the div for the tooltip | |
| var tooltip = d3.select("body").append("div") | |
| .attr("class", "tooltip") | |
| .style("opacity", 0); | |
| // TODO scales | |
| // chart | |
| let chart = d3 | |
| .select("#student-placeholder") | |
| .append("svg") | |
| .attr("width", w) | |
| .attr("height", h) | |
| .attr("class", "chart"); | |
| // Create a scale for the y-axis, based on 'prenoms' array | |
| let yScalePrenoms = d3.scaleLinear().range([0, height]).domain([0, prenoms.length]); | |
| let xScaleWeekdays = d3.scaleLinear().range([150, w]).domain([0, weekdays.length]); | |
| let xScaleItem = d3.scaleLinear().range([150, w]).domain([timeBegin, timeEnd - timeBegin]); | |
| // Draw 1 lane per student | |
| let g = chart.append('g'); | |
| g.selectAll("text") | |
| .data(prenoms) | |
| .enter() | |
| .append("text") | |
| .text(prenom => prenom) | |
| .attrs({ | |
| x: 100, | |
| y: (prenom, index) => yScalePrenoms(index) + 10, | |
| "font-size": 12, | |
| "text-anchor": "middle", | |
| "font-family": defaultFonts, | |
| }); | |
| // draw rectangles per item | |
| g = chart.append('g'); | |
| g.selectAll("rect") | |
| .data(items) | |
| .enter() | |
| .append("rect") | |
| .attrs({ | |
| x: item => xScaleItem(item["start"]), | |
| y: item => yScalePrenoms(item["id"]), | |
| width: item => xScaleItem(item["end"]) - xScaleItem(item["start"]), | |
| height: 15, | |
| fill: item => prenomsColor[item["id"]], | |
| }) | |
| // color change on hovering rectangles | |
| .on("mouseover", function(item) { | |
| d3.select(this) | |
| .transition(defaultTransition) | |
| .duration(defaultTransitionDuration) | |
| .attr("fill", adjust(prenomsColor[item["id"]], 20)); | |
| tooltip | |
| .transition(defaultTransition) | |
| .duration(defaultTransitionDuration) | |
| .style("opacity", .9); | |
| tooltip.html(prenoms[item["id"]] + " slept from " + item["start"] + " to " + item["end"] + " on " + item["jour"]) | |
| .style("left", d3.event.pageX + "px") | |
| .style("top", d3.event.pageY + "px") | |
| }) | |
| .on("mouseout", function(item) { | |
| d3.select(this) | |
| .transition(defaultTransition) | |
| .duration(defaultTransitionDuration) | |
| .attr("fill", prenomsColor[item["id"]]); | |
| tooltip | |
| .transition(defaultTransition) | |
| .duration(defaultTransitionDuration) | |
| .style("opacity", 0); | |
| }); | |
| // draw 1 line per day | |
| g = chart.append('g'); | |
| g.selectAll("line") | |
| .data(weekdays) | |
| .enter() | |
| .append("line") | |
| .attrs({ | |
| x1: (weekday, index) => xScaleWeekdays(index), | |
| y1: 0, | |
| x2: (weekday, index) => xScaleWeekdays(index), | |
| y2: h - 15, | |
| "stroke": "gray", | |
| "stroke-width": 1, | |
| }); | |
| g.selectAll("text") | |
| .data(weekdays) | |
| .enter() | |
| .append("text") | |
| .text(weekday => weekday) | |
| .attrs({ | |
| x: (weekday, index) => xScaleWeekdays(index), | |
| y: h - 5, | |
| }) | |
| .style("font-size", 12) | |
| .style("text-anchor", "middle") | |
| .style("font-family", defaultFonts); | |
| }); | |
| </script> | |
| </body> | |
| </html> |