agent.html 6.11 KB
{% extends "base_page.html" %}

{% block more_heads %}
<style type="text/css">
  #charge_div {
    background-color: #fAfAfA;
    border: 1pt solid black;
    display: inline-block;
  }

  rect.bar:hover {
    fill: dimgrey;
  }

  rect.bar {
    fill: rgb(127, 127, 159);
  }

  .tooltip {
    position: absolute;
    opacity: 1.0;
    z-index: 1000;
    text-align: left;
    border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    padding: 10px;
    border: 1px solid;
    background-color: white;
    color: black;
    /*font: 12px sans-serif;*/
    max-width: 300px;
  }

</style>
{% endblock %}

{% block content %}
<div id="charge_div"></div>
{% endblock %}


{% block more_scripts %}
{% include 'd3js-includes.html' %}
<script>

  const margin = {top: 40, right: 40, bottom: 90, left: 120},
      width = 900 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

  const tooltip_offset = {dx: 300, dy: 120}

  const x = d3.scaleBand()
      .range([0, width])
      .padding(0.2);

  const y = d3.scaleLinear()
      .range([height, 0]);

  const svg = d3.select("#charge_div").append("svg")
      .attr("id", "svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");


  // On demande à D3JS de charger notre fichier
  d3.json("{{url_for('main.charge_agent', agent_id=agent.id)}}").then(data => {

    // waiting for structure of the form:
    //
    // {
    // '2014_S1': {'4Q++': None,
    //          'Activité service C2L': None,
    //          'Activité service COMCL': None,
    //          .
    //           ...},
    // '2014_S2': {'4Q++': None,
    //          'Activité service C2L': None,
    //          .
    //          .
    //          .
    // '2021_S2': {'4Q++': None,
    //          .
    //          .
    //          'Test IAS': None,
    //          'cahier des charges DT insu': None,
    //          'ŒIL': None
    //          }
    //   }


    var periods = Object.keys(data)
    var first_stacked_charges = Object.values(data)[0]
    var projects = Object.keys(first_stacked_charges)

    var x = d3.scaleBand()
        .domain(periods)
        .range([0, width])
        .padding(0.2)
    // Ajout de l'axe X au SVG
    // Déplacement de l'axe horizontal et du futur texte (via la fonction translate) au bas du SVG
    // Selection des noeuds text, positionnement puis rotation
    // svg.append('g')
    //     .attr('transform', 'translate(20, ' + height + ')')
    //     .call(d3.axisBottom(x).tickSizeOuter(0));
    svg.append("g")
        .attr("transform", "translate(20," + height + ")")
        .call(d3.axisBottom(x).tickSize(5))
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", "rotate(-65)");

    var y = d3.scaleLinear()
        .domain([0, 100])
        .range([height, 0])

    svg.append('g')
        .attr('transform', 'translate(20, 0)')
        .call(d3.axisLeft(y))


    svg.append("text")
        .attr("text-anchor", "end")
        .attr("transform", "rotate(-90)")
        .attr("y", -margin.left + 60)
        .attr("x", -margin.top - 70)
        .text("Charge (ETP)")


    var color = d3.scaleOrdinal()
        .domain(projects)
        .range(['#e41a1c', '#377eb8', '#4daf4a',
          "#800000",
          "#FFFF00",
          "#808000",
          "#00FF00",
          "#008000",
          "#00FFFF",
          "#008080",
          "#0000FF",
          "#000080",
          "#FF00FF",
          "#800080",
        ]);

    var stack_generator = d3.stack().keys(projects)

    // Building a list of dict, with projects as keys, like in the input dat,
    // but with a new key, 'period' wich value is the period string for that line
    // This is need for the d3js stack_generator function
    var stackable_data = []
    Object.keys(data).forEach(function (period) {
      line = data[period];
      line['period'] = period;
      stackable_data.push(line)
    });

    var stacked_data = stack_generator(stackable_data)


    // ----------------
    // Create a tooltip
    // ----------------
    var tooltip = d3.select("#charge_div")
        .append("div")
        .style("opacity", 0)
        .attr("class", "tooltip")

    // // Three function that change the tooltip when user hover / move / leave a cell
    // var mouseover = function (d) {
    //   var subgroupName = d3.select(this.parentNode).datum().key;
    //   // var subgroupValue = d.data[subgroupName];
    //   tooltip
    //       .html("subgroup: " + subgroupName + "<br>" + "Value: " + subgroupValue)
    //       .style("opacity", 1)
    // }

    var mousemove = function (e, d) {
      tooltip
          .style("left", (e.x - tooltip_offset.dx) + "px")
          .style("top", (e.y - tooltip_offset.dy) + "px")
    }

    var mouseleave = function (d) {
      tooltip
          .transition()
          .duration(100)
          .style("opacity", 0)
    }

    var mouseover = function (e, d) {
      var project_name = d3.select(this.parentNode).datum().key
      var project_charge = d.data[project_name]
      tooltip
          .transition()
          .duration(200)
          .style("opacity", 1);
      tooltip
          .html("Project: " + project_name + "<br>" + "Charge: " + project_charge + "%")
          .style("left", (e.x - 400) + "px")
          .style("top", (e.y - 90) + "px");
    }

    svg.append('g')
        .selectAll('g')
        .data(stacked_data)
        .enter().append('g')
        .attr("fill", function (d) {
          return color(d.key);
        })
        .selectAll("rect")
        // enter a second time = loop subgroup per subgroup to add all rectangles
        .data(d => d)
        .enter().append("rect")
        .attr("x", d => x(d.data.period) + 20)
        .attr("y", d => y(d[1]))
        .attr("height", d => y(d[0]) - y(d[1]))
        .attr("width", x.bandwidth())
        .attr("stroke", "black")
        .on("mouseover", mouseover)
        .on("mousemove", mousemove)
        .on("mouseleave", mouseleave);
  });
</script>
{% endblock %}