diff --git a/app/db_mgr.py b/app/db_mgr.py index d02b695..1545447 100644 --- a/app/db_mgr.py +++ b/app/db_mgr.py @@ -13,6 +13,21 @@ def agents(): return all_agents +def stacked_charges_by_agent(agent_id): + all_charges = {} + for (period_id, period_name) in db.session.execute("select id, name from period order by id"): + charge_by_project_req = """select p.name, c.charge_rate from project p left join + charge c on p.id = c.project_id and agent_id = {} and period_id={} + order by p.id""".format(agent_id, period_id) + period_charge = {} + for project_name, project_rate in db.session.execute(charge_by_project_req): + period_charge[project_name] = project_rate + all_charges[period_name]=period_charge + + pprint(all_charges) + return all_charges + + def charges_by_agent(agent_id): # all_charges = db.session.query(Charge).all() periods = db.session.execute("select name from period") diff --git a/app/main/routes.py b/app/main/routes.py index f2ec1ea..945720d 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -94,11 +94,7 @@ def charge_add(): @bp.route('/charge/agent/') @role_required('service') def charge_agent(agent_id): - agent_charges = [] - for [period, charge] in db_mgr.charges_by_agent(agent_id): - agent_charges.append({"charge": charge, "periode": period}) - # agent_charges = [["charge", "periode"]]+db_mgr.charges_by_agent(agent_id)#agent_charges - resp = make_response(json.dumps(agent_charges)) + resp = make_response(json.dumps(db_mgr.stacked_charges_by_agent(agent_id))) resp.headers['Content-Type'] = 'application/json' return resp diff --git a/app/main/templates/agent.html b/app/main/templates/agent.html index 9ae646b..e026c54 100644 --- a/app/main/templates/agent.html +++ b/app/main/templates/agent.html @@ -67,57 +67,98 @@ // On demande à D3JS de charger notre fichier d3.json("{{url_for('main.charge_agent', agent_id=agent.id)}}").then(data => { - // Conversion des caractères en nombres - data.forEach(d => d.charge = +d.charge); - - // Mise en relation du scale avec les données de notre fichier - // Pour l'axe X, c'est la liste des periodes - // Pour l'axe Y, c'est le max des charge - x.domain(data.map(d => d.periode)); - y.domain([0, 100]); - - // 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(0," + height + ")") - .call(d3.axisBottom(x).tickSize(5)) - .selectAll("text") - .style("text-anchor", "end") - .attr("dx", "-.8em") - .attr("dy", ".15em") - .attr("transform", "rotate(-65)"); - - - svg.append("text") - .attr("text-anchor", "end") - .attr("transform", "rotate(-90)") - .attr("y", -margin.left+60) - .attr("x", -margin.top-70) - .text("Charge (ETP)") - - - // Ajout de l'axe Y au SVG avec 6 éléments de légende en utilisant la fonction ticks (sinon D3JS en place autant qu'il peut). - svg.append("g") - .call(d3.axisLeft(y).ticks(6)); - - // Ajout des bars en utilisant les données de notre fichier data.tsv - // La largeur de la barre est déterminée par la fonction x - // La hauteur par la fonction y en tenant compte de la charge - // La gestion des events de la souris pour le popup - svg.selectAll(".bar") - .data(data) + + // waiting for structure of the form: + // + var periods = Object.keys(data) + var first_stacked_charges = Object.values(data)[0] + var projects = Object.keys(first_stacked_charges) + console.log(projects) + + // periods = data + var x = d3.scaleBand() + .domain(periods) + .range([0, width]) + .padding(0.2) + + svg.append('g') + .attr('transform', 'translate(20, ' + height + ')') + .call(d3.axisBottom(x).tickSizeOuter(0)); + + var y = d3.scaleLinear() + .domain([0, 100]) + .range([height, 0]) + + svg.append('g') + .attr('transform', 'translate(20, 0)') + .call(d3.axisLeft(y)) + + 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) + + 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) + + // var sel = d3.select("#demo2") + // .select('g') + // .selectAll('g.series') + // .data(stackedSeries) + // .join('g') + // .classed('series', true) + // .style('fill', (d) => colorScale(d.key)); + // + // sel.selectAll('rect') + // .data((d) => d) + // .join('rect') + // .attr('width', 40) + // .attr('y', (d) => yScale(d[1])) + // .attr('x', (d) => xScale(d.data.month) - 20) + // .attr('height', (d) => yScale(d[0]) - yScale(d[1])); + + 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("class", "bar") - .attr("x", d => x(d.periode)) + .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("y", d => y(d.charge)) - .attr("height", d => height - y(d.charge)) + .on("mouseover", function (e, d) { + console.log(d) div.transition() .duration(200) .style("opacity", .9); - div.html("Charge: " + d.charge) + div.html("Charge: " + d) .style("left", (e.x + 10) + "px") .style("top", (e.y - 50) + "px"); }) -- libgit2 0.21.2